diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..8d801ce6ac --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,62 @@ +name: Build +on: + push: + tags: + pull_request: + branches: + - main + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + +jobs: + build: + name: Build wasm-tools + runs-on: ${{ matrix.os }} + if: github.event_name != 'push' || startsWith(github.ref, 'refs/tags/wasm-tools-') + strategy: + matrix: + include: + - build: x86_64-linux + os: ubuntu-latest + - build: x86_64-macos + os: macos-latest + - build: aarch64-macos + os: macos-latest + target: aarch64-apple-darwin + - build: x86_64-windows + os: windows-latest + - build: aarch64-linux + os: ubuntu-latest + target: aarch64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - run: rustup update stable --no-self-update && rustup default stable + - uses: bytecodealliance/wasmtime/.github/actions/binary-compatible-builds@v4.0.0 + with: + name: ${{ matrix.build }} + - run: | + echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV + rustup target add ${{ matrix.target }} + if: matrix.target != '' + - run: $CENTOS cargo build --release + - run: ./ci/build-tarballs.sh "${{ matrix.build }}" "${{ matrix.target }}" + - uses: actions/upload-artifact@v3 + with: + name: bins-${{ matrix.build }} + path: dist + + - uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') && github.repository == 'bytecodealliance/wasm-tools' + with: + files: "dist/*" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 04a941d213..ccfcd72c32 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,45 +35,72 @@ jobs: os: windows-latest rust: stable steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: true - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} shell: bash - - run: cargo test --all - - run: cargo test --manifest-path crates/wasmparser/Cargo.toml --features deterministic - - run: cargo test -p wasmparser --benches + - run: cargo test --locked --all + - run: cargo test --locked -p wasmparser --benches + - run: cargo test --locked -p wasm-encoder --all-features - run: cargo build --manifest-path crates/wast/Cargo.toml --no-default-features - run: cargo build --manifest-path crates/wast/Cargo.toml --no-default-features --features wasm-module - run: cmake -S ${{github.workspace}}/examples -B ${{github.workspace}}/examples/build -DCMAKE_BUILD_TYPE=Release - run: cmake --build ${{github.workspace}}/examples/build --config Release + wasm: + name: Test on WebAssembly + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - name: Install Rust + run: rustup update stable --no-self-update && rustup default stable + - run: rustup target add wasm32-wasi + - run: | + tag=v10.0.1 + curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/${tag}/wasmtime-${tag}-x86_64-linux.tar.xz + tar xf wasmtime-${tag}-x86_64-linux.tar.xz + echo `pwd`/wasmtime-${tag}-x86_64-linux >> $GITHUB_PATH + echo CARGO_TARGET_WASM32_WASI_RUNNER='wasmtime run --dir . --' >> $GITHUB_ENV + echo CARGO_BUILD_TARGET='wasm32-wasi' >> $GITHUB_ENV + - run: | + cargo --locked test --workspace \ + --exclude fuzz-stats \ + --exclude wasm-tools-fuzz \ + --exclude wasm-mutate-stats + rustfmt: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Rust run: rustup update stable && rustup default stable && rustup component add rustfmt - - run: cargo fmt -- --check + # Note that this doesn't use `cargo fmt` because that doesn't format + # modules-defined-in-macros which is in use in `wast` for example. This is + # the best alternative I can come up with at this time + - run: find . -name '*.rs' | xargs rustfmt --check --edition 2021 fuzz: name: Fuzz runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: true - name: Install Rust run: rustup update nightly && rustup default nightly - run: cargo install cargo-fuzz - - run: cargo fuzz build + - run: cargo fuzz build --dev -s none + - run: cargo fuzz build --dev --features wasmtime -s none check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: cargo check --benches -p wasm-smith - run: cargo check --no-default-features - run: cargo check --no-default-features --features print @@ -84,9 +111,16 @@ jobs: - run: cargo check --no-default-features --features mutate - run: cargo check --no-default-features --features dump - run: cargo check --no-default-features --features objdump + - run: cargo check --no-default-features --features strip + - run: cargo check --no-default-features --features compose + - run: cargo check --no-default-features --features demangle + - run: cargo check --no-default-features --features component + - run: cargo check --no-default-features --features metadata + - run: cargo check --no-default-features --features wit-smith + - run: cargo check --no-default-features --features addr2line doc: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: cargo doc --all diff --git a/.gitignore b/.gitignore index 14d925d6d6..9e608d96ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ target/ -Cargo.lock publish # Generated by some fuzz targets. *.wasm *.wat test.config + diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..dcdaee7424 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2439 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "cpp_demangle 0.4.2", + "fallible-iterator", + "gimli", + "memmap2", + "object", + "rustc-demangle", + "smallvec", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "blake3" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags 1.3.2", + "textwrap", + "unicode-width", +] + +[[package]] +name = "clap" +version = "4.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b417ae4361bca3f5de378294fc7472d3c4ed86a5ef9f49e93ae722f432aae8d2" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c90dc0f0e42c64bff177ca9d7be6fcc9ddb0f26a6e062174a61c84dd6c644d4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpp_demangle" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee34052ee3d93d6d8f3e6f81d85c47921f6653a19a7b70e939e3e602d893a674" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cranelift-bforest" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8e3fb66d520d18326327ffbcaa4805c64b0bed3d714cd8f711ca702b22ac46" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e4313f83f085204ea2eee80c4e358d6accbd516397bb02a1d0768cda63111cb" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.13.2", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63c18105d18b816e29b536c431a2a23c9b4de0ee5f21df04469d95f202f62f48" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cd2a1d68642141d8c28de1f6e9761ad7e7182b8aeb2b79b2d21bab4b367ae85" + +[[package]] +name = "cranelift-control" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8559ce38ee79ec6ad4d3a3ddb3f2bc8831c80bccb1d086ee6a1de3c9d4e40700" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab228adaf41d8e82c11ba04e57577328013aaf7a40ae3b2bd99b020a9fe418b5" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd45c75c4196f0f2f125bddf5cfab927934ef67b49a0c72522c3994fdb04f7f6" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cb0b7bdf32152b3c6e45076fd5bfcf3d89d61a17469c1113127be14ac610af6" + +[[package]] +name = "cranelift-native" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156b48e8e47b6e248c1468d36e1719aa8eda4ac20f4d7f970f170cc2570cbe48" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f9400cb80b18a6714f5b7112335c5d0bb33270e03f6730e38dd93077019a" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser 0.110.0", + "wasmtime-types", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap 2.34.0", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "egg" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05a6c0bbc92278f84e742f08c0ab9cb16a987376cd2bc39d228ef9c74d98d6f7" +dependencies = [ + "indexmap 1.9.3", + "instant", + "log", + "once_cell", + "smallvec", + "symbolic_expressions", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flagset" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779" + +[[package]] +name = "flate2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fuzz-stats" +version = "0.1.0" +dependencies = [ + "anyhow", + "arbitrary", + "num_cpus", + "rand", + "wasm-smith", + "wasmtime", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "fxprof-processed-profile" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" +dependencies = [ + "bitflags 2.4.0", + "debugid", + "fxhash", + "serde", + "serde_json", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +dependencies = [ + "fallible-iterator", + "indexmap 1.9.3", + "stable_deref_trait", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", + "serde", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.2", + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.2", + "rustix 0.38.8", + "windows-sys", +] + +[[package]] +name = "is_executable" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" +dependencies = [ + "winapi", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memfd" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +dependencies = [ + "rustix 0.37.23", +] + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.2", + "libc", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "crc32fast", + "flate2", + "hashbrown 0.13.2", + "indexmap 1.9.3", + "memchr", + "ruzstd", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap 1.9.3", +] + +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "pulldown-cmark" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regalloc2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b4dcbd3a2ae7fb94b5813fa0e957c6ab51bf5d0a8ee1b69e0c2d0f1e6eb8485" +dependencies = [ + "hashbrown 0.13.2", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.5", + "windows-sys", +] + +[[package]] +name = "ruzstd" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a15e661f0f9dac21f3494fe5d23a6338c0ac116a2d22c2b63010acd89467ffe" +dependencies = [ + "byteorder", + "thiserror", + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "serde" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +dependencies = [ + "indexmap 2.0.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "spdx" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" +dependencies = [ + "smallvec", +] + +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "symbolic_expressions" +version = "5.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c68d531d83ec6c531150584c42a4290911964d5f0d79132b193b67252a23b71" + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" + +[[package]] +name = "tempfile" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix 0.38.8", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" + +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wasm-compose" +version = "0.4.9" +dependencies = [ + "anyhow", + "glob", + "heck", + "indexmap 2.0.0", + "log", + "petgraph", + "pretty_assertions", + "serde", + "serde_derive", + "serde_yaml", + "smallvec", + "wasm-encoder 0.35.0", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wat", + "wit-component", +] + +[[package]] +name = "wasm-encoder" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-encoder" +version = "0.35.0" +dependencies = [ + "anyhow", + "leb128", + "tempfile", + "wasmparser 0.115.0", +] + +[[package]] +name = "wasm-metadata" +version = "0.10.9" +dependencies = [ + "anyhow", + "clap 4.3.22", + "indexmap 2.0.0", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder 0.35.0", + "wasmparser 0.115.0", + "wat", +] + +[[package]] +name = "wasm-mutate" +version = "0.2.38" +dependencies = [ + "anyhow", + "clap 4.3.22", + "egg", + "env_logger", + "log", + "rand", + "thiserror", + "wasm-encoder 0.35.0", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wat", +] + +[[package]] +name = "wasm-mutate-stats" +version = "0.1.0" +dependencies = [ + "anyhow", + "arbitrary", + "clap 4.3.22", + "env_logger", + "itertools", + "log", + "num_cpus", + "rand", + "wasm-mutate", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wasmtime", +] + +[[package]] +name = "wasm-shrink" +version = "0.1.39" +dependencies = [ + "anyhow", + "blake3", + "clap 4.3.22", + "env_logger", + "log", + "rand", + "wasm-mutate", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wat", +] + +[[package]] +name = "wasm-smith" +version = "0.12.21" +dependencies = [ + "arbitrary", + "criterion", + "flagset", + "indexmap 2.0.0", + "leb128", + "libfuzzer-sys", + "rand", + "serde", + "serde_derive", + "wasm-encoder 0.35.0", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wat", +] + +[[package]] +name = "wasm-tools" +version = "1.0.47" +dependencies = [ + "addr2line", + "anyhow", + "arbitrary", + "clap 4.3.22", + "cpp_demangle 0.4.2", + "diff", + "env_logger", + "gimli", + "is_executable", + "log", + "pretty_assertions", + "rayon", + "regex", + "rustc-demangle", + "serde", + "serde_derive", + "serde_json", + "tempfile", + "termcolor", + "wasm-compose", + "wasm-encoder 0.35.0", + "wasm-metadata", + "wasm-mutate", + "wasm-shrink", + "wasm-smith", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wast", + "wat", + "wit-component", + "wit-parser 0.12.0", + "wit-smith", +] + +[[package]] +name = "wasm-tools-c-api" +version = "0.1.1" +dependencies = [ + "arbitrary", + "wasm-mutate", + "wasm-shrink", + "wasm-smith", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wast", + "wat", +] + +[[package]] +name = "wasm-tools-fuzz" +version = "0.0.1" +dependencies = [ + "anyhow", + "arbitrary", + "env_logger", + "libfuzzer-sys", + "log", + "tempfile", + "wasm-encoder 0.35.0", + "wasm-mutate", + "wasm-smith", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wasmtime", + "wast", + "wat", + "wit-component", + "wit-parser 0.12.0", + "wit-smith", +] + +[[package]] +name = "wasmparser" +version = "0.110.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dfcdb72d96f01e6c85b6bf20102e7423bdbaad5c337301bab2bbf253d26413c" +dependencies = [ + "indexmap 2.0.0", + "semver", +] + +[[package]] +name = "wasmparser" +version = "0.115.0" +dependencies = [ + "anyhow", + "criterion", + "env_logger", + "indexmap 2.0.0", + "log", + "once_cell", + "rayon", + "semver", + "wasm-encoder 0.35.0", + "wast", + "wat", +] + +[[package]] +name = "wasmprinter" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cd12ed4d96a984e4b598a17457f1126d01640cc7461afbb319642111ff9e7f" +dependencies = [ + "anyhow", + "wasmparser 0.110.0", +] + +[[package]] +name = "wasmprinter" +version = "0.2.70" +dependencies = [ + "anyhow", + "diff", + "rayon", + "tempfile", + "wasmparser 0.115.0", + "wast", + "wat", +] + +[[package]] +name = "wasmtime" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a70fb49f6d619463ca39718e3aafe1b6e4e57fa026aaacc0a350efaed739d1d" +dependencies = [ + "anyhow", + "bincode", + "bumpalo", + "cfg-if", + "encoding_rs", + "fxprof-processed-profile", + "indexmap 2.0.0", + "libc", + "log", + "object", + "once_cell", + "paste", + "psm", + "serde", + "serde_json", + "target-lexicon", + "wasm-encoder 0.31.1", + "wasmparser 0.110.0", + "wasmtime-component-macro", + "wasmtime-component-util", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", + "wasmtime-winch", + "windows-sys", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada1830a37e61033ce2f9a754fd73c47a6897ad0bde6f680a7b8f19af9b96b71" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-component-macro" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37f0866a7bedfbaf61698a7d9f19f642052cdc02dc4a67eb41844fa49fabd162" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn", + "wasmtime-component-util", + "wasmtime-wit-bindgen", + "wit-parser 0.9.2", +] + +[[package]] +name = "wasmtime-component-util" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0035b51b0b895d77d83af51b65283defd8bae10ce9521d8162d63c1f16090ab2" + +[[package]] +name = "wasmtime-cranelift" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efd62f1f47103199c50f8b0c9df4125280ad4f2d6a0d2bec7b2b279f409fdf4" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser 0.110.0", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-cranelift-shared" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c439bbe3b049a2c04fd4c6a3b937f8892d0f39e9ea180c6dd6ac94f349a034" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-native", + "gimli", + "object", + "target-lexicon", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1371be0e60ebb9790baf41f3d51c8741b7abca210bedcab3aa09b170167456c7" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap 2.0.0", + "log", + "object", + "serde", + "target-lexicon", + "thiserror", + "wasm-encoder 0.31.1", + "wasmparser 0.110.0", + "wasmprinter 0.2.62", + "wasmtime-component-util", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6145785fdc6c6e36f1cc91aa04d03eedcad6d0d87ae5d0708355cd3dbc7882b" +dependencies = [ + "addr2line", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle 0.3.5", + "gimli", + "log", + "object", + "rustc-demangle", + "rustix 0.38.8", + "serde", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb9846545044c2b4ba14cb206e2ca4f603989d2176f034ca0a56565c98c1c4" +dependencies = [ + "once_cell", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53a371aba40de6a84621993f2f9ff1ff1366fb1cb32d21d0d01f7815fe12313" +dependencies = [ + "cfg-if", + "libc", + "windows-sys", +] + +[[package]] +name = "wasmtime-runtime" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c99982745bca96680c9e46c4d74080e940dcbe1ac0fe0a455e7ce10d2857b300" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "encoding_rs", + "indexmap 2.0.0", + "libc", + "log", + "mach", + "memfd", + "memoffset", + "paste", + "rand", + "rustix 0.38.8", + "sptr", + "wasm-encoder 0.31.1", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-jit-debug", + "wasmtime-versioned-export-macros", + "windows-sys", +] + +[[package]] +name = "wasmtime-types" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ca1bccb131a6d878523aa89e94b58607b96cbca86a9ba2292f6d769b6cbcec" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser 0.110.0", +] + +[[package]] +name = "wasmtime-versioned-export-macros" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2074279edf31e0e7f9e03f06ebe1fae459a930c9d3e4a931fb721ebe9c83fc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "wasmtime-winch" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b603a999095336de035ff8cc4f5e1a0d078c9d7649182d3a9f000972f4d79029" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "object", + "target-lexicon", + "wasmparser 0.110.0", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "winch-codegen", +] + +[[package]] +name = "wasmtime-wit-bindgen" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba9ceb094d4c85e4d143a2a583a6db8f9dcffdb503d7332ff54aebf40ef009b" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.0.0", + "wit-parser 0.9.2", +] + +[[package]] +name = "wast" +version = "66.0.2" +dependencies = [ + "anyhow", + "leb128", + "memchr", + "rayon", + "unicode-width", + "wasm-encoder 0.35.0", + "wasmparser 0.115.0", + "wat", +] + +[[package]] +name = "wat" +version = "1.0.77" +dependencies = [ + "wast", +] + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winch-codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c8e117592d104837af2819a908d851932e83e842b9d63bbdbfb5e4d77788da1" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "wasmparser 0.110.0", + "wasmtime-environ", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92ecb8ae0317859f509f17b19adc74b0763b0fa3b085dea8ed01085c8dac222" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d14b0ee96970be7108701212f097ce67ca772fd84cb0ffbc86d26a94e77ba929" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1332277d49f440c8fc6014941e320ee47ededfcce10cb272728470f56cc092c9" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d992130ac399d56f02c20564e9975ac5ba08cb25cb832849bbc0d736a101abe5" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "962e96d0fa4b4773c63977977ea6564f463fb10e34a6e07360428b53ae7a3f71" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30652a53018a48a9735fbc2986ff0446c37bc8bed0d3f98a0ed4d04cdb80027e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5bb3f0331abfe1a95af56067f1e64b3791b55b5373b03869560b6025de809bf" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd1df36d9fd0bbe4849461de9b969f765170f4e0f90497d580a235d515722b10" + +[[package]] +name = "wit-component" +version = "0.15.0" +dependencies = [ + "anyhow", + "bitflags 2.4.0", + "env_logger", + "glob", + "indexmap 2.0.0", + "log", + "pretty_assertions", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.35.0", + "wasm-metadata", + "wasmparser 0.115.0", + "wasmprinter 0.2.70", + "wasmtime", + "wast", + "wat", + "wit-parser 0.12.0", +] + +[[package]] +name = "wit-parser" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "541efa2046e544de53a9da1e2f6299e63079840360c9e106f1f8275a97771318" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.0.0", + "log", + "pulldown-cmark", + "semver", + "unicode-xid", + "url", +] + +[[package]] +name = "wit-parser" +version = "0.12.0" +dependencies = [ + "anyhow", + "env_logger", + "id-arena", + "indexmap 2.0.0", + "log", + "pretty_assertions", + "rayon", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "wit-parser-fuzz" +version = "0.0.1" +dependencies = [ + "arbitrary", + "env_logger", + "libfuzzer-sys", + "log", + "wasmprinter 0.2.70", + "wit-parser 0.12.0", +] + +[[package]] +name = "wit-smith" +version = "0.1.17" +dependencies = [ + "arbitrary", + "clap 4.3.22", + "indexmap 2.0.0", + "log", + "semver", + "wit-component", + "wit-parser 0.12.0", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index 3270fcb5bc..c612d16bbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "wasm-tools" -version = "1.0.10" +version = "1.0.47" authors = ["The Wasmtime Project Developers"] -edition = "2021" +edition.workspace = true description = "CLI tools for interoperating with WebAssembly files" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://github.com/bytecodealliance/wasm-tools" @@ -10,60 +10,122 @@ categories = ["wasm"] keywords = ["webassembly", "wasm"] repository = "https://github.com/bytecodealliance/wasm-tools" readme = "README.md" -exclude = ['tests/wabt', 'tests/testsuite', 'publish.rs'] +exclude = ['tests/wabt', 'tests/testsuite', 'tests/snapshots', 'ci'] [workspace] -members = ['crates/c-api', 'fuzz', 'crates/wasm-encoder', 'crates/fuzz-stats', 'crates/wasm-mutate-stats'] +members = [ + 'crates/c-api', + 'crates/fuzz-stats', + 'crates/wasm-mutate-stats', + 'fuzz', + 'crates/wit-parser/fuzz', +] -[dependencies] -anyhow = "1.0" -atty = "0.2" +[workspace.package] +edition = '2021' + +[workspace.dependencies] +anyhow = "1.0.58" +arbitrary = "1.1.0" +clap = { version = "4.0.0", features = ["derive"] } +criterion = "0.3.3" env_logger = "0.9" -log = "0.4" -clap = { version = "3.1.8", features = ['derive'] } +indexmap = "2.0.0" +leb128 = "0.2.4" +libfuzzer-sys = "0.4.0" +log = "0.4.17" +num_cpus = "1.13" +rand = { version = "0.8.4", features = ["small_rng"] } +rayon = "1.3" +serde = "1.0.166" +serde_derive = "1.0.166" +serde_json = { version = "1" } +wasmtime = { version = "12.0.0", default-features = false, features = ['cranelift', 'component-model'] } +url = "2.0.0" +pretty_assertions = "1.3.0" +semver = "1.0.0" + +wasm-compose = { version = "0.4.9", path = "crates/wasm-compose" } +wasm-encoder = { version = "0.35.0", path = "crates/wasm-encoder" } +wasm-metadata = { version = "0.10.9", path = "crates/wasm-metadata" } +wasm-mutate = { version = "0.2.38", path = "crates/wasm-mutate" } +wasm-shrink = { version = "0.1.39", path = "crates/wasm-shrink" } +wasm-smith = { version = "0.12.21", path = "crates/wasm-smith" } +wasmparser = { version = "0.115.0", path = "crates/wasmparser" } +wasmprinter = { version = "0.2.70", path = "crates/wasmprinter" } +wast = { version = "66.0.2", path = "crates/wast" } +wat = { version = "1.0.77", path = "crates/wat" } +wit-component = { version = "0.15.0", path = "crates/wit-component" } +wit-parser = { version = "0.12.0", path = "crates/wit-parser" } +wit-smith = { version = "0.1.17", path = "crates/wit-smith" } + +[dependencies] +anyhow = { workspace = true } +env_logger = { workspace = true } +log = { workspace = true } +clap = { workspace = true } tempfile = "3.2.0" -wat = { path = "crates/wat", version = '1.0.48' } +wat = { workspace = true } +termcolor = "1.2.0" # Dependencies of `validate` -wasmparser = { path = "crates/wasmparser", optional = true, version = '0.90.0' } -rayon = { version = "1.0", optional = true } +wasmparser = { workspace = true, optional = true } +rayon = { workspace = true, optional = true } # Dependencies of `print` -wasmprinter = { path = "crates/wasmprinter", version = '0.2.39' } +wasmprinter = { workspace = true } # Dependencies of `smith` -arbitrary = { version = "1.0.0", optional = true } -serde = { version = "1", features = ['derive'], optional = true } -serde_json = { version = "1", optional = true } -wasm-smith = { path = "crates/wasm-smith", features = ["_internal_cli"], optional = true, version = '0.11.4' } +arbitrary = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +serde_json = { workspace = true, optional = true } +wasm-smith = { workspace = true, features = ["_internal_cli"], optional = true } # Dependencies of `shrink` -wasm-shrink = { path = "crates/wasm-shrink", features = ["clap"], optional = true, version = '0.1.9' } -is_executable = { version = "1.0.1", optional = true } +wasm-shrink = { workspace = true, features = ["clap"], optional = true } # Dependencies of `mutate` -wasm-mutate = { path = "crates/wasm-mutate", features = ["clap"], optional = true, version = '0.2.7' } - -# Dependencies of `dump` -wasmparser-dump = { path = "crates/dump", optional = true, version = '0.1.7' } +wasm-mutate = { workspace = true, features = ["clap"], optional = true } # Dependencies of `strip` -wasm-encoder = { path = "crates/wasm-encoder", optional = true, version = '0.16.0' } +wasm-encoder = { workspace = true, optional = true } +regex = { version = "1.6.0", optional = true } # Dependencies of `compose` -wasm-compose = { path = "crates/wasm-compose", optional = true, version = '0.1.0', features = ['cli'] } +wasm-compose = { workspace = true, optional = true } + +# Dependencies of `demangle` +rustc-demangle = { version = "0.1.21", optional = true } +cpp_demangle = { version = "0.4.0", optional = true } + +# Dependencies of `component` +wit-component = { workspace = true, optional = true, features = ['dummy-module', 'wat'] } +wit-parser = { workspace = true, optional = true } +wast = { workspace = true, optional = true } + +# Dependencies of `metadata` +wasm-metadata = { workspace = true, features = ["clap"], optional = true } + +# Dependencies of `wit-smith` +wit-smith = { workspace = true, features = ["clap"], optional = true } + +# Dependencies of `addr2line` +addr2line = { version = "0.20.0", optional = true } +gimli = { version = "0.27.2", optional = true } + +[target.'cfg(not(target_family = "wasm"))'.dependencies] +is_executable = { version = "1.0.1", optional = true } [dev-dependencies] -anyhow = "1.0" -getopts = "0.2" serde_json = "1.0" tempfile = "3.1" diff = "0.1" -wasmparser-dump = { path = 'crates/dump' } wast = { path = 'crates/wast' } +pretty_assertions = { workspace = true } [[test]] -name = "dump" +name = "cli" harness = false [[test]] @@ -72,16 +134,44 @@ harness = false [features] # By default, all subcommands are built -default = ['shrink', 'smith', 'mutate', 'validate', 'print', 'parse', 'dump', 'objdump', 'strip', 'compose'] +default = [ + 'shrink', + 'smith', + 'mutate', + 'validate', + 'print', + 'parse', + 'dump', + 'objdump', + 'strip', + 'compose', + 'demangle', + 'component', + 'metadata', + 'wit-smith', + 'addr2line', +] # Each subcommand is gated behind a feature and lists the dependencies it needs -validate = ['wasmparser', 'rayon'] +validate = ['dep:wasmparser', 'rayon'] print = [] parse = [] -smith = ['wasm-smith', 'arbitrary', 'serde', 'serde_json'] +smith = ['wasm-smith', 'arbitrary', 'serde', 'serde_derive', 'serde_json'] shrink = ['wasm-shrink', 'is_executable'] mutate = ['wasm-mutate'] -dump = ['wasmparser-dump'] -objdump = ['wasmparser'] -strip = ['wasm-encoder'] -compose = ['wasm-compose'] +dump = ['dep:wasmparser'] +objdump = ['dep:wasmparser'] +strip = ['wasm-encoder', 'dep:wasmparser', 'regex'] +compose = ['wasm-compose', 'dep:wasmparser'] +demangle = ['rustc-demangle', 'cpp_demangle', 'dep:wasmparser', 'wasm-encoder'] +component = [ + 'wit-component', + 'wit-parser', + 'wast', + 'wasm-encoder', + 'dep:wasmparser', + 'serde_json', +] +metadata = ['dep:wasmparser', 'wasm-metadata', 'serde_json'] +wit-smith = ['dep:wit-smith', 'arbitrary'] +addr2line = ['dep:addr2line', 'dep:gimli', 'dep:wasmparser'] diff --git a/README.md b/README.md index 919a7ad5ef..06ae5a7456 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,11 @@ This project can be installed and compiled from source with this Cargo command: $ cargo install wasm-tools ``` +Additionally there are [precompiled artifacts built on CI][artifacts] which are +available for download as well. + +[artifacts]: https://github.com/bytecodealliance/wasm-tools/releases + Installation can be confirmed with: ``` @@ -37,7 +42,7 @@ programmatically as well: | Tool | Crate | Description | |------|------|------------| | `wasm-tools validate` | [wasmparser] | Validate a WebAssembly file | -| `wasm-tools parser` | [wat] and [wast] | Translate the WebAssembly text format to binary | +| `wasm-tools parse` | [wat] and [wast] | Translate the WebAssembly text format to binary | | `wasm-tools print` | [wasmprinter] | Translate the WebAssembly binary format to text | | `wasm-tools smith` | [wasm-smith] | Generate a "random" valid WebAssembly module | | `wasm-tools mutate` | [wasm-mutate] | Mutate an input wasm file into a new valid wasm file | @@ -45,6 +50,14 @@ programmatically as well: | `wasm-tools dump` | | Print debugging information about the binary format | | `wasm-tools objdump` | | Print debugging information about section headers | | `wasm-tools strip` | | Remove custom sections from a WebAssembly file | +| `wasm-tools demangle` | | Demangle Rust and C++ symbol names in the `name` section | +| `wasm-tools compose` | [wasm-compose] | Compose wasm components together | +| `wasm-tools component new` | [wit-component] | Create a component from a core wasm binary | +| `wasm-tools component wit` | | Extract a `*.wit` interface from a component | +| `wasm-tools component embed` | | Embed a `component-type` custom section in a core wasm binary | +| `wasm-tools metadata show` | [wasm-metadata] | Show name and producer metadata in a component or module | +| `wasm-tools metadata add` | | Add name or producer metadata to a component or module | +| `wasm-tools addr2line` | | Translate wasm offsets to filename/line numbers with DWARF | [wasmparser]: https://crates.io/crates/wasmparser [wat]: https://crates.io/crates/wat @@ -53,6 +66,9 @@ programmatically as well: [wasm-smith]: https://crates.io/crates/wasm-smith [wasm-mutate]: https://crates.io/crates/wasm-mutate [wasm-shrink]: https://crates.io/crates/wasm-shrink +[wit-component]: https://crates.io/crates/wit-component +[wasm-compose]: https://crates.io/crates/wasm-compose +[wasm-metadata]: https://crates.io/crates/wasm-metadata The `wasm-tools` CLI is primarily intended to be a debugging aid. The various subcommands all have `--help` explainer texts to describe more about their @@ -73,6 +89,12 @@ implemented in this repository as well. These libraries are: * [**`wasm-smith`**](crates/wasm-smith) - a WebAssembly test case generator * [**`wasm-encoder`**](crates/wasm-encoder) - a crate to generate a binary WebAssembly module +* [**`wit-parser`**](crates/wit-parser) - a crate to parse and manage `*.wit` + files and interfaces. +* [**`wit-component`**](crates/wit-component) - a crate to create components + from core wasm modules. +* [**`wasm-metadata`**](crates/wasm-metadata) - a crate to manipulate name and + producer metadata (custom sections) in a wasm module or component. It's recommended to use the libraries directly rather than the CLI tooling when embedding into a separate project. diff --git a/build.rs b/build.rs new file mode 100644 index 0000000000..707ae43fe5 --- /dev/null +++ b/build.rs @@ -0,0 +1,34 @@ +use std::{path::Path, process::Command}; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + commit_info(); +} + +fn commit_info() { + if !Path::new(".git").exists() { + return; + } + let output = match Command::new("git") + .arg("log") + .arg("-1") + .arg("--date=short") + .arg("--format=%H %h %cd") + .arg("--abbrev=9") + .output() + { + Ok(output) if output.status.success() => output, + _ => return, + }; + let stdout = String::from_utf8(output.stdout).unwrap(); + let mut parts = stdout.split_whitespace(); + let mut next = || parts.next().unwrap(); + println!("cargo:rustc-env=CARGO_GIT_HASH={}", next()); + println!( + "cargo:rustc-env=CARGO_VERSION_INFO={} ({} {})", + env!("CARGO_PKG_VERSION"), + next(), + next() + ); +} diff --git a/ci/build-tarballs.sh b/ci/build-tarballs.sh new file mode 100755 index 0000000000..d8fb762298 --- /dev/null +++ b/ci/build-tarballs.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +set -ex + +platform=$1 +target=$2 + +rm -rf tmp +mkdir tmp +mkdir -p dist + +tag=dev +if [[ $GITHUB_REF == refs/tags/wasm-tools-* ]]; then + tag=${GITHUB_REF:21} +fi + +bin_pkgname=wasm-tools-$tag-$platform + +mkdir tmp/$bin_pkgname +cp LICENSE README.md tmp/$bin_pkgname + +fmt=tar +if [ "$platform" = "x86_64-windows" ]; then + cp target/release/wasm-tools.exe tmp/$bin_pkgname + fmt=zip +elif [ "$target" = "" ]; then + cp target/release/wasm-tools tmp/$bin_pkgname +else + cp target/$target/release/wasm-tools tmp/$bin_pkgname +fi + + +mktarball() { + dir=$1 + if [ "$fmt" = "tar" ]; then + tar czvf dist/$dir.tar.gz -C tmp $dir + else + # Note that this runs on Windows, and it looks like GitHub Actions doesn't + # have a `zip` tool there, so we use something else + (cd tmp && 7z a ../dist/$dir.zip $dir/) + fi +} + +mktarball $bin_pkgname diff --git a/ci/docker/aarch64-linux/Dockerfile b/ci/docker/aarch64-linux/Dockerfile new file mode 100644 index 0000000000..a176276b5e --- /dev/null +++ b/ci/docker/aarch64-linux/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:16.04 + +RUN apt-get update -y && apt-get install -y gcc gcc-aarch64-linux-gnu ca-certificates git + +ENV PATH=$PATH:/rust/bin +ENV CARGO_BUILD_TARGET=aarch64-unknown-linux-gnu +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc diff --git a/ci/docker/x86_64-linux/Dockerfile b/ci/docker/x86_64-linux/Dockerfile new file mode 100644 index 0000000000..89ddc2b282 --- /dev/null +++ b/ci/docker/x86_64-linux/Dockerfile @@ -0,0 +1,5 @@ +FROM centos:7 + +RUN yum install -y git gcc + +ENV PATH=$PATH:/rust/bin diff --git a/publish.rs b/ci/publish.rs similarity index 87% rename from publish.rs rename to ci/publish.rs index 9fb968333f..a55c21bd33 100644 --- a/publish.rs +++ b/ci/publish.rs @@ -26,8 +26,8 @@ use std::time::Duration; // Crates we care about publishing sorted topologically. const CRATES_TO_PUBLISH: &[&str] = &[ - "wasmparser", "wasm-encoder", + "wasmparser", "wasmprinter", "wast", "wat", @@ -35,8 +35,30 @@ const CRATES_TO_PUBLISH: &[&str] = &[ "wasm-smith", "wasm-mutate", "wasm-shrink", - "wasm-tools", + "wit-parser", + "wasm-metadata", + "wit-component", "wasm-compose", + "wit-smith", + "wasm-tools", +]; + +const NO_VERIFY: &[&str] = &[ + // Circular dev dependencies between `wasmparser` and `wasm-encoder`. + "wasm-encoder", + "wasmparser", +]; + +/// A mapping from a crate to those crates which have a public dependency on +/// that crate. +/// +/// This is used so that when a major version bump of the left-hand-side is done +/// then it must also force major version bumps of everything on the +/// right-hand-side. +const PUBLIC_DEPS: &[(&str, &[&str])] = &[ + ("wasmparser", &["wasm-encoder"]), + ("wit-parser", &["wit-component"]), + ("wasm-metadata", &["wit-component"]), ]; #[derive(Clone)] @@ -64,7 +86,7 @@ fn main() { match &env::args().nth(1).expect("must have one argument")[..] { "bump" => { - let bumps = env::args() + let mut bumps = env::args() .skip(2) .map(|s| { if let Some(s) = s.strip_suffix(":major") { @@ -76,6 +98,21 @@ fn main() { } }) .collect::>(); + + // For all major version bumps automatically do a major version + // bump those crates which have a public dependency on it. + let mut extra = Vec::new(); + for (name, _) in bumps.iter().filter(|(_, major)| *major) { + if let Some((_, public_deps)) = PUBLIC_DEPS.iter().find(|(n, _)| name == n) { + extra.extend(public_deps.iter().map(|name| (name.to_string(), true))); + } + } + bumps.extend(extra); + + // Move all major bumps first in the case of duplicate keys to + // ensure that major bumps are seen first. + bumps.sort_by_key(|(_, major)| if *major { 0 } else { 1 }); + for (i, mut krate) in crates.clone().into_iter().enumerate() { bump_version(&mut krate, &mut crates, &bumps); crates[i] = krate; @@ -242,7 +279,7 @@ fn bump_version(krate: &mut Crate, crates: &mut [Crate], bumps: &[(String, bool) if !is_deps || !line.starts_with(&format!("{} ", other.name)) { continue; } - if !line.contains(&other.version) { + if !line.contains(&other.version) && !line.contains("workspace = true") { if !line.contains("version =") || !krate.publish { continue; } @@ -323,11 +360,15 @@ fn publish(krate: &Crate) -> bool { return true; } - let status = Command::new("cargo") - .arg("publish") - .current_dir(krate.manifest.parent().unwrap()) - .status() - .expect("failed to run cargo"); + let mut cmd = Command::new("cargo"); + cmd.arg("publish"); + cmd.current_dir(krate.manifest.parent().unwrap()); + + if NO_VERIFY.iter().any(|s| *s == krate.name) { + cmd.arg("--no-verify"); + } + + let status = cmd.status().expect("failed to run cargo"); if !status.success() { println!("FAIL: failed to publish `{}`: {}", krate.name, status); return false; diff --git a/crates/c-api/Cargo.toml b/crates/c-api/Cargo.toml index 2d38bb4a9f..c588816568 100644 --- a/crates/c-api/Cargo.toml +++ b/crates/c-api/Cargo.toml @@ -3,7 +3,7 @@ name = "wasm-tools-c-api" authors = ["Addison Hart "] categories = ["development-tools", "development-tools::testing", "wasm"] description = "C API to expose wasm-tools" -edition = "2021" +edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" readme = "./README.md" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/c-api" @@ -18,12 +18,11 @@ test = false doctest = false [dependencies] -arbitrary = { version = "1.1.0", features = ["derive"] } -wasmparser-dump = { version = "0.1.4", path = "../dump" } -wasm-mutate = { version = "0.2.4", path = "../wasm-mutate" } -wasm-shrink = { version = "0.1.6", path = "../wasm-shrink" } -wasm-smith = { version = "0.11.2", path = "../wasm-smith" } -wasmparser = { version = "0.90.0", path = "../wasmparser" } -wasmprinter = { version = "0.2.36", path = "../wasmprinter" } -wast = { version = "46.0.0", path = "../wast" } -wat = { version = "1.0.44", path = "../wat" } +arbitrary = { workspace = true, features = ["derive"] } +wasm-mutate = { workspace = true } +wasm-shrink = { workspace = true } +wasm-smith = { workspace = true } +wasmparser = { workspace = true } +wasmprinter = { workspace = true } +wast = { workspace = true } +wat = { workspace = true } diff --git a/crates/c-api/src/lib.rs b/crates/c-api/src/lib.rs index 0c20668b2b..1542dd1ad8 100644 --- a/crates/c-api/src/lib.rs +++ b/crates/c-api/src/lib.rs @@ -30,8 +30,13 @@ pub extern "C" fn wasm_tools_byte_vec_delete(bytes: &mut wasm_tools_byte_vec_t) } } +/// Create a new WebAssembly module with the given seed. +/// +/// # Safety +/// +/// `seed` must be a valid pointer to `seed_len` bytes of memory. #[no_mangle] -pub extern "C" fn wasm_smith_create( +pub unsafe extern "C" fn wasm_smith_create( seed: *const u8, seed_len: usize, bytes: &mut wasm_tools_byte_vec_t, diff --git a/crates/dump/Cargo.toml b/crates/dump/Cargo.toml deleted file mode 100644 index b84a3d3387..0000000000 --- a/crates/dump/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "wasmparser-dump" -version = "0.1.7" -authors = ["The Wasmtime Project Developers"] -edition = "2021" -license = "Apache-2.0 WITH LLVM-exception" -repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/dump" -description = "Utility to dump debug information about the wasm binary format" - -[dependencies] -anyhow = "1" -wasmparser = { path = "../wasmparser", version = "0.90.0" } diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs deleted file mode 100644 index 00cfd8ff60..0000000000 --- a/crates/dump/src/lib.rs +++ /dev/null @@ -1,632 +0,0 @@ -use anyhow::{bail, Result}; -use std::fmt::Write as _; -use std::io::Write; -use wasmparser::*; - -pub fn dump_wasm(bytes: &[u8]) -> Result { - let mut dst = vec![]; - { - let mut d = Dump::new(bytes, &mut dst); - d.run()?; - } - Ok(String::from_utf8(dst).unwrap()) -} - -pub fn dump_wasm_into(bytes: &[u8], into: impl Write) -> Result<()> { - let mut d = Dump::new(bytes, into); - d.run()?; - Ok(()) -} - -struct Dump<'a> { - bytes: &'a [u8], - cur: usize, - state: String, - dst: Box, - nesting: u32, - offset_width: usize, -} - -#[derive(Default)] -struct Indices { - // Core module indexes - core_types: u32, - core_funcs: u32, - core_globals: u32, - core_tables: u32, - core_memories: u32, - core_tags: u32, - core_modules: u32, - core_instances: u32, - - // Component indexes - types: u32, - funcs: u32, - components: u32, - instances: u32, - values: u32, -} - -enum ComponentTypeKind { - Func, - Component, - Instance, - DefinedType, -} - -const NBYTES: usize = 4; - -impl<'a> Dump<'a> { - fn new(bytes: &'a [u8], dst: impl Write + 'a) -> Dump<'a> { - Dump { - bytes, - cur: 0, - nesting: 0, - state: String::new(), - dst: Box::new(dst) as _, - offset_width: format!("{:x}", bytes.len()).len() + 1, - } - } - - fn run(&mut self) -> Result<()> { - self.print_module()?; - assert_eq!(self.cur, self.bytes.len()); - Ok(()) - } - - fn print_module(&mut self) -> Result<()> { - let mut stack = Vec::new(); - let mut i = Indices::default(); - let mut component_types = Vec::new(); - self.nesting += 1; - - for item in Parser::new(0).parse_all(self.bytes) { - match item? { - Payload::Version { - num, - encoding, - range, - } => { - write!(self.state, "version {} ({:?})", num, encoding)?; - self.print(range.end)?; - } - Payload::TypeSection(s) => self.section(s, "type", |me, end, t| { - write!(me.state, "[type {}] {:?}", inc(&mut i.core_types), t)?; - me.print(end) - })?, - Payload::ImportSection(s) => self.section(s, "import", |me, end, imp| { - write!(me.state, "import ")?; - match imp.ty { - TypeRef::Func(_) => write!(me.state, "[func {}]", inc(&mut i.core_funcs))?, - TypeRef::Memory(_) => { - write!(me.state, "[memory {}]", inc(&mut i.core_memories))? - } - TypeRef::Tag(_) => write!(me.state, "[tag {}]", inc(&mut i.core_tags))?, - TypeRef::Table(_) => { - write!(me.state, "[table {}]", inc(&mut i.core_tables))? - } - TypeRef::Global(_) => { - write!(me.state, "[global {}]", inc(&mut i.core_globals))? - } - } - write!(me.state, " {:?}", imp)?; - me.print(end) - })?, - Payload::FunctionSection(s) => { - let mut cnt = i.core_funcs; - self.section(s, "func", |me, end, f| { - write!(me.state, "[func {}] type {:?}", inc(&mut cnt), f)?; - me.print(end) - })? - } - Payload::TableSection(s) => self.section(s, "table", |me, end, t| { - write!(me.state, "[table {}] {:?}", inc(&mut i.core_tables), t)?; - me.print(end) - })?, - Payload::MemorySection(s) => self.section(s, "memory", |me, end, m| { - write!(me.state, "[memory {}] {:?}", inc(&mut i.core_memories), m)?; - me.print(end) - })?, - Payload::TagSection(s) => self.section(s, "tag", |me, end, m| { - write!(me.state, "[tag {}] {:?}", inc(&mut i.core_tags), m)?; - me.print(end) - })?, - Payload::ExportSection(s) => self.section(s, "export", |me, end, e| { - write!(me.state, "export {:?}", e)?; - me.print(end) - })?, - Payload::GlobalSection(s) => self.section(s, "global", |me, _end, g| { - write!(me.state, "[global {}] {:?}", inc(&mut i.core_globals), g.ty)?; - me.print(g.init_expr.get_binary_reader().original_position())?; - me.print_ops(g.init_expr.get_operators_reader()) - })?, - Payload::StartSection { func, range } => { - write!(self.state, "start section")?; - self.print(range.start)?; - write!(self.state, "start function {}", func)?; - self.print(range.end)?; - } - Payload::DataCountSection { count, range } => { - write!(self.state, "data count section")?; - self.print(range.start)?; - write!(self.state, "data count {}", count)?; - self.print(range.end)?; - } - Payload::ElementSection(s) => self.section(s, "element", |me, _end, i| { - write!(me.state, "element {:?}", i.ty)?; - let mut items = i.items.get_items_reader()?; - match i.kind { - ElementKind::Passive => { - write!(me.state, " passive, {} items", items.get_count())?; - } - ElementKind::Active { - table_index, - offset_expr, - } => { - write!(me.state, " table[{}]", table_index)?; - me.print(offset_expr.get_binary_reader().original_position())?; - me.print_ops(offset_expr.get_operators_reader())?; - write!(me.state, "{} items", items.get_count())?; - } - ElementKind::Declared => { - write!(me.state, " declared {} items", items.get_count())?; - } - } - me.print(items.original_position())?; - for _ in 0..items.get_count() { - let item = items.read()?; - write!(me.state, "item {:?}", item)?; - me.print(items.original_position())?; - } - Ok(()) - })?, - - Payload::DataSection(s) => self.section(s, "data", |me, end, i| { - match i.kind { - DataKind::Passive => { - write!(me.state, "data passive")?; - me.print(end - i.data.len())?; - } - DataKind::Active { - memory_index, - offset_expr, - } => { - write!(me.state, "data memory[{}]", memory_index)?; - me.print(offset_expr.get_binary_reader().original_position())?; - me.print_ops(offset_expr.get_operators_reader())?; - } - } - me.print_byte_header()?; - for _ in 0..NBYTES { - write!(me.dst, "---")?; - } - writeln!(me.dst, "-| ... {} bytes of data", i.data.len())?; - me.cur = end; - Ok(()) - })?, - - Payload::CodeSectionStart { count, range, size } => { - write!(self.state, "code section")?; - self.print(range.start)?; - write!(self.state, "{} count", count)?; - self.print(range.end - size as usize)?; - } - - Payload::CodeSectionEntry(body) => { - writeln!( - self.dst, - "============== func {} ====================", - inc(&mut i.core_funcs), - )?; - write!(self.state, "size of function")?; - self.print(body.get_binary_reader().original_position())?; - let mut locals = body.get_locals_reader()?; - write!(self.state, "{} local blocks", locals.get_count())?; - self.print(locals.original_position())?; - for _ in 0..locals.get_count() { - let (amt, ty) = locals.read()?; - write!(self.state, "{} locals of type {:?}", amt, ty)?; - self.print(locals.original_position())?; - } - self.print_ops(body.get_operators_reader()?)?; - } - - // Component sections - Payload::ModuleSection { range, .. } => { - write!( - self.state, - "[core module {}] inline size", - inc(&mut i.core_modules) - )?; - self.print(range.start)?; - self.nesting += 1; - stack.push(i); - i = Indices::default(); - } - - Payload::InstanceSection(s) => self.section(s, "core instance", |me, end, e| { - write!( - me.state, - "[core instance {}] {:?}", - inc(&mut i.core_instances), - e - )?; - me.print(end) - })?, - - Payload::CoreTypeSection(s) => self.section(s, "core type", |me, end, t| { - write!(me.state, "[core type {}] {:?}", inc(&mut i.core_types), t)?; - me.print(end) - })?, - - Payload::ComponentSection { range, .. } => { - write!( - self.state, - "[component {}] inline size", - inc(&mut i.components) - )?; - self.print(range.start)?; - self.nesting += 1; - stack.push(i); - i = Indices::default(); - } - - Payload::ComponentInstanceSection(s) => { - self.section(s, "component instance", |me, end, e| { - write!(me.state, "[instance {}] {:?}", inc(&mut i.instances), e)?; - me.print(end) - })? - } - - Payload::ComponentAliasSection(s) => { - self.section(s, "component alias", |me, end, a| { - let (kind, num) = match a { - ComponentAlias::InstanceExport { - kind: ComponentExternalKind::Module, - .. - } - | ComponentAlias::Outer { - kind: ComponentOuterAliasKind::CoreModule, - .. - } => ("module", inc(&mut i.core_modules)), - ComponentAlias::Outer { - kind: ComponentOuterAliasKind::CoreType, - .. - } => ("core type", inc(&mut i.core_types)), - ComponentAlias::InstanceExport { - kind: ComponentExternalKind::Func, - .. - } => ("func", inc(&mut i.funcs)), - ComponentAlias::InstanceExport { - kind: ComponentExternalKind::Value, - .. - } => ("value", inc(&mut i.values)), - ComponentAlias::InstanceExport { - kind: ComponentExternalKind::Type, - .. - } - | ComponentAlias::Outer { - kind: ComponentOuterAliasKind::Type, - .. - } => ("type", inc(&mut i.types)), - ComponentAlias::InstanceExport { - kind: ComponentExternalKind::Instance, - .. - } => ("instance", inc(&mut i.instances)), - ComponentAlias::InstanceExport { - kind: ComponentExternalKind::Component, - .. - } - | ComponentAlias::Outer { - kind: ComponentOuterAliasKind::Component, - .. - } => ("component", inc(&mut i.components)), - ComponentAlias::CoreInstanceExport { kind, .. } => match kind { - ExternalKind::Func => ("core func", inc(&mut i.core_funcs)), - ExternalKind::Table => ("core table", inc(&mut i.core_tables)), - ExternalKind::Memory => ("core memory", inc(&mut i.core_memories)), - ExternalKind::Global => ("core global", inc(&mut i.core_globals)), - ExternalKind::Tag => ("core tag", inc(&mut i.core_tags)), - }, - }; - - write!(me.state, "alias [{} {}] {:?}", kind, num, a)?; - me.print(end) - })? - } - - Payload::ComponentTypeSection(s) => { - self.section(s, "component type", |me, end, t| { - write!(me.state, "[type {}] {:?}", inc(&mut i.types), t)?; - component_types.push(match t { - ComponentType::Defined(_) => ComponentTypeKind::DefinedType, - ComponentType::Func(_) => ComponentTypeKind::Func, - ComponentType::Component(_) => ComponentTypeKind::Component, - ComponentType::Instance(_) => ComponentTypeKind::Instance, - }); - me.print(end) - })? - } - - Payload::ComponentImportSection(s) => { - self.section(s, "component import", |me, end, item| { - let (desc, idx) = match item.ty { - ComponentTypeRef::Module(..) => ("module", inc(&mut i.core_modules)), - ComponentTypeRef::Func(..) => ("func", inc(&mut i.funcs)), - ComponentTypeRef::Value(..) => ("value", inc(&mut i.values)), - ComponentTypeRef::Type(..) => ("type", inc(&mut i.types)), - ComponentTypeRef::Instance(..) => ("instance", inc(&mut i.instances)), - ComponentTypeRef::Component(..) => { - ("component", inc(&mut i.components)) - } - }; - write!(me.state, "[{desc} {idx}] {item:?}")?; - me.print(end) - })? - } - - Payload::ComponentCanonicalSection(s) => { - self.section(s, "canonical function", |me, end, f| { - let (name, col) = match &f { - CanonicalFunction::Lift { .. } => ("func", &mut i.funcs), - CanonicalFunction::Lower { .. } => ("core func", &mut i.core_funcs), - }; - - write!(me.state, "[{} {}] {:?}", name, inc(col), f)?; - me.print(end) - })? - } - - Payload::ComponentExportSection(s) => { - self.section(s, "component export", |me, end, e| { - write!(me.state, "export {:?}", e)?; - me.print(end) - })? - } - - Payload::ComponentStartSection(mut s) => { - write!(self.state, "start section")?; - self.print(s.range().start)?; - write!(self.state, "{:?}", s.read()?)?; - self.print(s.range().end)?; - } - - Payload::CustomSection(c) => { - write!(self.state, "custom section")?; - self.print(c.range().start)?; - write!(self.state, "name: {:?}", c.name())?; - self.print(c.data_offset())?; - if c.name() == "name" { - let mut iter = NameSectionReader::new(c.data(), c.data_offset())?; - while !iter.eof() { - self.print_custom_name_section(iter.read()?, iter.original_position())?; - } - } else { - self.print_byte_header()?; - for _ in 0..NBYTES { - write!(self.dst, "---")?; - } - writeln!(self.dst, "-| ... {} bytes of data", c.data().len())?; - self.cur += c.data().len(); - } - } - Payload::UnknownSection { - id, - range, - contents, - } => { - write!(self.state, "unknown section: {}", id)?; - self.print(range.start)?; - self.print_byte_header()?; - for _ in 0..NBYTES { - write!(self.dst, "---")?; - } - writeln!(self.dst, "-| ... {} bytes of data", contents.len())?; - self.cur += contents.len(); - } - Payload::End(_) => { - self.nesting -= 1; - if self.nesting > 0 { - i = stack.pop().unwrap(); - } - } - } - } - - Ok(()) - } - - fn print_name_map(&mut self, thing: &str, n: NameMap<'_>) -> Result<()> { - write!(self.state, "{} names", thing)?; - self.print(n.original_position())?; - let mut map = n.get_map()?; - write!(self.state, "{} count", map.get_count())?; - self.print(map.original_position())?; - for _ in 0..map.get_count() { - write!(self.state, "{:?}", map.read()?)?; - self.print(map.original_position())?; - } - Ok(()) - } - - fn print_indirect_name_map( - &mut self, - thing_a: &str, - thing_b: &str, - n: IndirectNameMap<'_>, - ) -> Result<()> { - write!(self.state, "{} names", thing_b)?; - self.print(n.original_position())?; - let mut outer_map = n.get_indirect_map()?; - write!(self.state, "{} count", outer_map.get_indirect_count())?; - self.print(outer_map.original_position())?; - for _ in 0..outer_map.get_indirect_count() { - let inner = outer_map.read()?; - write!( - self.state, - "{} {} {}s", - thing_a, inner.indirect_index, thing_b, - )?; - self.print(inner.original_position())?; - let mut map = inner.get_map()?; - write!(self.state, "{} count", map.get_count())?; - self.print(map.original_position())?; - for _ in 0..map.get_count() { - write!(self.state, "{:?}", map.read()?)?; - self.print(map.original_position())?; - } - } - Ok(()) - } - - fn print_custom_name_section(&mut self, name: Name<'_>, end: usize) -> Result<()> { - match name { - Name::Module(n) => { - write!(self.state, "module name")?; - self.print(n.original_position())?; - write!(self.state, "{:?}", n.get_name()?)?; - self.print(end)?; - } - Name::Function(n) => self.print_name_map("function", n)?, - Name::Local(n) => self.print_indirect_name_map("function", "local", n)?, - Name::Label(n) => self.print_indirect_name_map("function", "label", n)?, - Name::Type(n) => self.print_name_map("type", n)?, - Name::Table(n) => self.print_name_map("table", n)?, - Name::Memory(n) => self.print_name_map("memory", n)?, - Name::Global(n) => self.print_name_map("global", n)?, - Name::Element(n) => self.print_name_map("element", n)?, - Name::Data(n) => self.print_name_map("data", n)?, - Name::Unknown { ty, range, .. } => { - write!(self.state, "unknown names: {}", ty)?; - self.print(range.start)?; - self.print(end)?; - } - } - Ok(()) - } - - fn section( - &mut self, - iter: T, - name: &str, - print: impl FnMut(&mut Self, usize, T::Item) -> Result<()>, - ) -> Result<()> - where - T: SectionReader + SectionWithLimitedItems, - { - write!(self.state, "{} section", name)?; - self.print(iter.range().start)?; - self.print_iter(iter, print) - } - - fn print_iter( - &mut self, - mut iter: T, - mut print: impl FnMut(&mut Self, usize, T::Item) -> Result<()>, - ) -> Result<()> - where - T: SectionReader + SectionWithLimitedItems, - { - write!(self.state, "{} count", iter.get_count())?; - self.print(iter.original_position())?; - for _ in 0..iter.get_count() { - let item = iter.read()?; - print(self, iter.original_position(), item)?; - } - if !iter.eof() { - bail!("too many bytes in section"); - } - Ok(()) - } - - fn print_ops(&mut self, mut i: OperatorsReader) -> Result<()> { - while !i.eof() { - match i.visit_with_offset(self) { - Ok(()) => {} - Err(_) => write!(self.state, "??")?, - } - self.print(i.original_position())?; - } - Ok(()) - } - - fn print(&mut self, end: usize) -> Result<()> { - assert!( - self.cur < end, - "{:#x} >= {:#x}\ntrying to print: {}", - self.cur, - end, - self.state, - ); - let bytes = &self.bytes[self.cur..end]; - self.print_byte_header()?; - for (i, chunk) in bytes.chunks(NBYTES).enumerate() { - if i > 0 { - for _ in 0..self.nesting - 1 { - write!(self.dst, " ")?; - } - for _ in 0..self.offset_width { - write!(self.dst, " ")?; - } - write!(self.dst, " |")?; - } - for j in 0..NBYTES { - match chunk.get(j) { - Some(b) => write!(self.dst, " {:02x}", b)?, - None => write!(self.dst, " ")?, - } - } - if i == 0 { - write!(self.dst, " | ")?; - write!(self.dst, "{}", &self.state)?; - self.state.truncate(0); - } - writeln!(self.dst)?; - } - self.cur = end; - Ok(()) - } - - fn print_byte_header(&mut self) -> Result<()> { - for _ in 0..self.nesting - 1 { - write!(self.dst, " ")?; - } - write!( - self.dst, - "{:#width$x} |", - self.cur, - width = self.offset_width + 2 - )?; - Ok(()) - } -} - -fn inc(spot: &mut u32) -> u32 { - let ret = *spot; - *spot += 1; - ret -} - -macro_rules! define_visit_operator { - ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { - $( - fn $visit(&mut self, _offset: usize $($(,$arg: $argty)*)?) { - write!( - self.state, - concat!( - "{}" - $( $(, " ", stringify!($arg), ":{:?}")* )? - ), - stringify!($visit).strip_prefix("visit_").unwrap(), - $( $($arg,)* )? - ).unwrap(); - } - )* - } -} - -impl<'a> VisitOperator<'a> for Dump<'_> { - type Output = (); - - wasmparser::for_each_operator!(define_visit_operator); -} diff --git a/crates/fuzz-stats/Cargo.toml b/crates/fuzz-stats/Cargo.toml index 7cb3cb15f2..1789e13cda 100644 --- a/crates/fuzz-stats/Cargo.toml +++ b/crates/fuzz-stats/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "fuzz-stats" version = "0.1.0" -edition = "2021" +edition.workspace = true publish = false [dependencies] -anyhow = "1.0" -arbitrary = "1.0" -num_cpus = "1.13" -rand = "0.8" -wasm-smith = { path = '../wasm-smith' } -wasmtime = "0.38.1" +anyhow = { workspace = true } +arbitrary = { workspace = true } +num_cpus = { workspace = true } +rand = { workspace = true } +wasm-smith = { workspace = true } +wasmtime = { workspace = true } [lib] doctest = false diff --git a/crates/fuzz-stats/src/bin/failed-instantiations.rs b/crates/fuzz-stats/src/bin/failed-instantiations.rs index 254cf39e11..86c8e2866b 100644 --- a/crates/fuzz-stats/src/bin/failed-instantiations.rs +++ b/crates/fuzz-stats/src/bin/failed-instantiations.rs @@ -103,9 +103,8 @@ impl State { let mut config = SwarmConfig::arbitrary(&mut u)?; config.allow_start_export = false; - // Temporarily disable the multi-memory proposal until the updated - // encoding of multi-memory has made its way into Wasmtime. - config.max_memories = config.max_memories.min(1); + // Wasmtime doesn't support this proposal yet. + config.tail_call_enabled = false; let mut wasm = wasm_smith::Module::new(config, &mut u)?; wasm.ensure_termination(10_000); @@ -118,7 +117,7 @@ impl State { let module = Module::new(&self.engine, &wasm).expect("failed to compile module"); let mut store = Store::new( &self.engine, - StoreLimits { + fuzz_stats::limits::StoreLimits { remaining_memory: 1 << 30, oom: false, }, @@ -181,34 +180,3 @@ impl State { println!(); } } - -struct StoreLimits { - remaining_memory: usize, - oom: bool, -} - -impl StoreLimits { - fn alloc(&mut self, amt: usize) -> bool { - match self.remaining_memory.checked_sub(amt) { - Some(mem) => { - self.remaining_memory = mem; - true - } - None => { - self.oom = true; - false - } - } - } -} - -impl ResourceLimiter for StoreLimits { - fn memory_growing(&mut self, current: usize, desired: usize, _maximum: Option) -> bool { - self.alloc(desired - current) - } - - fn table_growing(&mut self, current: u32, desired: u32, _maximum: Option) -> bool { - let delta = (desired - current) as usize * std::mem::size_of::(); - self.alloc(delta) - } -} diff --git a/crates/fuzz-stats/src/lib.rs b/crates/fuzz-stats/src/lib.rs index 61147493ad..21f063fa76 100644 --- a/crates/fuzz-stats/src/lib.rs +++ b/crates/fuzz-stats/src/lib.rs @@ -1 +1,2 @@ pub mod dummy; +pub mod limits; diff --git a/crates/fuzz-stats/src/limits.rs b/crates/fuzz-stats/src/limits.rs new file mode 100644 index 0000000000..f8f20526cc --- /dev/null +++ b/crates/fuzz-stats/src/limits.rs @@ -0,0 +1,39 @@ +use anyhow::Result; +use wasmtime::*; + +#[derive(Clone)] +pub struct StoreLimits { + pub remaining_memory: usize, + pub oom: bool, +} + +impl StoreLimits { + fn alloc(&mut self, amt: usize) -> bool { + match self.remaining_memory.checked_sub(amt) { + Some(mem) => { + self.remaining_memory = mem; + true + } + None => { + self.oom = true; + false + } + } + } +} + +impl ResourceLimiter for StoreLimits { + fn memory_growing( + &mut self, + current: usize, + desired: usize, + _maximum: Option, + ) -> Result { + Ok(self.alloc(desired - current)) + } + + fn table_growing(&mut self, current: u32, desired: u32, _maximum: Option) -> Result { + let delta = (desired - current) as usize * std::mem::size_of::(); + Ok(self.alloc(delta)) + } +} diff --git a/crates/wasm-compose/CONFIG.md b/crates/wasm-compose/CONFIG.md index 475cdb8ae2..f27d782cd8 100644 --- a/crates/wasm-compose/CONFIG.md +++ b/crates/wasm-compose/CONFIG.md @@ -7,18 +7,21 @@ To specify the configuration file to use, pass the `--config` option to The configuration file has the following top-level fields: -* `search-paths` : `list` (optional) - a list of paths to search for dependencies. -* `skip-validation` : `bool` (optional) - a boolean indicating whether to skip - validation of the resulting composed component. -* `dependencies` : `map` (optional) - a map specifying the explicit - locations of transitive dependencies. -* `instantiations` : `map` (optional) - a map specifying the explicit - instantiations of transitive dependencies. +* `search-paths` : `list` (optional) - a list of paths to search for +dependencies. +* `skip-validation` : `bool` (optional) - a boolean indicating whether to skip +validation of the resulting composed component. +* `dependencies` : `map` (optional) - a map specifying the +explicit locations of transitive dependencies. +* `instantiations` : `map` (optional) - a map specifying +the explicit instantiations of transitive dependencies. +* `definitions` : `list` (optional) - a list of paths to _definition_ +components. ## Dependencies -Each `dependency` specifies a path where `wasm-compose` may locate a dependency, rather -than searching the configured search paths. +Each `dependency` specifies a path where `wasm-compose` may locate a +dependency, rather than searching the configured search paths. A dependency has the following fields: @@ -46,47 +49,53 @@ dependencies: In the above example, two dependencies are defined in the configuration: -* `a` - the contents of `a.wasm` will be defined directly in the composed component. -* `b` - a component of the same type as `b.wasm` will be imported in the composed - component with name `b`; the original file will not be embedded in the composed - component. +* `a` - the contents of `a.wasm` will be defined directly in the composed +component. +* `b` - a component of the same type as `b.wasm` will be imported in the +composed component with name `b`; the original file will not be embedded in the +composed component. -_Note: importing components from a composed component is not currently supported in_ -_[Wasmtime](https://github.com/bytecodealliance/wasmtime)._ +_Note: importing components from a composed component is not currently +supported in [Wasmtime](https://github.com/bytecodealliance/wasmtime)._ -Dependency names should match the expected name of imports from components in the -component graph. +Dependency names should match the expected name of imports from components in +the component graph. ## Instantiations -Each `instantiation` specifies how a particular dependency is to be instantiated, even -allowing a dependency to be instantiated multiple times. +Each `instantiation` specifies how a particular dependency is to be +instantiated, even allowing a dependency to be instantiated multiple times. An instantiation has the following fields: -* `dependency` : `string` (optional) - the name of the dependency to instantiate. - If unspecified, the instantiation will be for a dependency of the same name as the - instantiation itself. +* `dependency` : `string` (optional) - the name of the dependency to + instantiate. -* `arguments` : `map` (optional) - a mapping of argument names to - arguments; argument names match the names of the imports of the dependency being + If unspecified, the instantiation will be for a dependency of the same name + as the instantiation itself. + +* `arguments` : `map` (optional) - a mapping of argument + names to arguments. + + Argument names match the names of the imports of the dependency being instantiated. -Note that the instantiation name `$component` is special and signifies how the input +Note that the instantiation name `$input` is special and signifies how the input component is to be instantiated. ### Instantiation arguments -Each `argument` specifies exactly which instance should be provided as argument to the -instantiation of a dependency. +Each `argument` specifies exactly which instance should be provided as argument +to the instantiation of a dependency. An argument has the following fields: * `instance` : `string` - the name of the instance to pass as the argument. -* `export` : `string` (optional) - the name of the exported instance on `instance` to use - as the argument; if not present, the instance specified by `instance` will be passed - directly. +* `export` : `string` (optional) - the name of the exported instance on + `instance` to use as the argument. + + If not present, the instance specified by `instance` will be passed directly. Arguments may be specified as a `string` rather than a `map`, in which case it is treated as having an `instance` field with the value of the string. @@ -97,7 +106,7 @@ A slightly complex example of configuring instantiations: ```yaml instantiations: - $component: + $input: arguments: a: b b: @@ -109,15 +118,36 @@ instantiations: dependency: f ``` -In the above example, the `$component` instantiation (i.e. the root instantiation) has explicitly -specified that the argument named `a` is to be provided instance `b`. +In the above example, the `$input` instantiation (i.e. the root instantiation) +has explicitly specified that the argument named `a` is to be provided instance +`b`. + +It also defines an instantiation named `b` which is to be passed an instance +export named `e` from instance `d` (of a dependency named `f`) for the +instantiation argument named `c`. + +By default, `wasm-compose` will minimize the number of instantiations and +dependencies which share an import of the same name will share the same +instance of that dependency, provided that the instance is compatible with +every import. + +Configuring instantiations for `wasm-compose` allows for a custom instantiation +graph to be constructed in the composed component. + +## Definition components + +A _definition_ component is a component that exports instances that are +automatically used to satisfy any instance import in the composition with a +matching name. -It also defines an instantiation named `b` which is to be passed an instance export named `e` -from instance `d` (of a dependency named `f`) for the instantiation argument named `c`. +A typical use case for definition components is to provide a _virtualized_ +implementation of common interfaces. -By default, `wasm-compose` will minimize the number of instantiations and dependencies which share -an import of the same name will share the same instance of that dependency, provided that the -instance is compatible with every import. +For example, a definition component might export a virtualized implementation +of the `wasi:filesystem/types` interface that serves files via inline data +segments instead of by accessing the host filesystem. -Configuring instantiations for `wasm-compose` allows for a custom instantiation graph to be -constructed in the composed component. +By providing such a definition component to the composition, any use of the +WASI filesystem interface by the root component (or its dependencies) will +automatically use the implementation provided by the definition component +instead of importing it from the host environment. diff --git a/crates/wasm-compose/Cargo.toml b/crates/wasm-compose/Cargo.toml index 045b11252b..fa90bae9de 100644 --- a/crates/wasm-compose/Cargo.toml +++ b/crates/wasm-compose/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "wasm-compose" -version = "0.1.1" -edition = "2021" +version = "0.4.9" +edition.workspace = true authors = ["Peter Huene "] license = "Apache-2.0 WITH LLVM-exception" readme = "README.md" @@ -11,22 +11,21 @@ documentation = "https://docs.rs/wasm-compose" description = "A library for composing WebAssembly components." [dependencies] -wat = { version = "1.0.48", path = "../wat" } -wasm-encoder = { version = "0.16.0", path = "../wasm-encoder" } -wasmparser = { version = "0.90.0", path = "../wasmparser" } -indexmap = { version = "1.9.1", features = ["serde"] } -anyhow = "1.0.58" -serde = { version = "1.0.137", features = ["derive"] } +wat = { workspace = true } +wasm-encoder = { workspace = true } +wasmparser = { workspace = true } +indexmap = { workspace = true, features = ["serde"] } +anyhow = { workspace = true } +serde = { workspace = true } +serde_derive = { workspace = true } petgraph = "0.6.2" -log = "0.4.17" -serde_yaml = "0.8.26" -clap = { version = "3.2.7", features = ["derive"], optional = true } - -[features] -default = [] -cli = ["clap"] +log = { workspace = true } +serde_yaml = "0.9.22" +smallvec = "1.10.0" +heck = "0.4.0" [dev-dependencies] glob = "0.3.0" pretty_assertions = "1.2.1" -wasmprinter = { version = "0.2.39", path = "../wasmprinter" } +wasmprinter = { workspace = true } +wit-component = { workspace = true } diff --git a/crates/wasm-compose/README.md b/crates/wasm-compose/README.md index 6ab8bc7b1a..644b19329a 100644 --- a/crates/wasm-compose/README.md +++ b/crates/wasm-compose/README.md @@ -75,7 +75,7 @@ of composing WebAssembly components together. ## License This project is licensed under the Apache 2.0 license with the LLVM exception. -See [LICENSE](LICENSE) for more details. +See [LICENSE](../../LICENSE) for more details. ### Contribution diff --git a/crates/wasm-compose/example/README.md b/crates/wasm-compose/example/README.md index de5a79be49..7d378c764e 100644 --- a/crates/wasm-compose/example/README.md +++ b/crates/wasm-compose/example/README.md @@ -5,63 +5,59 @@ to compose a component from other components. ## Directory layout -There are four subdirectories in this example: +There are three subdirectories in this example: -* `backend` - a simple HTTP backend component that responds with the original - request body. -* `middleware` - a middleware component that gzip compresses response bodies. -* `service` - a service component that is configured with a backend component - to send requests to. -* `server` - a custom HTTP server that instantiates a composed `service` - component for each HTTP request. +* `service` - a service component that responds with the original request body. +* `middleware` - a middleware component that compresses response bodies. +* `server` - a custom HTTP server that instantiates a service component for + each HTTP request. ## Overview -The server will listen for `POST` requests at `http://localhost:8080`. +The server will listen for `POST` requests at `http://localhost:8080`. -When it receives a request, the server will instantiate the `service` component +When it receives a request, the server will instantiate a service component and forward it the request. -Each component implements a `service` interface defined in `service.wit` as: +Each service implements a `handler` interface defined in `service.wit` as: ```wit -record request { - headers: list, list>>, - body: list, +interface handler { + record request { + headers: list, list>>, + body: list, + } + + record response { + headers: list, list>>, + body: list + } + + enum error { + bad-request, + } + + execute: func(req: request) -> result } - -record response { - headers: list, list>>, - body: list -} - -enum error { - bad-request, -} - -execute: func(req: request) -> expected ``` -A service will be passed a `request` containing only the headers and body and -respond with a `response` containing only the headers and body. +A service handler will be passed a `request` containing only the headers and +body and respond with a `response` containing only the headers and body. -Note that this is an overly-simplistic (and inefficient) interface for describing -HTTP request processing. +Note that this is an overly-simplistic (and inefficient) interface for +describing HTTP request processing. ### Execution flow -The example will compose a `service` component that initially executes like +The example implements a `service` component that initially executes like this: ```mermaid sequenceDiagram participant server (native) participant service (wasm) - participant backend (wasm) server (native)->>service (wasm): execute() - service (wasm)->>backend (wasm): execute() - Note right of backend (wasm): echo request body - backend (wasm)->>service (wasm): uncompressed response + Note right of service (wasm): echo request body service (wasm)->>server (native): uncompressed response ``` @@ -72,16 +68,13 @@ altering the execution flow to this: ```mermaid sequenceDiagram participant server (native) - participant service (wasm) participant middleware (wasm) - participant backend (wasm) - server (native)->>service (wasm): execute() - service (wasm)->>middleware (wasm): execute() - middleware (wasm)->>backend (wasm): execute() - Note right of backend (wasm): echo request body - backend (wasm)->>middleware (wasm): uncompressed response - middleware (wasm)->>service (wasm): compressed response - service (wasm)->>server (native): compressed response + participant service (wasm) + server (native)->>middleware (wasm): execute() + middleware (wasm)->>service (wasm): execute() + Note right of service (wasm): echo request body + service (wasm)->>middleware (wasm): uncompressed response + middleware (wasm)->>server (native): compressed response ``` All this without having to rebuild any of the original components! @@ -93,15 +86,19 @@ The components in this example will be built with [`cargo component`](https://gi Follow the [installation instructions](https://github.com/bytecodealliance/cargo-component#installation) to install `cargo component` locally. +> *Note*: `cargo component` is under active development. This example has been tested +> with git sha [`df2eb26`](https://github.com/bytecodealliance/cargo-component/commit/df2eb2633fa6d0c234372fb0471b8e9867d135c6) +> and may not work with other versions of `cargo component`. + Additionally, it is assumed that `wasm-tools` has been installed from the root of this repository. ## Building the components -To build the `backend` component, use `cargo component build`: +To build the `service` component, use `cargo component build`: ```sh -cd backend +cd service cargo component build --release ``` @@ -112,41 +109,16 @@ cd middleware cargo component build --release ``` -Finally, to build the `service` component, use `cargo component build`: - -```sh -cd service -cargo component build --release -``` - -## Composing the `service` component - -Initially, we will compose a service component that directly sends requests -to the backend service. - -The `server/config.yml` configuration file instructs `wasm-compose` to -search for dependencies from the expected output paths of the components we -built previously. - -Based on this, `wasm-compose` will automatically satisfy the `backend` -dependency of the `service` component with the `backend` component. - -To compose the `service` component, run `wasm-tools compose`: - -```sh -cd server -wasm-tools compose -c config.yml -o service.wasm ../service/target/wasm32-unknown-unknown/release/svc.wasm -``` - -There should now be a `service.wasm` in the `server` directory. - ## Running the server +Initially, we will run the server with the `service` component that responds +with an uncompressed response body. + The server can be run with `cargo run`: ```sh cd server -cargo run --release -- service.wasm +cargo run --release -- ../service/target/wasm32-wasi/release/svc.wasm ``` This will start a HTTP server that listens at `http://localhost:8080`. @@ -172,13 +144,13 @@ This should output something like this: > Accept: */* > Content-Type: text/plain > Content-Length: 13 -> +> * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < content-length: 35 < content-type: text/plain < date: Fri, 05 Aug 2022 01:39:43 GMT -< +< * Connection #0 to host localhost left intact The request body was: Hello, world! ``` @@ -186,34 +158,20 @@ The request body was: Hello, world! Note that the response body matches the request body, but it was not compressed. -## Changing the composition - -If we want to instead compress the response bodies for the service, we can easily -change the composition to send requests through the `middleware` component -without rebuilding any of the previously built components. - -To change how the `service` component is composed, edit `server/config.yml` -and uncomment the specified lines: - -```yml -instantiations: - $component: - arguments: - backend: middleware -``` +## Composing with a middleware -This provides an explicit dependency of `middleware` for the `backend` argument -of the composed component. +If we want to instead compress the response bodies for the service, we can +easily compose a new component that sends requests through the `middleware` +component without rebuilding any of the previously built components. -`wasm-compose` will therefore use the `middleware` component to satisfy the -dependency; the `backend` dependency of the `middleware` component will automatically -be satisfied by the `backend` component. +The `server/config.yml` file contains the configuration needed to compose a new +component from the `service` and `middleware` components. -And run `wasm-compose` again: +Run `wasm-compose` to compose the new component: ```sh cd server -wasm-tools compose -c config.yml -o service.wasm ../service/target/wasm32-unknown-unknown/release/svc.wasm +wasm-tools compose -c config.yml -o service.wasm ../middleware/target/wasm32-wasi/release/middleware.wasm ``` This results in a new `service.wasm` in the `server` directory where the @@ -223,7 +181,7 @@ This results in a new `service.wasm` in the `server` directory where the If you haven't already, stop the currently running server by pressing `ctrl-c`. -Start the server again with `cargo run`: +Start the server again with `cargo run` with the newly composed component: ```sh cd server @@ -255,14 +213,14 @@ This should output something like this: > Accept-Encoding: deflate, gzip > Content-Type: text/plain > Content-Length: 13 -> +> * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < content-encoding: gzip < content-length: 58 < content-type: text/plain < date: Fri, 05 Aug 2022 01:47:59 GMT -< +< * Connection #0 to host localhost left intact The request body was: Hello, world! ``` diff --git a/crates/wasm-compose/example/backend/.vscode/settings.json b/crates/wasm-compose/example/backend/.vscode/settings.json deleted file mode 100644 index 09b1909af8..0000000000 --- a/crates/wasm-compose/example/backend/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "rust-analyzer.server.extraEnv": { "CARGO": "cargo-component" } -} diff --git a/crates/wasm-compose/example/backend/Cargo.toml b/crates/wasm-compose/example/backend/Cargo.toml deleted file mode 100644 index be65e50d28..0000000000 --- a/crates/wasm-compose/example/backend/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "backend" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", default_features = false } - -[lib] -crate-type = ["cdylib"] - -[package.metadata.component] -direct-interface-export = "service" - -[package.metadata.component.exports] -service = "../service.wit" - -[workspace] diff --git a/crates/wasm-compose/example/backend/src/lib.rs b/crates/wasm-compose/example/backend/src/lib.rs deleted file mode 100644 index 76c33575dd..0000000000 --- a/crates/wasm-compose/example/backend/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -use service::{Error, Request, Response, Service}; -use std::str; - -struct Component; - -impl Service for Component { - fn execute(req: Request) -> Result { - // The content should be plain text - let content_type = req - .headers - .iter() - .find(|(k, _)| k == b"content-type") - .map(|(_, v)| v) - .ok_or_else(|| Error::BadRequest)?; - if content_type != b"text/plain" { - return Err(Error::BadRequest); - } - - // We assume the body is UTF-8 encoded - let body = str::from_utf8(&req.body).map_err(|_| Error::BadRequest)?; - - // Echo the body back in the response - Ok(Response { - headers: vec![(b"content-type".to_vec(), b"text/plain".to_vec())], - body: format!("The request body was: {body}").into_bytes(), - }) - } -} - -service::export!(Component); diff --git a/crates/wasm-compose/example/middleware/Cargo-component.lock b/crates/wasm-compose/example/middleware/Cargo-component.lock new file mode 100644 index 0000000000..00bc239dbb --- /dev/null +++ b/crates/wasm-compose/example/middleware/Cargo-component.lock @@ -0,0 +1,3 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 diff --git a/crates/wasm-compose/example/middleware/Cargo.toml b/crates/wasm-compose/example/middleware/Cargo.toml index 3cc44fc35c..91d426e269 100644 --- a/crates/wasm-compose/example/middleware/Cargo.toml +++ b/crates/wasm-compose/example/middleware/Cargo.toml @@ -6,18 +6,12 @@ publish = false [dependencies] flate2 = "1.0.24" -wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", default_features = false } +cargo-component-bindings = { git = "https://github.com/bytecodealliance/cargo-component" } [lib] crate-type = ["cdylib"] [package.metadata.component] -direct-interface-export = "service" - -[package.metadata.component.imports] -backend = "../service.wit" - -[package.metadata.component.exports] -service = "../service.wit" +target = { path = "../service.wit", world = "middleware" } [workspace] diff --git a/crates/wasm-compose/example/middleware/src/lib.rs b/crates/wasm-compose/example/middleware/src/lib.rs index 50b3e41630..d1870c51c8 100644 --- a/crates/wasm-compose/example/middleware/src/lib.rs +++ b/crates/wasm-compose/example/middleware/src/lib.rs @@ -1,28 +1,27 @@ +cargo_component_bindings::generate!(); + +use bindings::{ + example::service::handler as downstream, + exports::example::service::handler::{Error, Handler, Request, Response}, +}; use flate2::{write::GzEncoder, Compression}; -use service::{Error, Request, Response, Service}; use std::io::Write; struct Component; -impl Service for Component { +impl Handler for Component { fn execute(req: Request) -> Result { - let headers: Vec<_> = req - .headers - .iter() - .map(|(k, v)| (k.as_slice(), v.as_slice())) - .collect(); - - // Send the request to the backend - let mut response = backend::execute(backend::Request { - headers: &headers, - body: &req.body, + // Send the request to the downstream service + let mut response = downstream::execute(&downstream::Request { + headers: req.headers, + body: req.body, }) .map(|r| Response { headers: r.headers, body: r.body, }) .map_err(|e| match e { - backend::Error::BadRequest => Error::BadRequest, + downstream::Error::BadRequest => Error::BadRequest, })?; // If the response is already encoded, leave it alone @@ -49,5 +48,3 @@ impl Service for Component { Ok(response) } } - -service::export!(Component); diff --git a/crates/wasm-compose/example/server/Cargo.toml b/crates/wasm-compose/example/server/Cargo.toml index 679532b04b..2cce17ddce 100644 --- a/crates/wasm-compose/example/server/Cargo.toml +++ b/crates/wasm-compose/example/server/Cargo.toml @@ -6,9 +6,12 @@ publish = false [dependencies] async-std = { version = "1.12.0", features = ["attributes"] } -clap = { version = "3.2.16", features = ["derive"] } -driftwood = "0.0.6" +clap = { version = "4.3.19", features = ["derive"] } +driftwood = "0.0.7" tide = "0.16.0" -wasmtime = { version = "0.41.0", features = ["component-model"], git = "https://github.com/bytecodealliance/wasmtime", rev = "1ce9e8aa5f32a8dad42f02c8fd84514a641c4a5c" } +wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "7b9189b", features = ["component-model"] } +wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime", rev = "7b9189b" } +wasi-cap-std-sync = { git = "https://github.com/bytecodealliance/wasmtime", rev = "7b9189b" } +anyhow = "1.0.72" [workspace] diff --git a/crates/wasm-compose/example/server/config.yml b/crates/wasm-compose/example/server/config.yml index c0142d16b6..36715256b3 100644 --- a/crates/wasm-compose/example/server/config.yml +++ b/crates/wasm-compose/example/server/config.yml @@ -1,9 +1,7 @@ search-paths: - - ../backend/target/wasm32-unknown-unknown/release - - ../middleware/target/wasm32-unknown-unknown/release + - ../service/target/wasm32-wasi/release -# Remove the comments below to compose with the middleware component -# instantiations: -# $component: -# arguments: -# backend: middleware +instantiations: + $input: + arguments: + example:service/handler@0.1.0: svc diff --git a/crates/wasm-compose/example/server/src/main.rs b/crates/wasm-compose/example/server/src/main.rs index ae632d6283..7b3010cb89 100644 --- a/crates/wasm-compose/example/server/src/main.rs +++ b/crates/wasm-compose/example/server/src/main.rs @@ -8,7 +8,17 @@ use tide::{ utils::After, Request, Response, StatusCode, }; + use wasmtime::{component::*, Config, Engine, Store}; +use wasmtime_wasi::preview2::{command, Table, WasiCtx, WasiCtxBuilder, WasiView}; + +use exports::example::service::*; + +wasmtime::component::bindgen!({ + path: "../service.wit", + world: "service", + async: true +}); /// Represents state stored in the tide application context. /// @@ -25,6 +35,7 @@ impl State { // Enable component model support in Wasmtime let mut config = Config::default(); config.wasm_component_model(true); + config.async_support(true); // Load the component from the given path let engine = Engine::new(&config)?; @@ -33,42 +44,10 @@ impl State { } } -#[derive(ComponentType, Lower)] -#[component(record)] -struct ServiceRequest { - headers: Vec<(Vec, Vec)>, - body: Vec, -} - -impl ServiceRequest { - async fn new(mut req: Request) -> tide::Result { - // Convert the tide request to a service request. - let headers = req - .iter() - .map(|(n, v)| { - ( - n.as_str().as_bytes().to_vec(), - v.as_str().as_bytes().to_vec(), - ) - }) - .collect(); - let body = req.take_body().into_bytes().await?; - - Ok(Self { headers, body }) - } -} - -#[derive(ComponentType, Lift)] -#[component(record)] -struct ServiceResponse { - headers: Vec<(Vec, Vec)>, - body: Vec, -} - -impl TryFrom for tide::Response { +impl TryFrom for tide::Response { type Error = tide::Error; - fn try_from(r: ServiceResponse) -> Result { + fn try_from(r: handler::Response) -> Result { // Convert the service response to a tide response let mut builder = tide::Response::builder(StatusCode::Ok); for (name, value) in r.headers { @@ -82,25 +61,16 @@ impl TryFrom for tide::Response { } } -#[derive(ComponentType, Lift)] -#[component(enum)] -enum ServiceError { - #[component(name = "bad-request")] - BadRequest, -} - -impl From for tide::Error { - fn from(e: ServiceError) -> Self { - match e { - ServiceError::BadRequest => { +impl handler::Error { + fn into_tide(self) -> tide::Error { + match self { + Self::BadRequest => { tide::Error::from_str(StatusCode::BadRequest, "bad service request") } } } } -type ServiceResult = Result; - /// WebAssembly component server. /// /// A demonstration server that executes WebAssembly components. @@ -144,23 +114,65 @@ impl ServerApp { app.listen(address).await.map_err(Into::into) } - async fn process_request(req: Request) -> tide::Result { - let state = req.state(); + async fn process_request(mut req: Request) -> tide::Result { + let body = req.body_bytes().await?; + let headers = req + .iter() + .map(|(n, v)| { + ( + n.as_str().as_bytes().to_vec(), + v.as_str().as_bytes().to_vec(), + ) + }) + .collect::>(); // Create a new store for the request - let mut store = Store::new(&state.engine, ()); - let linker: Linker<()> = Linker::new(&state.engine); - - // Instantiate the service component and get its `execute` export - let instance = linker.instantiate(&mut store, &state.component)?; - let execute = instance - .get_typed_func::<(ServiceRequest,), ServiceResult, _>(&mut store, "execute")?; - - // Call the `execute` export with the request and translate the response - execute - .call(&mut store, (ServiceRequest::new(req).await?,))? - .map_err(Into::into) - .and_then(TryInto::try_into) + let state = req.state(); + let mut linker = Linker::new(&state.engine); + command::add_to_linker(&mut linker)?; + + let wasi_view = ServerWasiView::new()?; + let mut store = Store::new(&state.engine, wasi_view); + let (service, _) = + Service::instantiate_async(&mut store, &state.component, &linker).await?; + service + .example_service_handler() + .call_execute(&mut store, &handler::Request { headers, body }) + .await? + .map(TryInto::try_into) + .map_err(handler::Error::into_tide)? + } +} + +struct ServerWasiView { + table: Table, + ctx: WasiCtx, +} + +impl ServerWasiView { + fn new() -> Result { + let mut table = Table::new(); + let ctx = WasiCtxBuilder::new().inherit_stdio().build(&mut table)?; + + Ok(Self { table, ctx }) + } +} + +impl WasiView for ServerWasiView { + fn table(&self) -> &Table { + &self.table + } + + fn table_mut(&mut self) -> &mut Table { + &mut self.table + } + + fn ctx(&self) -> &WasiCtx { + &self.ctx + } + + fn ctx_mut(&mut self) -> &mut WasiCtx { + &mut self.ctx } } diff --git a/crates/wasm-compose/example/service.wit b/crates/wasm-compose/example/service.wit index eba6406520..d5888d456f 100644 --- a/crates/wasm-compose/example/service.wit +++ b/crates/wasm-compose/example/service.wit @@ -1,15 +1,28 @@ -record request { - headers: list, list>>, - body: list, -} +package example:service@0.1.0 + +interface handler { + record request { + headers: list, list>>, + body: list, + } + + record response { + headers: list, list>>, + body: list + } -record response { - headers: list, list>>, - body: list + enum error { + bad-request, + } + + execute: func(req: request) -> result } -enum error { - bad-request, +world service { + export handler } -execute: func(req: request) -> expected +world middleware { + import handler + export handler +} diff --git a/crates/wasm-compose/example/service/.gitignore b/crates/wasm-compose/example/service/.gitignore deleted file mode 100644 index af4ffc84cf..0000000000 --- a/crates/wasm-compose/example/service/.gitignore +++ /dev/null @@ -1 +0,0 @@ -composed.wasm diff --git a/crates/wasm-compose/example/service/Cargo-component.lock b/crates/wasm-compose/example/service/Cargo-component.lock new file mode 100644 index 0000000000..00bc239dbb --- /dev/null +++ b/crates/wasm-compose/example/service/Cargo-component.lock @@ -0,0 +1,3 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 diff --git a/crates/wasm-compose/example/service/Cargo.toml b/crates/wasm-compose/example/service/Cargo.toml index 75d9bc0ed1..ba9e6c0eca 100644 --- a/crates/wasm-compose/example/service/Cargo.toml +++ b/crates/wasm-compose/example/service/Cargo.toml @@ -5,18 +5,12 @@ edition = "2021" publish = false [dependencies] -wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", default_features = false } +cargo-component-bindings = { git = "https://github.com/bytecodealliance/cargo-component" } [lib] crate-type = ["cdylib"] [package.metadata.component] -direct-interface-export = "service" - -[package.metadata.component.imports] -backend = "../service.wit" - -[package.metadata.component.exports] -service = "../service.wit" +target = { path = "../service.wit", world = "service" } [workspace] diff --git a/crates/wasm-compose/example/service/src/lib.rs b/crates/wasm-compose/example/service/src/lib.rs index 51fa032e28..03d43e314c 100644 --- a/crates/wasm-compose/example/service/src/lib.rs +++ b/crates/wasm-compose/example/service/src/lib.rs @@ -1,32 +1,31 @@ -use service::{Error, Request, Response, Service}; +cargo_component_bindings::generate!(); + +use bindings::exports::example::service::handler::{Error, Handler, Request, Response}; +use std::str; struct Component; -impl Service for Component { +impl Handler for Component { fn execute(req: Request) -> Result { - // Right now, generated types aren't shared for bindings, so we - // have to manually convert between the different types; eventually - // this will not be necessary and we can call `backend::execute` - // with the request passed to us. - let headers: Vec<_> = req + // The content should be plain text + let content_type = req .headers .iter() - .map(|(k, v)| (k.as_slice(), v.as_slice())) - .collect(); + .find(|(k, _)| k == b"content-type") + .map(|(_, v)| v) + .ok_or(Error::BadRequest)?; - // Send the request to the backend and convert the response - backend::execute(backend::Request { - headers: &headers, - body: req.body.as_slice(), - }) - .map(|r| Response { - headers: r.headers, - body: r.body, - }) - .map_err(|e| match e { - backend::Error::BadRequest => Error::BadRequest, + if content_type != b"text/plain" { + return Err(Error::BadRequest); + } + + // We assume the body is UTF-8 encoded + let body = str::from_utf8(&req.body).map_err(|_| Error::BadRequest)?; + + // Echo the body back in the response + Ok(Response { + headers: vec![(b"content-type".to_vec(), b"text/plain".to_vec())], + body: format!("The request body was: {body}").into_bytes(), }) } } - -service::export!(Component); diff --git a/crates/wasm-compose/src/cli.rs b/crates/wasm-compose/src/cli.rs deleted file mode 100644 index 359031a2f6..0000000000 --- a/crates/wasm-compose/src/cli.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Module for CLI parsing. - -use crate::{composer::ComponentComposer, config::Config}; -use anyhow::{Context, Result}; -use clap::Parser; -use std::path::{Path, PathBuf}; -use wasmparser::{Validator, WasmFeatures}; - -/// WebAssembly component composer. -/// -/// A tool for composing WebAssembly components together. -#[derive(Debug, Parser)] -#[clap(name = "component-encoder", version = env!("CARGO_PKG_VERSION"))] -pub struct WasmComposeCommand { - /// The path of the output composed WebAssembly component. - #[clap(long, short = 'o', value_name = "OUTPUT")] - pub output: PathBuf, - - /// The path to the configuration file to use. - #[clap(long, short = 'c', value_name = "CONFIG")] - pub config: Option, - - /// A path to search for imports. - #[clap(long = "search-path", short = 'p', value_name = "PATH")] - pub paths: Vec, - - /// Skip validation of the composed output component. - #[clap(long)] - pub skip_validation: bool, - - /// Do not allow instance imports in the composed output component. - #[clap(long = "no-imports")] - pub disallow_imports: bool, - - /// The path to the root component to compose. - #[clap(value_name = "COMPONENT")] - pub component: PathBuf, -} - -impl WasmComposeCommand { - /// Executes the application. - pub fn execute(self) -> Result<()> { - let config = self.create_config()?; - log::debug!("configuration:\n{:#?}", config); - - let bytes = ComponentComposer::new(&self.component, &config).compose()?; - - std::fs::write(&self.output, &bytes).with_context(|| { - format!( - "failed to write composed component `{output}`", - output = self.output.display() - ) - })?; - - if config.skip_validation { - log::debug!("output validation was skipped"); - } else { - Validator::new_with_features(WasmFeatures { - component_model: true, - ..Default::default() - }) - .validate_all(&bytes) - .with_context(|| { - format!( - "failed to validate output component `{output}`", - output = self.output.display() - ) - })?; - - log::debug!("output component validated successfully"); - } - - println!( - "composed component `{output}`", - output = self.output.display() - ); - - Ok(()) - } - - fn create_config(&self) -> Result { - let mut config = if let Some(config) = &self.config { - Config::from_file(config)? - } else { - // Pretend a default configuration file is sitting next to the component - Config { - dir: self - .component - .parent() - .map(Path::to_path_buf) - .unwrap_or_default(), - ..Default::default() - } - }; - - config.search_paths.extend(self.paths.iter().cloned()); - config.skip_validation |= self.skip_validation; - config.disallow_imports |= self.disallow_imports; - Ok(config) - } -} diff --git a/crates/wasm-compose/src/composer.rs b/crates/wasm-compose/src/composer.rs index 8108e05fcd..b54d57873c 100644 --- a/crates/wasm-compose/src/composer.rs +++ b/crates/wasm-compose/src/composer.rs @@ -2,525 +2,137 @@ use crate::{ config::Config, - encoding::{InstantiationGraphEncoder, TypeEncoder}, + encoding::CompositionGraphEncoder, + graph::{ + Component, ComponentId, CompositionGraph, EncodeOptions, ExportIndex, ImportIndex, + InstanceId, + }, }; use anyhow::{anyhow, bail, Context, Result}; -use indexmap::{IndexMap, IndexSet}; -use petgraph::{algo::toposort, dot::Dot, graph::NodeIndex, visit::EdgeRef, EdgeDirection, Graph}; -use std::{ - collections::VecDeque, - path::{Path, PathBuf}, -}; -use wasm_encoder::ComponentExportKind; +use indexmap::IndexMap; +use std::{collections::VecDeque, ffi::OsStr, path::Path}; use wasmparser::{ - types::{ComponentEntityType, ComponentInstanceType, Types, TypesRef}, - Chunk, ComponentExport, ComponentExternalKind, ComponentImport, ComponentTypeRef, Encoding, - Parser, Payload, ValidPayload, Validator, WasmFeatures, + types::{ComponentEntityType, TypeId, TypesRef}, + ComponentExternalKind, ComponentTypeRef, }; /// The root component name used in configuration. -pub const ROOT_COMPONENT_NAME: &str = "$component"; - -pub(crate) struct Component { - /// The index of the component in the instantiation graph. - index: ComponentIndex, - /// The path to the component file. - path: PathBuf, - /// The raw bytes of the component. - bytes: Vec, - /// The type information of the component. - types: Types, - /// The name to use to import this component in the composed component. - /// If this is `None`, the component will be defined in the composed component. - import_name: Option, - /// The import map of the component. - imports: IndexMap, - /// The export map of the component. - exports: IndexMap, -} - -impl Component { - fn new( - index: ComponentIndex, - path: impl Into, - import_name: Option, - ) -> Result { - let path = path.into(); - log::info!("parsing WebAssembly component `{}`", path.display()); - - let bytes = wat::parse_file(&path).with_context(|| { - format!("failed to parse component `{path}`", path = path.display()) - })?; - - let mut parser = Parser::new(0); - let mut parsers = Vec::new(); - let mut validator = Validator::new_with_features(WasmFeatures { - component_model: true, - ..Default::default() - }); - let mut imports = IndexMap::new(); - let mut exports = IndexMap::new(); - - let mut cur = bytes.as_slice(); - loop { - match parser.parse(cur, true).with_context(|| { - format!("failed to parse component `{path}`", path = path.display()) - })? { - Chunk::Parsed { payload, consumed } => { - cur = &cur[consumed..]; - - match validator.payload(&payload).with_context(|| { - format!( - "failed to validate WebAssembly component `{}`", - path.display() - ) - })? { - ValidPayload::Ok => { - // Don't parse any sub-components or sub-modules - if !parsers.is_empty() { - continue; - } - - match payload { - Payload::Version { encoding, .. } => { - if encoding != Encoding::Component { - bail!( - "file `{path}` is not a WebAssembly component", - path = path.display() - ); - } - } - Payload::ComponentImportSection(s) => { - for import in s { - let import = import?; - imports.insert(import.name.to_string(), import.ty); - } - } - Payload::ComponentExportSection(s) => { - for export in s { - let export = export?; - exports.insert( - export.name.to_string(), - (export.kind, export.index), - ); - } - } - _ => {} - } - } - ValidPayload::Func(_, _) => {} - ValidPayload::Parser(next) => { - parsers.push(parser); - parser = next; - } - ValidPayload::End(types) => match parsers.pop() { - Some(parent) => parser = parent, - None => { - let component = Component { - index, - path, - bytes, - types, - import_name, - imports, - exports, - }; - log::debug!( - "WebAssembly component `{path}` parsed:\n{component:#?}", - path = component.path.display() - ); - return Ok(component); - } - }, - } - } - Chunk::NeedMoreData(_) => unreachable!(), - } - } - } - - pub(crate) fn index(&self) -> ComponentIndex { - self.index - } - - pub(crate) fn path(&self) -> &Path { - &self.path - } - - pub(crate) fn bytes(&self) -> &[u8] { - &self.bytes - } - - pub(crate) fn types(&self) -> TypesRef { - self.types.as_ref() - } - - pub(crate) fn import_name(&self) -> Option<&str> { - self.import_name.as_deref() - } - - pub(crate) fn ty(&self) -> wasm_encoder::ComponentType { - let encoder = TypeEncoder::new(self.types.as_ref()); - - encoder.component( - self.imports.iter().map(|(name, ty)| { - ( - name.as_str(), - self.types - .component_entity_type_from_import(&ComponentImport { - name: name.as_str(), - ty: *ty, - }) - .unwrap(), - ) - }), - self.exports.iter().map(|(name, (kind, index))| { - ( - name.as_str(), - self.types - .component_entity_type_from_export(&ComponentExport { - name: name.as_str(), - kind: *kind, - index: *index, - }) - .unwrap(), - ) - }), - ) - } +pub const ROOT_COMPONENT_NAME: &str = "$input"; - /// Gets an export from the component for the given export index. - pub(crate) fn export(&self, index: ExportIndex) -> (&str, ComponentExternalKind, u32) { - let (name, (kind, index)) = self - .exports - .get_index(index.0) - .expect("invalid export index"); - (name.as_str(), *kind, *index) - } - - /// Gets an iterator over the component's exports. - pub(crate) fn exports(&self) -> impl Iterator { - self.exports - .iter() - .map(|(name, (kind, index))| (name.as_str(), *kind, *index)) - } - - /// Gets an exported instance index and type with the given export name. - fn export_instance(&self, name: &str) -> Option<(ExportIndex, &ComponentInstanceType)> { - self.exports - .get_full(name) - .and_then(|(i, _, (kind, index))| match kind { - ComponentExternalKind::Instance => Some(( - ExportIndex(i), - self.types.component_instance_at(*index).unwrap(), - )), - _ => None, - }) - } - - /// Finds a compatible instance export on the component for the given instance type. - fn find_compatible_export( - &self, - ty: &ComponentInstanceType, - types: TypesRef, - ) -> Option { - self.exports - .iter() - .position(|(_, (kind, index))| { - if *kind != ComponentExternalKind::Instance { - return false; - } - ComponentInstanceType::is_subtype_of( - self.types.component_instance_at(*index).unwrap(), - self.types.as_ref(), - ty, - types, - ) - }) - .map(ExportIndex) - } - - /// Checks to see if an instance of this component would be a - /// subtype of the given instance type. - fn is_subtype_of(&self, ty: &ComponentInstanceType, types: TypesRef) -> bool { - let exports = ty.exports(types); - - // This checks if this import's instance type is a subtype of the given instance type. - for (k, b) in exports { - match self.exports.get(k.as_str()) { - Some((ak, ai)) => { - let a = self - .types - .component_entity_type_from_export(&ComponentExport { - name: k.as_str(), - kind: *ak, - index: *ai, - }) - .unwrap(); - if !ComponentEntityType::is_subtype_of(&a, self.types.as_ref(), b, types) { - return false; - } - } - None => return false, - } - } - - true - } -} - -impl std::fmt::Debug for Component { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("Component") - .field("path", &self.path) - .field("imports", &self.imports) - .field("exports", &self.exports) - .finish_non_exhaustive() - } -} - -/// Represents an index into an instantiation graph's `components` collection. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub(crate) struct ComponentIndex(usize); - -/// An instance index into an instantiation graph. -pub(crate) type InstanceIndex = NodeIndex; - -/// Represents an index into a component's imports collection. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub(crate) struct ImportIndex(usize); - -/// Represents an index into a component's exports collection. +/// A reference to an instance import on a component. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub(crate) struct ExportIndex(usize); - -/// A reference to an import on a component -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub(crate) struct ImportRef { - /// The index of the component with the import. - pub(crate) component: ComponentIndex, +pub(crate) struct InstanceImportRef { + /// The id of the component with the instance import. + pub(crate) component: ComponentId, /// The index of the import on the component. pub(crate) import: ImportIndex, } -/// An instance (node) in the instantiation graph. -#[derive(Debug)] -enum Instance { - /// The instance will be imported in the composed component. - /// - /// The value is the set of components that will import the instance. - Import(IndexSet), - /// The instance will be from an instantiation in the composed component. - Instantiation { - /// The index of the component being instantiated. - component: ComponentIndex, +/// Represents the kind of dependency to process. +enum DependencyKind { + /// The dependency is on a configured instance. + Instance { + /// The name of the instance from the instantiation argument. + instance: String, + /// The name of the export on the instance to use as the instantiation argument. + export: Option, }, -} - -/// An instantiation argument (edge) in the instantiation graph. -#[derive(Debug, Copy, Clone)] -struct InstantiationArg { - /// The import index on the component being instantiated. - import: ImportIndex, - /// The export index of the instantiation argument. - /// - /// A value of `None` indicates that the instance is itself the argument to use. - export: Option, -} - -pub(crate) struct InstantiationGraph { - /// The parsed components in the graph. - components: IndexMap, - /// The actual instantiation graph. - /// - /// Each node is an instance and each edge is an argument to the instance. - instances: Graph, - /// Map from instantiation name to instance index. - names: IndexMap, - /// True if at least one dependency was found and instantiated. - /// - /// This is used to determine if no dependencies were found. - instantiated: bool, -} - -impl InstantiationGraph { - /// Gets the component index for the given instance. - /// - /// Returns `None` for imported instances. - pub(crate) fn component(&self, instance: InstanceIndex) -> Option<&Component> { - match &self.instances[instance] { - Instance::Import(_) => None, - Instance::Instantiation { component } => Some(&self.components[component.0]), - } - } - - /// Gets the set of import references for an imported instance. - /// - /// Returns `None` for instantiated instances. - pub(crate) fn import_refs(&self, instance: InstanceIndex) -> Option<&IndexSet> { - match &self.instances[instance] { - Instance::Import(imports) => Some(imports), - Instance::Instantiation { .. } => None, - } - } - - /// Gets the name of the given instance index. - pub(crate) fn instance_name(&self, instance: InstanceIndex) -> &str { - self.names - .get_index(instance.index()) - .map(|(n, _)| n.as_str()) - .expect("invalid instance index") - } - /// Gets the topological instantiation order based on the instantiation graph - pub(crate) fn instantiation_order(&self) -> Result> { - toposort(&self.instances, None).map_err(|e| { - anyhow!( - "instantiation `{name}` and its dependencies form a cycle in the instantiation graph", - name = self.names.get_index(e.node_id().index()).unwrap().0 - ) - }) - } - - /// Gets the instantiation arguments for the given instance index. - /// - /// The given function is used to resolve an encoded instance index - /// for a given graph instance index. - pub(crate) fn instantiation_args( - &self, - instance: InstanceIndex, - mut index_of_instance: T, - ) -> Vec<(&str, ComponentExportKind, u32)> - where - T: FnMut(InstanceIndex, Option) -> u32, - { - match self.instances[instance] { - Instance::Import { .. } => Vec::new(), - Instance::Instantiation { component } => { - let imports = &self.components[component.0].imports; - - self.instances - .edges_directed(instance, EdgeDirection::Incoming) - .map(|e| { - let arg = e.weight(); - ( - imports.get_index(arg.import.0).unwrap().0.as_str(), - ComponentExportKind::Instance, - index_of_instance(e.source(), arg.export), - ) - }) - .collect() - } - } - } - - /// Resolves an import reference to its originating component, import name, and instance type. - pub(crate) fn resolve_import( - &self, - r: ImportRef, - ) -> (&Component, &str, &ComponentInstanceType) { - let component = &self.components[r.component.0]; - let (name, ty) = component.imports.get_index(r.import.0).unwrap(); - match ty { - ComponentTypeRef::Instance(index) => ( - component, - name.as_str(), - component - .types - .type_at(*index, false) - .unwrap() - .as_component_instance_type() - .unwrap(), - ), - _ => unreachable!("should not have an import ref to a non-instance import"), - } - } + /// The dependency is on a definition component. + Definition { + /// The index into `definitions` for the dependency. + index: usize, + /// The export on the definition component to use as the instantiation argument. + export: ExportIndex, + }, } -/// An instance dependency to process in the instantiation graph. +/// An instance dependency to process in the composer. struct Dependency { - /// The index of the dependent instance. - dependent: InstanceIndex, - /// The import reference on the dependent instance. - import: ImportRef, - /// The name of the instance from the instantiation argument. - instance: String, - /// The name of the export on the instance to use as the instantiation argument. - export: Option, + /// The index into `instances` for the dependent instance. + dependent: usize, + /// The instance import reference on the dependent instance. + import: InstanceImportRef, + /// The kind of dependency. + kind: DependencyKind, } -struct InstantiationGraphBuilder<'a> { +/// A composition graph builder that wires up instances from components +/// resolved from the file system. +struct CompositionGraphBuilder<'a> { /// The associated composition configuration. config: &'a Config, /// The graph being built. - graph: InstantiationGraph, + graph: CompositionGraph<'a>, + /// A map from instance name to graph instance id. + instances: IndexMap, + /// The definition components in the graph. + definitions: Vec<(ComponentId, Option)>, } -impl<'a> InstantiationGraphBuilder<'a> { - fn new(component: &Path, config: &'a Config) -> Result { - // The root component is always first in the map - let mut components = IndexMap::new(); - components.insert( - ROOT_COMPONENT_NAME.to_string(), - Component::new(ComponentIndex(0), component, None)?, - ); +impl<'a> CompositionGraphBuilder<'a> { + fn new(root_path: &Path, config: &'a Config) -> Result { + let mut graph = CompositionGraph::new(); + graph.add_component(Component::from_file(ROOT_COMPONENT_NAME, root_path)?)?; + + let definitions = config + .definitions + .iter() + .map(|path| { + let name = path.file_stem().and_then(OsStr::to_str).with_context(|| { + format!( + "invalid definition component path `{path}`", + path = path.display() + ) + })?; + + let component = Component::from_file(name, config.dir.join(path))?; + + Ok((graph.add_component(component)?, None)) + }) + .collect::>()?; Ok(Self { config, - graph: InstantiationGraph { - components, - instances: Default::default(), - names: Default::default(), - instantiated: false, - }, + graph, + instances: Default::default(), + definitions, }) } /// Adds a component of the given name to the graph. /// - /// If a component with the given name already exists, its index is returned. - fn add_component(&mut self, name: &str) -> Result> { - if let Some(index) = self.graph.components.get_index_of(name) { - return Ok(Some(ComponentIndex(index))); + /// If a component with the given name already exists, its id is returned. + /// Returns `Ok(None)` if a matching component cannot be found. + fn add_component(&mut self, name: &str) -> Result> { + if let Some((id, _)) = self.graph.get_component_by_name(name) { + return Ok(Some(id)); } - match self.find_component(ComponentIndex(self.graph.components.len()), name)? { - Some(component) => { - let index = component.index; - assert_eq!(index.0, self.graph.components.len()); - self.graph.components.insert(name.to_string(), component); - log::debug!( - "adding component `{name}` (component index {index})", - index = index.0 - ); - Ok(Some(index)) - } + match self.find_component(name)? { + Some(component) => Ok(Some(self.graph.add_component(component)?)), None => Ok(None), } } /// Finds the component with the given name on disk. - /// - /// The given index is the index at which the component would be - /// inserted into the graph. - fn find_component(&self, index: ComponentIndex, name: &str) -> Result> { + fn find_component(&self, name: &str) -> Result>> { // Check the config for an explicit path (must be a valid component) if let Some(dep) = self.config.dependencies.get(name) { log::debug!( "component with name `{name}` has an explicit path of `{path}`", path = dep.path.display() ); - return Ok(Some(Component::new( - index, + return Ok(Some(Component::from_file( + name, self.config.dir.join(&dep.path), - dep.import.clone(), )?)); } // Otherwise, search the paths for a valid component with the same name log::info!("searching for a component with name `{name}`"); for dir in std::iter::once(&self.config.dir).chain(self.config.search_paths.iter()) { - if let Some(component) = Self::parse_component(index, dir, name)? { + if let Some(component) = Self::parse_component(dir, name)? { return Ok(Some(component)); } } @@ -531,7 +143,7 @@ impl<'a> InstantiationGraphBuilder<'a> { /// Parses a component from the given directory, if it exists. /// /// Returns `Ok(None)` if the component does not exist. - fn parse_component(index: ComponentIndex, dir: &Path, name: &str) -> Result> { + fn parse_component(dir: &Path, name: &str) -> Result>> { let mut path = dir.join(name); for ext in ["wasm", "wat"] { @@ -541,7 +153,7 @@ impl<'a> InstantiationGraphBuilder<'a> { continue; } - return Ok(Some(Component::new(index, &path, None)?)); + return Ok(Some(Component::from_file(name, &path)?)); } Ok(None) @@ -549,48 +161,31 @@ impl<'a> InstantiationGraphBuilder<'a> { /// Instantiates an instance with the given name into the graph. /// - /// `import` is expected to be `None` only for the root instantiation. - fn instantiate( - &mut self, - name: &str, - component_name: &str, - import: Option, - ) -> Result<(InstanceIndex, bool)> { - if let Some(index) = self.graph.names.get(name) { - if let Instance::Import(refs) = &mut self.graph.instances[*index] { - refs.insert(import.unwrap()); - } - return Ok((*index, true)); + /// Returns an index into `instances` for the instance being instantiated. + /// + /// Returns `Ok(None)` if a component to instantiate cannot be found. + fn instantiate(&mut self, name: &str, component_name: &str) -> Result> { + if let Some(index) = self.instances.get_index_of(name) { + return Ok(Some((index, true))); } - let instance = match self.add_component(component_name)? { - Some(component) => { - // If a dependency component was instantiated, mark it in the graph - if component.0 != 0 { - self.graph.instantiated = true; - } - Instance::Instantiation { component } + match self.add_component(component_name)? { + Some(component_id) => { + let (index, prev) = self + .instances + .insert_full(name.to_string(), self.graph.instantiate(component_id)?); + assert!(prev.is_none()); + Ok(Some((index, false))) } None => { if self.config.disallow_imports { - bail!( - "a dependency named `{component_name}` could not be found and instance imports are not allowed", - ); + bail!("a dependency named `{component_name}` could not be found and instance imports are not allowed"); } log::warn!("instance `{name}` will be imported because a dependency named `{component_name}` could not be found"); - Instance::Import([import.unwrap()].into()) + Ok(None) } - }; - - let index = self.graph.instances.add_node(instance); - log::debug!( - "adding instance `{name}` to the graph (instance index {index})", - index = index.index() - ); - assert_eq!(index.index(), self.graph.names.len()); - self.graph.names.insert(name.to_string(), index); - Ok((index, false)) + } } /// Finds a compatible instance for the given instance type. @@ -600,51 +195,41 @@ impl<'a> InstantiationGraphBuilder<'a> { /// Returns `Err(_)` if no compatible instance was found. fn find_compatible_instance( &self, - instance: InstanceIndex, - dependent: InstanceIndex, + instance: usize, + dependent: usize, arg_name: &str, - ty: &ComponentInstanceType, + ty: TypeId, types: TypesRef, ) -> Result> { - match self.graph.component(instance) { - Some(component) => { - let instance_name = self.graph.instance_name(instance); - let dependent_name = self.graph.instance_name(dependent); - - // Check if the instance or one of its exports is compatible with the expected import type - if component.is_subtype_of(ty, types) { - // The instance itself can be used - log::debug!( - "instance `{instance_name}` can be used for argument `{arg_name}` of instance `{dependent_name}`", - ); - return Ok(None); - } + let (instance_name, instance_id) = self.instances.get_index(instance).unwrap(); + let (_, component) = self.graph.get_component_of_instance(*instance_id).unwrap(); - log::debug!( - "searching for compatible export from instance `{instance_name}` for argument `{arg_name}` of instance `{dependent_name}`", - ); + let (dependent_name, dependent_instance_id) = self.instances.get_index(dependent).unwrap(); - let export = component.find_compatible_export(ty, types) .ok_or_else(|| { - anyhow!( - "component `{path}` is not compatible with import `{arg_name}` of component `{dependent_path}`", - path = component.path.display(), - dependent_path = self.graph.component(dependent).unwrap().path.display(), - ) - })?; + // Check if the instance or one of its exports is compatible with the expected import type + if component.is_instance_subtype_of(ty, types) { + // The instance itself can be used + log::debug!("instance `{instance_name}` can be used for argument `{arg_name}` of instance `{dependent_name}`"); + return Ok(None); + } - log::debug!( - "export `{export_name}` (export index {export}) from instance `{instance_name}` can be used for argument `{arg_name}` of instance `{dependent_name}`", - export = export.0, - export_name = component.exports.get_index(export.0).unwrap().0, - ); + log::debug!("searching for compatible export from instance `{instance_name}` for argument `{arg_name}` of instance `{dependent_name}`"); - Ok(Some(export)) - } - None => { - // An imported instance should be directly compatible - Ok(None) - } - } + let export = component.find_compatible_export(ty, types).ok_or_else(|| { + anyhow!( + "component `{path}` is not compatible with import `{arg_name}` of component `{dependent_path}`", + path = component.path().unwrap().display(), + dependent_path = self.graph.get_component_of_instance(*dependent_instance_id).unwrap().1.path().unwrap().display(), + ) + })?; + + log::debug!( + "export `{export_name}` (export index {export}) from instance `{instance_name}` can be used for argument `{arg_name}` of instance `{dependent_name}`", + export = export.0, + export_name = component.exports.get_index(export.0).unwrap().0, + ); + + Ok(Some(export)) } /// Resolves an explicitly specified export to its index. @@ -653,178 +238,268 @@ impl<'a> InstantiationGraphBuilder<'a> { fn resolve_export_index( &self, export: &str, - instance: InstanceIndex, - dependent: InstanceIndex, + instance: usize, + dependent_path: &Path, arg_name: &str, - ty: &ComponentInstanceType, + ty: TypeId, types: TypesRef, ) -> Result { - let instance_name = self.graph.instance_name(instance); - - match self.graph.component(instance) { - Some(component) => match component.export_instance(export) { - Some((index, export_ty)) => { - if !ComponentInstanceType::is_subtype_of( - export_ty, - component.types.as_ref(), - ty, - types, - ) { - bail!("component `{path}` exports an instance named `{export}` but it is not compatible with import `{arg_name}` of component `{dependent_path}`", - path = component.path.display(), - dependent_path = self.graph.component(dependent).unwrap().path.display(), - ) - } - - Ok(index) + let (_, instance_id) = self.instances.get_index(instance).unwrap(); + let (_, component) = self.graph.get_component_of_instance(*instance_id).unwrap(); + match component.export_by_name(export) { + Some((export_index, kind, index)) if kind == ComponentExternalKind::Instance => { + let export_ty = component.types.component_instance_at(index); + if !ComponentEntityType::is_subtype_of( + &ComponentEntityType::Instance(export_ty), + component.types(), + &ComponentEntityType::Instance(ty), + types, + ) { + bail!("component `{path}` exports an instance named `{export}` but it is not compatible with import `{arg_name}` of component `{dependent_path}`", + path = component.path().unwrap().display(), + dependent_path = dependent_path.display(), + ) } - None => bail!("component `{path}` does not export an instance named `{export}`", - path = component.path.display(), - ), - }, - None => bail!("an explicit export `{export}` cannot be specified for imported instance `{instance_name}`"), + + Ok(export_index) + } + _ => bail!( + "component `{path}` does not export an instance named `{export}`", + path = component.path().unwrap().display(), + ), } } - /// Processes a dependency in the graph. - fn process_dependency(&mut self, dependency: Dependency) -> Result<(InstanceIndex, bool)> { - let name = self.config.dependency_name(&dependency.instance); + /// Resolves an import instance reference. + fn resolve_import_ref(&self, r: InstanceImportRef) -> (&Component, &str, TypeId) { + let component = self.graph.get_component(r.component).unwrap(); + let (name, ty) = component.import(r.import).unwrap(); + match ty { + ComponentTypeRef::Instance(index) => { + (component, name, component.types.component_type_at(index)) + } + _ => unreachable!("should not have an instance import ref to a non-instance import"), + } + } - log::info!( - "processing dependency `{name}` from instance `{dependent}` to instance `{instance}`", - dependent = self - .graph - .names - .get_index(dependency.dependent.index()) - .unwrap() - .0, - instance = dependency.instance - ); + /// Processes a dependency in the graph. + /// + /// Returns `Ok(Some(index))` if the dependency resulted in a new dependency instance being created. + fn process_dependency(&mut self, dependency: Dependency) -> Result> { + match dependency.kind { + DependencyKind::Instance { instance, export } => self.process_instance_dependency( + dependency.dependent, + dependency.import, + &instance, + export.as_deref(), + ), + DependencyKind::Definition { index, export } => { + // The dependency is on a definition component, so we simply connect the dependent to the definition's export + let (component_id, instance_id) = &mut self.definitions[index]; + let instance_id = *instance_id + .get_or_insert_with(|| self.graph.instantiate(*component_id).unwrap()); + + self.graph + .connect( + instance_id, + Some(export), + self.instances[dependency.dependent], + dependency.import.import, + ) + .with_context(|| { + let name = self.instances.get_index(dependency.dependent).unwrap().0; + format!( + "failed to connect instance `{name}` to definition component `{path}`", + path = self + .graph + .get_component(*component_id) + .unwrap() + .path() + .unwrap() + .display(), + ) + })?; - let (instance, existing) = - self.instantiate(&dependency.instance, name, Some(dependency.import))?; + // No new dependency instance was created + Ok(None) + } + } + } - let (dependent, import_name, import_type) = self.graph.resolve_import(dependency.import); + fn process_instance_dependency( + &mut self, + dependent_index: usize, + import: InstanceImportRef, + instance: &str, + export: Option<&str>, + ) -> Result> { + let name = self.config.dependency_name(instance); - let export = match &dependency.export { - Some(export) => Some(self.resolve_export_index( - export, - instance, - dependency.dependent, - import_name, - import_type, - dependent.types.as_ref(), - )?), - None => self.find_compatible_instance( - instance, - dependency.dependent, - import_name, - import_type, - dependent.types.as_ref(), - )?, - }; - - // Add the edge from this instance to the dependent instance - self.graph.instances.add_edge( - instance, - dependency.dependent, - InstantiationArg { - import: dependency.import.import, - export, - }, + log::info!( + "processing dependency `{name}` from instance `{dependent_name}` to instance `{instance}`", + dependent_name = self.instances.get_index(dependent_index).unwrap().0, ); - Ok((instance, existing)) + match self.instantiate(instance, name)? { + Some((instance, existing)) => { + let (dependent, import_name, import_type) = self.resolve_import_ref(import); + + let export = match export { + Some(export) => Some(self.resolve_export_index( + export, + instance, + dependent.path().unwrap(), + import_name, + import_type, + dependent.types(), + )?), + None => self.find_compatible_instance( + instance, + dependent_index, + import_name, + import_type, + dependent.types(), + )?, + }; + + // Connect the new instance to the dependent + self.graph.connect( + self.instances[instance], + export, + self.instances[dependent_index], + import.import, + )?; + + if existing { + return Ok(None); + } + + Ok(Some(instance)) + } + None => { + if let Some(export) = export { + bail!("an explicit export `{export}` cannot be specified for imported instance `{name}`"); + } + Ok(None) + } + } } /// Push dependencies of the given instance to the dependency queue. - fn push_dependencies( - &self, - instance: InstanceIndex, - queue: &mut VecDeque>, - ) -> Result<()> { - match self.graph.instances[instance] { - Instance::Import { .. } => { - // Imported instances don't have dependencies + fn push_dependencies(&self, instance: usize, queue: &mut VecDeque) -> Result<()> { + let (instance_name, instance_id) = self.instances.get_index(instance).unwrap(); + let instantiation = self.config.instantiations.get(instance_name); + let (component_id, component) = self.graph.get_component_of_instance(*instance_id).unwrap(); + let count = queue.len(); + + // Push a dependency for every instance import + 'outer: for (import, name, ty) in component.imports() { + match ty { + ComponentTypeRef::Instance(_) => {} + _ => bail!( + "component `{path}` has a non-instance import named `{name}`", + path = component.path().unwrap().display() + ), } - Instance::Instantiation { component } => { - let instance_name = self.graph.instance_name(instance); - let config = self.config.instantiations.get(instance_name); - let comp = &self.graph.components[component.0]; - let count = queue.len(); - - // Push a dependency for every import - for (import, (name, ty)) in comp.imports.iter().enumerate() { - match ty { - ComponentTypeRef::Instance(_) => {} - _ => bail!( - "component `{path}` has a non-instance import named `{name}`", - path = comp.path.display() - ), - } - log::debug!("adding dependency for argument `{name}` (import index {import}) from instance `{instance_name}` to the queue"); - - let arg = config.and_then(|c| c.arguments.get(name)); - queue.push_back(Some(Dependency { - dependent: instance, - import: ImportRef { - component, - import: ImportIndex(import), - }, - instance: arg.map(|arg| &arg.instance).unwrap_or(name).clone(), - export: arg.and_then(|arg| arg.export.clone()), - })); - } - - // Ensure every explicit argument is a valid import name - if let Some(config) = config { - for arg in config.arguments.keys() { - if !comp.imports.contains_key(arg) { - bail!( - "component `{path}` has no import named `{arg}`", - path = comp.path.display() - ); - } + log::debug!("adding dependency for argument `{name}` (import index {import}) from instance `{instance_name}` to the queue", import = import.0); + + // Search for a matching definition export for this import + for (index, (def_component_id, _)) in self.definitions.iter().enumerate() { + let def_component = self.graph.get_component(*def_component_id).unwrap(); + + match def_component.export_by_name(name) { + Some((export, ComponentExternalKind::Instance, _)) => { + log::debug!( + "found matching instance export `{name}` in definition component `{path}`", + path = def_component.path().unwrap().display() + ); + + queue.push_back(Dependency { + dependent: instance, + import: InstanceImportRef { + component: component_id, + import, + }, + kind: DependencyKind::Definition { index, export }, + }); + + continue 'outer; } + _ => continue, } + } + + let arg = instantiation.and_then(|c| c.arguments.get(name)); + queue.push_back(Dependency { + dependent: instance, + import: InstanceImportRef { + component: component_id, + import, + }, + kind: DependencyKind::Instance { + instance: arg + .map(|arg| arg.instance.clone()) + .unwrap_or_else(|| name.to_string()), + export: arg.and_then(|arg| arg.export.clone()), + }, + }); + } - // It is an error if the root component has no instance imports - if count == queue.len() && component.0 == 0 { + // Ensure every explicit argument is a valid import name + if let Some(instantiation) = instantiation { + for arg in instantiation.arguments.keys() { + if !component.imports.contains_key(arg) { bail!( - "component `{path}` does not import any instances", - path = comp.path.display() + "component `{path}` has no import named `{arg}`", + path = component.path().unwrap().display() ); } } } + // It is an error if the root component has no instance imports + if count == queue.len() && instance == 0 { + bail!( + "component `{path}` does not import any instances", + path = component.path().unwrap().display() + ); + } + Ok(()) } /// Build the instantiation graph. - fn build(mut self) -> Result { - let mut queue: VecDeque> = VecDeque::new(); - queue.push_back(None); + fn build(mut self) -> Result<(InstanceId, CompositionGraph<'a>)> { + let mut queue: VecDeque = VecDeque::new(); - while let Some(dependency) = queue.pop_front() { - let (instance, existing) = dependency - .map(|dep| self.process_dependency(dep)) - .unwrap_or_else(|| { - self.instantiate(ROOT_COMPONENT_NAME, ROOT_COMPONENT_NAME, None) - })?; + // Instantiate the root and push its dependencies to the queue + let (root_instance, existing) = self + .instantiate(ROOT_COMPONENT_NAME, ROOT_COMPONENT_NAME)? + .unwrap(); + + assert!(!existing); + + self.push_dependencies(0, &mut queue)?; - // Add dependencies only for new instances in the graph - if !existing { + // Process all remaining dependencies in the queue + while let Some(dependency) = queue.pop_front() { + if let Some(instance) = self.process_dependency(dependency)? { self.push_dependencies(instance, &mut queue)?; } } - Ok(self.graph) + Ok((self.instances[root_instance], self.graph)) } } /// Used to compose a WebAssembly component from other components. +/// +/// The component composer resolves the dependencies of a root component +/// from components of matching names in the file system. +/// +/// The exports of the root component are then exported from the composed +/// component. pub struct ComponentComposer<'a> { component: &'a Path, config: &'a Config, @@ -845,22 +520,25 @@ impl<'a> ComponentComposer<'a> { /// ## Returns /// Returns the bytes of the composed component. pub fn compose(&self) -> Result> { - let graph = InstantiationGraphBuilder::new(self.component, self.config)?.build()?; - - log::debug!( - "components:\n{components:#?}\ninstantiation graph:\n{graph:?}", - components = graph.components, - graph = Dot::new(&graph.instances) - ); + let (root_instance, graph) = + CompositionGraphBuilder::new(self.component, self.config)?.build()?; - // If not a single dependency was instantiated, error out - if !graph.instantiated { + // If only the root component was instantiated, then there are no resolved dependencies + if graph.instances.len() == 1 { bail!( "no dependencies of component `{path}` were found", path = self.component.display() ); } - InstantiationGraphEncoder::new(self.config, &graph).encode() + CompositionGraphEncoder::new( + EncodeOptions { + define_components: !self.config.import_components, + export: Some(root_instance), + validate: false, + }, + &graph, + ) + .encode() } } diff --git a/crates/wasm-compose/src/config.rs b/crates/wasm-compose/src/config.rs index 35d54cbdef..84f1df678e 100644 --- a/crates/wasm-compose/src/config.rs +++ b/crates/wasm-compose/src/config.rs @@ -2,7 +2,7 @@ use anyhow::{Context, Result}; use indexmap::IndexMap; -use serde::Deserialize; +use serde_derive::Deserialize; use std::{ fs, path::{Path, PathBuf}, @@ -15,22 +15,13 @@ use std::{ pub struct Dependency { /// The path to the dependency's component file. pub path: PathBuf, - - /// The name to import the component with. - /// - /// By default, components are defined (embedded) in the composed component. - /// By specifying an import name, the component will be imported instead. - pub import: Option, } impl FromStr for Dependency { type Err = (); fn from_str(s: &str) -> Result { - Ok(Self { - path: s.into(), - import: None, - }) + Ok(Self { path: s.into() }) } } @@ -86,6 +77,10 @@ pub struct Config { #[serde(skip)] pub dir: PathBuf, + /// Components whose exports define import dependencies to fulfill from. + #[serde(default)] + pub definitions: Vec, + /// The paths to search when automatically resolving dependencies. /// /// The config directory is always searched first. @@ -96,6 +91,13 @@ pub struct Config { #[serde(default)] pub skip_validation: bool, + /// Whether or not to import components in the composed component. + /// + /// By default, components are defined rather than imported in + /// the composed component. + #[serde(default)] + pub import_components: bool, + /// Whether or not to disallow instance imports in the output component. /// /// Enabling this option will cause an error if a dependency cannot be diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs index 1aa81d42ab..79c39b95d3 100644 --- a/crates/wasm-compose/src/encoding.rs +++ b/crates/wasm-compose/src/encoding.rs @@ -1,129 +1,313 @@ -use crate::{ - composer::{ - Component, ComponentIndex, ExportIndex, ImportRef, InstanceIndex, InstantiationGraph, - }, - config::Config, +use crate::graph::{ + type_desc, CompositionGraph, EncodeOptions, ExportIndex, ImportIndex, InstanceId, }; -use anyhow::{bail, Result}; +use anyhow::{anyhow, bail, Result}; +use heck::ToKebabCase; use indexmap::{IndexMap, IndexSet}; -use std::collections::{hash_map::Entry, HashMap, HashSet}; +use petgraph::EdgeDirection; +use smallvec::SmallVec; +use std::mem; +use std::{ + borrow::Cow, + collections::{hash_map::Entry, HashMap}, +}; use wasm_encoder::*; -use wasmparser::types::{ComponentEntityType, Type, TypeId, TypesRef}; - -// Utility trait implement on component and instance types -// to abstract their encoding. -trait Encodable { - fn type_count(&self) -> u32; - fn ty(&mut self) -> ComponentTypeEncoder; - fn core_type(&mut self) -> CoreTypeEncoder; +use wasmparser::{ + names::KebabString, + types::{self, ComponentEntityType, Type, TypeId}, + ComponentExternalKind, +}; + +fn type_ref_to_export_kind(ty: wasmparser::ComponentTypeRef) -> ComponentExportKind { + match ty { + wasmparser::ComponentTypeRef::Module(_) => ComponentExportKind::Module, + wasmparser::ComponentTypeRef::Func(_) => ComponentExportKind::Func, + wasmparser::ComponentTypeRef::Value(_) => ComponentExportKind::Value, + wasmparser::ComponentTypeRef::Type { .. } => ComponentExportKind::Type, + wasmparser::ComponentTypeRef::Instance(_) => ComponentExportKind::Instance, + wasmparser::ComponentTypeRef::Component(_) => ComponentExportKind::Component, + } } -impl Encodable for ComponentType { +enum Encodable { + Component(ComponentType), + Instance(InstanceType), + Builder(ComponentBuilder), +} + +impl Encodable { fn type_count(&self) -> u32 { - Self::type_count(self) + match self { + Encodable::Component(t) => t.type_count(), + Encodable::Instance(t) => t.type_count(), + Encodable::Builder(t) => t.type_count(), + } + } + + fn instance_count(&self) -> u32 { + match self { + Encodable::Component(t) => t.instance_count(), + Encodable::Instance(t) => t.instance_count(), + Encodable::Builder(t) => t.instance_count(), + } + } + + fn core_type_count(&self) -> u32 { + match self { + Encodable::Component(t) => t.core_type_count(), + Encodable::Instance(t) => t.core_type_count(), + Encodable::Builder(t) => t.core_type_count(), + } } fn ty(&mut self) -> ComponentTypeEncoder { - Self::ty(self) + match self { + Encodable::Component(t) => t.ty(), + Encodable::Instance(t) => t.ty(), + Encodable::Builder(t) => t.ty().1, + } } fn core_type(&mut self) -> CoreTypeEncoder { - self.core_type() + match self { + Encodable::Component(t) => t.core_type(), + Encodable::Instance(t) => t.core_type(), + Encodable::Builder(t) => t.core_type().1, + } + } + + fn alias(&mut self, alias: Alias<'_>) { + match self { + Encodable::Component(t) => { + t.alias(alias); + } + Encodable::Instance(t) => { + t.alias(alias); + } + Encodable::Builder(t) => { + t.alias(alias); + } + } } } -impl Encodable for InstanceType { - fn type_count(&self) -> u32 { - self.type_count() +/// Metadata necessary to track type definitions across both instances and also +/// across unioning components. +/// +/// This state is used when assembling the imports into a composed component. +/// The imported instances will have types that are intended to mirror the +/// original source components which means that the type structure, such as +/// aliases, additionally needs to be mirrored. This structure keeps track of +/// type scopes and is used throughout type translation to facilitate this. +pub(crate) struct TypeState<'a> { + // Current outer scopes of this state which can be referred to with + // `alias outer` + scopes: Vec>, + + // Current type scope that's being translated into. + cur: TypeScope<'a>, +} + +/// A unique key identifying a type. +/// +/// Note that this has two components: the first is the component that a type +/// comes from and the second is the wasmparser-unique id for within that +/// component. +type TypeKey<'a> = (PtrKey<'a, crate::graph::Component<'a>>, TypeId); + +/// A scope that types can be defined into. +/// +/// This is stored within `TypeState` and contains all the relevant information +/// for mirroring a preexisting wasmparser-defined structure of types into a +/// new component type (such as an instance for an instance import). +struct TypeScope<'a> { + /// Types defined in this current scope. + /// + /// Contains the type index that the type is defined at. + type_defs: HashMap, u32>, + + /// Types exported in the current scope. + /// + /// This is filled out during `export` and indicates that a particular type + /// is exported with the specified name. + type_exports: HashMap, &'a str>, + + /// Reverse of the `type_exports` map, indicating which name exports which + /// types. + /// + /// Note that this can export a "list" of types which represents that + /// multiple components may be "unioned" together to create a single + /// instance import, so exporting a type can have different names as each + /// original component may have ID for the same export name. + /// + /// This enables translating type-use situations where one component + /// translates the base type and then a second component refers to that. + type_exports_rev: HashMap<&'a str, Vec>>, + + /// Instances that are available to alias from in this scope. + /// + /// This map is keyed by the types that are available to be referred to. + /// The value here is the instance index that the type is defined in along + /// with its export name. This is used to generate `alias export` items. + instance_exports: HashMap, (u32, &'a str)>, + + /// Encoded representation of this type scope, a `wasm-encoder` structure. + encodable: Encodable, +} + +impl<'a> TypeState<'a> { + fn new() -> TypeState<'a> { + TypeState { + scopes: Vec::new(), + cur: TypeScope { + type_exports: HashMap::new(), + type_exports_rev: HashMap::new(), + instance_exports: HashMap::new(), + type_defs: HashMap::new(), + encodable: Encodable::Builder(Default::default()), + }, + } } - fn ty(&mut self) -> ComponentTypeEncoder { - self.ty() + /// Pushes a new scope which will be written to the `encodable` provided. + fn push(&mut self, encodable: Encodable) { + let prev = mem::replace( + &mut self.cur, + TypeScope { + type_exports: HashMap::new(), + type_exports_rev: HashMap::new(), + instance_exports: HashMap::new(), + type_defs: HashMap::new(), + encodable, + }, + ); + self.scopes.push(prev); } - fn core_type(&mut self) -> CoreTypeEncoder { - self.core_type() + /// Pops a previously pushed scope and returns the encoding. + fn pop(&mut self) -> Encodable { + let prev = mem::replace(&mut self.cur, self.scopes.pop().unwrap()); + + // If the previous scope was an instance then assume that the instance + // type is about to be used as an import or export which defines a new + // instance that this previously-outer-now-current scope has access to. + // + // This scope then takes all of the type exports of the created instance + // and registers them as available at this next instance index. + if let Encodable::Instance(_) = &prev.encodable { + let idx = self.cur.encodable.instance_count(); + for (id, name) in prev.type_exports { + let prev = self.cur.instance_exports.insert(id, (idx, name)); + assert!(prev.is_none()); + } + } + + prev.encodable } } -/// Represents a type key for type maps used in encoding. -/// -/// This implementation prevents encoding of duplicate types from the same -/// validator, but not from different validators. -/// -/// TODO: implement this fully in `wasmparser`? -#[derive(Copy, Clone)] -struct TypeKey<'a> { - types: TypesRef<'a>, - id: TypeId, +impl Default for TypeState<'_> { + fn default() -> Self { + Self::new() + } } -impl<'a> PartialEq for TypeKey<'a> { +impl<'a> TypeScope<'a> { + /// Registers that `ty` is exported as `name`, filling in both type export + /// maps at the same time. + fn add_type_export(&mut self, ty: TypeKey<'a>, name: &'a str) { + let prev = self.type_exports.insert(ty, name); + assert!(prev.is_none()); + self.type_exports_rev.entry(name).or_default().push(ty); + } +} + +pub struct PtrKey<'a, T>(&'a T); + +impl PartialEq for PtrKey<'_, T> { fn eq(&self, other: &Self) -> bool { - std::ptr::eq( - self.types.type_from_id(self.id).unwrap(), - other.types.type_from_id(other.id).unwrap(), - ) + std::ptr::eq(self.0, other.0) } } -impl<'a> Eq for TypeKey<'a> {} +impl Eq for PtrKey<'_, T> {} -impl std::hash::Hash for TypeKey<'_> { - fn hash(&self, state: &mut H) { - struct TypeHash<'a>(&'a Type); +impl Copy for PtrKey<'_, T> {} - impl std::hash::Hash for TypeHash<'_> { - fn hash(&self, state: &mut H) { - std::ptr::hash(self.0, state) - } - } +impl Clone for PtrKey<'_, T> { + fn clone(&self) -> Self { + *self + } +} - TypeHash(self.types.type_from_id(self.id).unwrap()).hash(state); +impl std::hash::Hash for PtrKey<'_, T> { + fn hash(&self, state: &mut H) { + std::ptr::hash(self.0, state); } } -pub struct TypeEncoder<'a>(TypesRef<'a>); +pub(crate) struct TypeEncoder<'a>(&'a crate::graph::Component<'a>); impl<'a> TypeEncoder<'a> { - pub fn new(types: TypesRef<'a>) -> Self { - Self(types) + pub fn new(component: &'a crate::graph::Component) -> Self { + Self(component) } - pub fn component(&self, imports: I, exports: E) -> ComponentType + pub fn component( + &self, + state: &mut TypeState<'a>, + imports: I, + exports: E, + ) -> ComponentType where I: IntoIterator, E: IntoIterator, { - let mut encoded = ComponentType::new(); - let mut types: HashMap, u32> = HashMap::new(); + state.push(Encodable::Component(ComponentType::new())); for (name, ty) in imports { - let ty = self.component_entity_type(&mut encoded, &mut types, ty); - encoded.import(name, ty); + let ty = self.component_entity_type(state, ty); + let c = match &mut state.cur.encodable { + Encodable::Component(c) => c, + _ => unreachable!(), + }; + c.import(name, ty); } for (name, ty) in exports { - let ty = self.component_entity_type(&mut encoded, &mut types, ty); - encoded.export(name, ty); + let export = self.export(name, ty, state); + let c = match &mut state.cur.encodable { + Encodable::Component(c) => c, + _ => unreachable!(), + }; + c.export(name, export); } - encoded + match state.pop() { + Encodable::Component(c) => c, + _ => unreachable!(), + } } - pub fn instance(&self, exports: E) -> InstanceType + pub fn instance(&self, state: &mut TypeState<'a>, exports: E) -> InstanceType where E: IntoIterator, { - let mut encoded = InstanceType::new(); - let mut types: HashMap, u32> = HashMap::new(); + state.push(Encodable::Instance(InstanceType::new())); for (name, ty) in exports { - let ty = self.component_entity_type(&mut encoded, &mut types, ty); - encoded.export(name, ty); + let export = self.export(name, ty, state); + let c = match &mut state.cur.encodable { + Encodable::Instance(c) => c, + _ => unreachable!(), + }; + c.export(name, export); } - encoded + match state.pop() { + Encodable::Instance(c) => c, + _ => unreachable!(), + } } pub fn module(&self, imports: I, exports: E) -> ModuleType @@ -132,7 +316,7 @@ impl<'a> TypeEncoder<'a> { E: IntoIterator, { let mut encoded = ModuleType::new(); - let mut types: HashMap, u32> = HashMap::new(); + let mut types = HashMap::default(); for (module, name, ty) in imports { let ty = self.entity_type(&mut encoded, &mut types, ty); @@ -150,15 +334,16 @@ impl<'a> TypeEncoder<'a> { fn entity_type( &self, encodable: &mut ModuleType, - types: &mut HashMap, u32>, + types: &mut HashMap, ty: wasmparser::types::EntityType, ) -> EntityType { match ty { wasmparser::types::EntityType::Func(id) => { - let idx = match types.entry(TypeKey { types: self.0, id }) { + let ty = &self.0.types[id]; + let idx = match types.entry(id) { Entry::Occupied(e) => *e.get(), Entry::Vacant(e) => { - let ty = self.0.type_from_id(id).unwrap().as_func_type().unwrap(); + let ty = ty.unwrap_func(); let index = encodable.type_count(); encodable.ty().function( ty.params().iter().copied().map(Self::val_type), @@ -173,10 +358,11 @@ impl<'a> TypeEncoder<'a> { wasmparser::types::EntityType::Memory(ty) => EntityType::Memory(Self::memory_type(ty)), wasmparser::types::EntityType::Global(ty) => EntityType::Global(Self::global_type(ty)), wasmparser::types::EntityType::Tag(id) => { - let idx = match types.entry(TypeKey { types: self.0, id }) { + let ty = &self.0.types[id]; + let idx = match types.entry(id) { Entry::Occupied(e) => *e.get(), Entry::Vacant(e) => { - let ty = self.0.type_from_id(id).unwrap().as_func_type().unwrap(); + let ty = ty.unwrap_func(); let index = encodable.type_count(); encodable.ty().function( ty.params().iter().copied().map(Self::val_type), @@ -193,6 +379,33 @@ impl<'a> TypeEncoder<'a> { } } + fn component_entity_type( + &self, + state: &mut TypeState<'a>, + ty: wasmparser::types::ComponentEntityType, + ) -> ComponentTypeRef { + match ty { + wasmparser::types::ComponentEntityType::Module(id) => { + ComponentTypeRef::Module(self.ty(state, id)) + } + wasmparser::types::ComponentEntityType::Func(id) => { + ComponentTypeRef::Func(self.ty(state, id)) + } + wasmparser::types::ComponentEntityType::Value(ty) => { + ComponentTypeRef::Value(self.component_val_type(state, ty)) + } + wasmparser::types::ComponentEntityType::Type { referenced, .. } => { + ComponentTypeRef::Type(TypeBounds::Eq(self.ty(state, referenced))) + } + wasmparser::types::ComponentEntityType::Instance(id) => { + ComponentTypeRef::Instance(self.ty(state, id)) + } + wasmparser::types::ComponentEntityType::Component(id) => { + ComponentTypeRef::Component(self.ty(state, id)) + } + } + } + fn val_type(ty: wasmparser::ValType) -> ValType { match ty { wasmparser::ValType::I32 => ValType::I32, @@ -200,14 +413,32 @@ impl<'a> TypeEncoder<'a> { wasmparser::ValType::F32 => ValType::F32, wasmparser::ValType::F64 => ValType::F64, wasmparser::ValType::V128 => ValType::V128, - wasmparser::ValType::FuncRef => ValType::FuncRef, - wasmparser::ValType::ExternRef => ValType::ExternRef, + wasmparser::ValType::Ref(ty) => ValType::Ref(Self::ref_type(ty)), + } + } + + fn ref_type(ty: wasmparser::RefType) -> RefType { + RefType { + nullable: ty.is_nullable(), + heap_type: match ty.heap_type() { + wasmparser::HeapType::Func => HeapType::Func, + wasmparser::HeapType::Extern => HeapType::Extern, + wasmparser::HeapType::Any => HeapType::Any, + wasmparser::HeapType::None => HeapType::None, + wasmparser::HeapType::NoExtern => HeapType::NoExtern, + wasmparser::HeapType::NoFunc => HeapType::NoFunc, + wasmparser::HeapType::Eq => HeapType::Eq, + wasmparser::HeapType::Struct => HeapType::Struct, + wasmparser::HeapType::Array => HeapType::Array, + wasmparser::HeapType::I31 => HeapType::I31, + wasmparser::HeapType::Indexed(i) => HeapType::Indexed(i), + }, } } fn table_type(ty: wasmparser::TableType) -> TableType { TableType { - element_type: Self::val_type(ty.element_type), + element_type: Self::ref_type(ty.element_type), minimum: ty.initial, maximum: ty.maximum, } @@ -247,199 +478,193 @@ impl<'a> TypeEncoder<'a> { } } - fn component_entity_type( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - ty: wasmparser::types::ComponentEntityType, - ) -> ComponentTypeRef { - match ty { - wasmparser::types::ComponentEntityType::Module(id) => { - ComponentTypeRef::Module(self.module_type(encodable, types, id)) - } - wasmparser::types::ComponentEntityType::Func(id) => { - ComponentTypeRef::Func(self.component_func_type(encodable, types, id)) - } - wasmparser::types::ComponentEntityType::Value(ty) => { - ComponentTypeRef::Value(self.component_val_type(encodable, types, ty)) - } - wasmparser::types::ComponentEntityType::Type(id) => { - ComponentTypeRef::Type(TypeBounds::Eq, self.ty(encodable, types, id)) - } - wasmparser::types::ComponentEntityType::Instance(id) => { - ComponentTypeRef::Instance(self.component_instance_type(encodable, types, id)) - } - wasmparser::types::ComponentEntityType::Component(id) => { - ComponentTypeRef::Component(self.component_type(encodable, types, id)) - } - } - } - - fn module_type( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - id: TypeId, - ) -> u32 { - match types.entry(TypeKey { types: self.0, id }) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let ty = self.0.type_from_id(id).unwrap().as_module_type().unwrap(); + fn module_type(&self, state: &mut TypeState<'a>, id: TypeId) -> u32 { + let ty = &self.0.types[id]; + let ty = ty.unwrap_module(); - let module = self.module( - ty.imports - .iter() - .map(|((m, n), t)| (m.as_str(), n.as_str(), *t)), - ty.exports.iter().map(|(n, t)| (n.as_str(), *t)), - ); + let module = self.module( + ty.imports + .iter() + .map(|((m, n), t)| (m.as_str(), n.as_str(), *t)), + ty.exports.iter().map(|(n, t)| (n.as_str(), *t)), + ); - let index = encodable.type_count(); - encodable.core_type().module(&module); - *e.insert(index) - } - } + let index = state.cur.encodable.core_type_count(); + state.cur.encodable.core_type().module(&module); + index } - fn component_instance_type( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - id: TypeId, - ) -> u32 { - match types.entry(TypeKey { types: self.0, id }) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let ty = self - .0 - .type_from_id(id) - .unwrap() - .as_component_instance_type() - .unwrap(); - - let instance = - self.instance(ty.exports(self.0).iter().map(|(n, t)| (n.as_str(), *t))); - - let index = encodable.type_count(); - encodable.ty().instance(&instance); - *e.insert(index) - } - } + fn component_instance_type(&self, state: &mut TypeState<'a>, id: TypeId) -> u32 { + let ty = &self.0.types[id]; + let ty = ty.unwrap_component_instance(); + let instance = self.instance(state, ty.exports.iter().map(|(n, t)| (n.as_str(), *t))); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().instance(&instance); + index } - fn component_type( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - id: TypeId, - ) -> u32 { - match types.entry(TypeKey { types: self.0, id }) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let ty = self - .0 - .type_from_id(id) - .unwrap() - .as_component_type() - .unwrap(); - - let component = self.component( - ty.imports.iter().map(|(n, t)| (n.as_str(), *t)), - ty.exports.iter().map(|(n, t)| (n.as_str(), *t)), - ); + fn component_type(&self, state: &mut TypeState<'a>, id: TypeId) -> u32 { + let ty = &self.0.types[id]; + let ty = ty.unwrap_component(); - let index = encodable.type_count(); - encodable.ty().component(&component); - *e.insert(index) - } - } - } + let component = self.component( + state, + ty.imports.iter().map(|(n, t)| (n.as_str(), *t)), + ty.exports.iter().map(|(n, t)| (n.as_str(), *t)), + ); - fn component_func_type( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - id: TypeId, - ) -> u32 { - if let Some(idx) = types.get(&TypeKey { types: self.0, id }) { - return *idx; - } + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().component(&component); + index + } - let ty = self - .0 - .type_from_id(id) - .unwrap() - .as_component_func_type() - .unwrap(); + fn component_func_type(&self, state: &mut TypeState<'a>, id: TypeId) -> u32 { + let ty = &self.0.types[id]; + let func_ty = ty.unwrap_component_func(); - let params = ty + let params = func_ty .params .iter() - .map(|(name, ty)| { - ( - name.as_deref(), - self.component_val_type(encodable, types, *ty), - ) - }) + .map(|(name, ty)| (name.as_str(), self.component_val_type(state, *ty))) .collect::>(); - let results = ty + let results = func_ty .results .iter() - .map(|(name, ty)| { - ( - name.as_deref(), - self.component_val_type(encodable, types, *ty), - ) - }) + .map(|(name, ty)| (name.as_deref(), self.component_val_type(state, *ty))) .collect::>(); - let index = encodable.type_count(); - let mut f = encodable.ty().function(); + let index = state.cur.encodable.type_count(); + let mut f = state.cur.encodable.ty().function(); - if params.len() == 1 && params[0].0.is_none() { - f.param(params[0].1); - } else { - f.params(params.into_iter().map(|(name, ty)| (name.unwrap(), ty))); - } + f.params(params); if results.len() == 1 && results[0].0.is_none() { f.result(results[0].1); } else { - f.results(results.into_iter().map(|(name, ty)| (name.unwrap(), ty))); + f.results( + results + .into_iter() + .map(|(name, ty)| (name.unwrap().as_str(), ty)), + ); } - types.insert(TypeKey { types: self.0, id }, index); index } - fn ty( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - id: TypeId, - ) -> u32 { - let ty = self.0.type_from_id(id).unwrap(); + /// Translates a type `id` provided, returning the index that it is defined + /// at. + /// + /// This is the main point at which type translation flows through. This + /// performs everything necessary such as: + /// + /// * Each type is translated only once + /// * If `id` comes from a different instance it's aliased + /// * Dispatching to the correct translation internally. + fn ty(&self, state: &mut TypeState<'a>, id: TypeId) -> u32 { + // Consult our scope's `type_defs` map, and if it's not present then + // generate the type and fill it in. + let key = (PtrKey(self.0), id); + if let Some(ret) = state.cur.type_defs.get(&key) { + return *ret; + } + let idx = self._ty(state, id); + let prev = state.cur.type_defs.insert(key, idx); + assert!(prev.is_none()); + idx + } - match ty { - wasmparser::types::Type::Func(_) | wasmparser::types::Type::Instance(_) => { - unreachable!() - } - wasmparser::types::Type::Module(_) => self.module_type(encodable, types, id), - wasmparser::types::Type::Component(_) => self.component_type(encodable, types, id), - wasmparser::types::Type::ComponentInstance(_) => { - self.component_instance_type(encodable, types, id) + // Inner version of `ty` above which is a separate method to make it easier + // to use `return` and not thwart the caching above. + fn _ty(&self, state: &mut TypeState<'a>, id: TypeId) -> u32 { + // If `id` is not an alias to anything else then it's a defined type in + // this scope meaning that it needs to be translated and represented + // here. + if self.0.types.peel_alias(id).is_none() { + return match &self.0.types[id] { + Type::Sub(_) | Type::Instance(_) => unreachable!(), + Type::Module(_) => self.module_type(state, id), + Type::Component(_) => self.component_type(state, id), + Type::ComponentInstance(_) => self.component_instance_type(state, id), + Type::ComponentFunc(_) => self.component_func_type(state, id), + Type::Defined(_) => self.defined_type(state, id), + Type::Resource(_) => unimplemented!(), + }; + } + + // Otherwise at this point we know that `id` is an alias to something. + // This basically means that it's a reference to an exported type which + // is an alias to a different underlying type. + // + // Before attempting to find something to alias first determine if the + // type has already been created but under a different name. This + // can happen where one component's view of an imported instance + // may be partial and then unioned with another component's view of an + // imported instance. The second instance should reuse all the types + // defined/exported by the first. + // + // Here the reverse-export map is consulted where if `key` is an + // exported type from this instance (which is registered in "parallel" + // when one of those is encountered for all components) then search + // with the exported name if any other component has a type definition + // for their own version of our `id`. + let key = (PtrKey(self.0), id); + if let Some(name) = state.cur.type_exports.get(&key) { + for key in state.cur.type_exports_rev[name].iter() { + if let Some(ret) = state.cur.type_defs.get(key) { + log::trace!("id already defined through a different component"); + return *ret; + } } - wasmparser::types::Type::ComponentFunc(_) => { - self.component_func_type(encodable, types, id) + } + + // Failing all that it seems that this type is defined elsewhere and + // no one has created an alias yet for it. That's our job so follow the + // alias chain and search all our outer scopes for one that has an + // instance that exports `id`. When found it's aliased out from + // that instance and then aliased into the current scope. + let mut cur = id; + loop { + for (i, scope) in state.scopes.iter_mut().rev().enumerate() { + let key = (PtrKey(self.0), cur); + let (instance, name) = match scope.instance_exports.get(&key) { + Some(pair) => *pair, + None => continue, + }; + let scope_idx = scope.encodable.type_count(); + scope.encodable.alias(Alias::InstanceExport { + instance, + name, + kind: ComponentExportKind::Type, + }); + match &scope.encodable { + Encodable::Instance(_) => log::trace!("instance"), + Encodable::Component(_) => log::trace!("component"), + Encodable::Builder(_) => log::trace!("builder"), + } + let ret = state.cur.encodable.type_count(); + state.cur.encodable.alias(Alias::Outer { + count: i as u32 + 1, + index: scope_idx, + kind: ComponentOuterAliasKind::Type, + }); + log::trace!("id defined in a different instance"); + return ret; } - wasmparser::types::Type::Defined(_) => self.defined_type(encodable, types, id), + + // If the end of the alias chain has been reached then that's a bug + // in this type translation. It should be the case that we know + // how to find all types at this point, so reaching the end means + // there's a missing case one way or another. + cur = self.0.types.peel_alias(cur).unwrap_or_else(|| { + panic!("failed to find alias of {id:?}"); + }); } } fn component_val_type( &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, + state: &mut TypeState<'a>, ty: wasmparser::types::ComponentValType, ) -> ComponentValType { match ty { @@ -447,125 +672,105 @@ impl<'a> TypeEncoder<'a> { ComponentValType::Primitive(Self::primitive(ty)) } wasmparser::types::ComponentValType::Type(id) => { - ComponentValType::Type(self.defined_type(encodable, types, id)) + ComponentValType::Type(self.ty(state, id)) } } } - fn defined_type( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - id: TypeId, - ) -> u32 { - if let Some(idx) = types.get(&TypeKey { types: self.0, id }) { - return *idx; - } - - let ty = self.0.type_from_id(id).unwrap().as_defined_type().unwrap(); + fn defined_type(&self, state: &mut TypeState<'a>, id: TypeId) -> u32 { + let ty = &self.0.types[id]; + let defined_ty = ty.unwrap_defined(); - let index = match ty { + match defined_ty { wasmparser::types::ComponentDefinedType::Primitive(ty) => { - let index = encodable.type_count(); - encodable + let index = state.cur.encodable.type_count(); + state + .cur + .encodable .ty() .defined_type() .primitive(Self::primitive(*ty)); index } - wasmparser::types::ComponentDefinedType::Record(r) => self.record(encodable, types, r), - wasmparser::types::ComponentDefinedType::Variant(v) => { - self.variant(encodable, types, v) + wasmparser::types::ComponentDefinedType::Record(r) => self.record(state, r), + wasmparser::types::ComponentDefinedType::Variant(v) => self.variant(state, v), + wasmparser::types::ComponentDefinedType::List(ty) => self.list(state, *ty), + wasmparser::types::ComponentDefinedType::Tuple(t) => self.tuple(state, t), + wasmparser::types::ComponentDefinedType::Flags(names) => { + Self::flags(&mut state.cur.encodable, names) } - wasmparser::types::ComponentDefinedType::List(ty) => self.list(encodable, types, *ty), - wasmparser::types::ComponentDefinedType::Tuple(t) => self.tuple(encodable, types, t), - wasmparser::types::ComponentDefinedType::Flags(names) => Self::flags(encodable, names), wasmparser::types::ComponentDefinedType::Enum(cases) => { - Self::enum_type(encodable, cases) - } - wasmparser::types::ComponentDefinedType::Union(u) => self.union(encodable, types, u), - wasmparser::types::ComponentDefinedType::Option(ty) => { - self.option(encodable, types, *ty) + Self::enum_type(&mut state.cur.encodable, cases) } + wasmparser::types::ComponentDefinedType::Option(ty) => self.option(state, *ty), wasmparser::types::ComponentDefinedType::Result { ok, err } => { - self.result(encodable, types, *ok, *err) + self.result(state, *ok, *err) } - }; - - types.insert(TypeKey { types: self.0, id }, index); - index + wasmparser::types::ComponentDefinedType::Own(id) => { + let i = self.ty(state, *id); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().defined_type().own(i); + index + } + wasmparser::types::ComponentDefinedType::Borrow(id) => { + let i = self.ty(state, *id); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().defined_type().borrow(i); + index + } + } } - fn record( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - record: &wasmparser::types::RecordType, - ) -> u32 { + fn record(&self, state: &mut TypeState<'a>, record: &wasmparser::types::RecordType) -> u32 { let fields = record .fields .iter() - .map(|(n, ty)| (n.as_str(), self.component_val_type(encodable, types, *ty))) + .map(|(n, ty)| (n.as_str(), self.component_val_type(state, *ty))) .collect::>(); - let index = encodable.type_count(); - encodable.ty().defined_type().record(fields); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().defined_type().record(fields); index } - fn variant( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - variant: &wasmparser::types::VariantType, - ) -> u32 { + fn variant(&self, state: &mut TypeState<'a>, variant: &wasmparser::types::VariantType) -> u32 { let cases = variant .cases .iter() .map(|(n, c)| { ( n.as_str(), - c.ty.map(|ty| self.component_val_type(encodable, types, ty)), + c.ty.map(|ty| self.component_val_type(state, ty)), c.refines .as_deref() .map(|r| variant.cases.iter().position(|(n, _)| n == r).unwrap() as u32), ) }) .collect::>(); - let index = encodable.type_count(); - encodable.ty().defined_type().variant(cases); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().defined_type().variant(cases); index } - fn list( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - ty: wasmparser::types::ComponentValType, - ) -> u32 { - let ty = self.component_val_type(encodable, types, ty); - let index = encodable.type_count(); - encodable.ty().defined_type().list(ty); + fn list(&self, state: &mut TypeState<'a>, ty: wasmparser::types::ComponentValType) -> u32 { + let ty = self.component_val_type(state, ty); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().defined_type().list(ty); index } - fn tuple( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - tuple: &wasmparser::types::TupleType, - ) -> u32 { + fn tuple(&self, state: &mut TypeState<'a>, tuple: &wasmparser::types::TupleType) -> u32 { let types = tuple .types .iter() - .map(|ty| self.component_val_type(encodable, types, *ty)) + .map(|ty| self.component_val_type(state, *ty)) .collect::>(); - let index = encodable.type_count(); - encodable.ty().defined_type().tuple(types); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().defined_type().tuple(types); index } - fn flags(encodable: &mut impl Encodable, names: &IndexSet) -> u32 { + fn flags(encodable: &mut Encodable, names: &IndexSet) -> u32 { let index = encodable.type_count(); encodable .ty() @@ -574,7 +779,7 @@ impl<'a> TypeEncoder<'a> { index } - fn enum_type(encodable: &mut impl Encodable, cases: &IndexSet) -> u32 { + fn enum_type(encodable: &mut Encodable, cases: &IndexSet) -> u32 { let index = encodable.type_count(); encodable .ty() @@ -583,377 +788,893 @@ impl<'a> TypeEncoder<'a> { index } - fn union( - &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - union: &wasmparser::types::UnionType, - ) -> u32 { - let types = union - .types - .iter() - .map(|ty| self.component_val_type(encodable, types, *ty)) - .collect::>(); + fn option(&self, state: &mut TypeState<'a>, ty: wasmparser::types::ComponentValType) -> u32 { + let ty = self.component_val_type(state, ty); - let index = encodable.type_count(); - encodable.ty().defined_type().union(types); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().defined_type().option(ty); index } - fn option( + fn result( &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - ty: wasmparser::types::ComponentValType, + state: &mut TypeState<'a>, + ok: Option, + err: Option, ) -> u32 { - let ty = self.component_val_type(encodable, types, ty); + let ok = ok.map(|ty| self.component_val_type(state, ty)); + let err = err.map(|ty| self.component_val_type(state, ty)); - let index = encodable.type_count(); - encodable.ty().defined_type().option(ty); + let index = state.cur.encodable.type_count(); + state.cur.encodable.ty().defined_type().result(ok, err); index } - fn result( + fn export( &self, - encodable: &mut impl Encodable, - types: &mut HashMap, u32>, - ok: Option, - err: Option, - ) -> u32 { - let ok = ok.map(|ty| self.component_val_type(encodable, types, ty)); - let err = err.map(|ty| self.component_val_type(encodable, types, ty)); + name: &'a str, + export: ComponentEntityType, + state: &mut TypeState<'a>, + ) -> ComponentTypeRef { + // Check if the export is a type; if so, we need to update the index of the + // type to point to the export instead of the original definition + let id = match export { + ComponentEntityType::Type { created: id, .. } => Some(id), + _ => None, + }; + let export = self.component_entity_type(state, export); + if let Some(id) = id { + // Update the index in the type map to point to this export + let key = (PtrKey(self.0), id); + let prev = state + .cur + .type_defs + .insert(key, state.cur.encodable.type_count()); + assert!(prev.is_none()); + state.cur.add_type_export(key, name); + } + export + } +} - let index = encodable.type_count(); - encodable.ty().defined_type().result(ok, err); - index +/// Represents an instance index in a composition graph. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +struct InstanceIndex(usize); + +enum ArgumentImportKind<'a> { + /// An item is being imported. + /// + /// The item may be an instance that does not need to be merged. + Item(&'a crate::graph::Component<'a>, ComponentEntityType), + /// A merged instance is being imported. + /// + /// Instances are unioned together to form a single instance to + /// import that will satisfy all instantiation arguments that + /// reference the import. + Instance(IndexMap<&'a str, Vec<(&'a crate::graph::Component<'a>, ComponentEntityType)>>), +} + +/// Represents an import for an instantiation argument. +struct ArgumentImport<'a> { + // The name of the import. + name: &'a str, + /// The kind of import. + kind: ArgumentImportKind<'a>, + /// The instances that will use the import for an argument. + instances: SmallVec<[(InstanceIndex, ImportIndex); 1]>, +} + +impl ArgumentImport<'_> { + fn merge(&mut self, arg: Self) -> Result<()> { + assert_eq!(self.name, arg.name); + self.instances.extend(arg.instances); + + // If the existing import is an instance, convert this argument import to + // a merged instance import. + if let ArgumentImportKind::Item(component, ComponentEntityType::Instance(id)) = &self.kind { + let exports = component.types[*id] + .unwrap_component_instance() + .exports + .iter(); + + let mut map = IndexMap::with_capacity(exports.len()); + for (name, ty) in exports { + map.insert(name.as_str(), vec![(*component, *ty)]); + } + + self.kind = ArgumentImportKind::Instance(map); + } + + match (&mut self.kind, arg.kind) { + // The new item should never be a merged instance + (_, ArgumentImportKind::Instance(..)) => { + unreachable!("expected an item import to merge with") + } + // If the existing import is a merged instance, merge with an instance item import + ( + ArgumentImportKind::Instance(exports), + ArgumentImportKind::Item(new_component, ComponentEntityType::Instance(id)), + ) => { + for (name, new_type) in new_component.types[id] + .unwrap_component_instance() + .exports + .iter() + { + let dst = exports.entry(name.as_str()).or_default(); + for (existing_component, existing_type) in dst.iter_mut() { + if Self::types_compatible( + existing_component, + *existing_type, + new_component, + *new_type, + ) { + continue; + } + bail!( + "cannot import instance with name `{name}` for \ + an instantiation argument of component \ + `{cname}` because it conflicts with an \ + imported instantiation argument of component \ + `{ecname}`", + name = self.name, + cname = new_component.name, + ecname = existing_component.name, + ) + } + dst.push((new_component, *new_type)); + } + } + // Otherwise, an attempt to merge an instance with a non-instance is an error + (ArgumentImportKind::Instance(_), ArgumentImportKind::Item(component, ty)) => { + bail!( + "cannot import {ty} with name `{name}` for an instantiation \ + argument of component `{cname}` because it conflicts with \ + an instance imported with the same name", + name = self.name, + ty = type_desc(ty), + cname = component.name, + ); + } + // Finally, merge two item imports together by finding the most-compatible type + ( + ArgumentImportKind::Item(existing_component, existing_type), + ArgumentImportKind::Item(new_component, new_type), + ) => { + if !Self::types_compatible( + existing_component, + *existing_type, + new_component, + new_type, + ) { + bail!( + "cannot import {ty} with name `{name}` for an \ + instantiation argument of component `{cname}` \ + because it conflicts with an imported instantiation \ + argument of component `{ecname}`", + ty = type_desc(new_type), + name = self.name, + cname = new_component.name, + ecname = existing_component.name, + ) + } + } + } + + Ok(()) + } + + /// Tests whether two types from different components are compatible with + /// one another. + /// + /// For now this performs a subtype check in both directions, only + /// considering them compatible if both checks are "true". This means + /// that it effectively requires the types to be structured the same way. + fn types_compatible<'a>( + existing_component: &'a crate::graph::Component<'a>, + existing_type: ComponentEntityType, + new_component: &'a crate::graph::Component<'a>, + new_type: ComponentEntityType, + ) -> bool { + ComponentEntityType::is_subtype_of( + &existing_type, + existing_component.types(), + &new_type, + new_component.types(), + ) && ComponentEntityType::is_subtype_of( + &new_type, + new_component.types(), + &existing_type, + existing_component.types(), + ) + } +} + +/// Represents an entry in the import map built up during +/// the encoding of a composition graph. +/// +/// A map entry is either an import of a component or +/// an import of an item to satisfy an instantiation argument. +enum ImportMapEntry<'a> { + /// An import of a component. + Component(&'a crate::graph::Component<'a>), + /// An import to satisfy one or more instantiation arguments. + Argument(ArgumentImport<'a>), +} + +/// Represents the import map built during the encoding +/// of a composition graph. +#[derive(Default)] +struct ImportMap<'a>(IndexMap, ImportMapEntry<'a>>); + +impl<'a> ImportMap<'a> { + fn new(import_components: bool, graph: &'a CompositionGraph) -> Result { + let mut imports = Self::default(); + + if import_components { + imports.add_component_imports(graph); + } + + imports.add_instantiation_imports(graph)?; + + Ok(imports) + } + + fn add_component_imports(&mut self, graph: &'a CompositionGraph) { + for entry in graph + .components + .values() + .filter(|e| !e.instances.is_empty()) + { + assert!(self + .0 + .insert( + entry.component.name.to_kebab_case().into(), + ImportMapEntry::Component(&entry.component), + ) + .is_none()); + } + } + + fn add_instantiation_imports(&mut self, graph: &'a CompositionGraph) -> Result<()> { + let mut imported = HashMap::new(); + + // Metadata about dependency edges used below during sorting (see + // below). + let mut component_defining_instance = HashMap::new(); + let mut deps = HashMap::new(); + + for (instance_index, instance) in graph.instances.values().enumerate() { + let (component_index, _, entry) = + graph.components.get_full(&instance.component).unwrap(); + let defining_instances = component_defining_instance + .entry(component_index) + .or_insert(HashMap::new()); + + let instance_index = InstanceIndex(instance_index); + + // Import any unconnected instantiation arguments for the instance + for (import_index, name, _) in entry.component.imports() { + if instance.connected.contains(&import_index) { + continue; + } + + let (_, ty) = entry.component.import_entity_type(import_index).unwrap(); + + let arg = ArgumentImport { + name, + kind: ArgumentImportKind::Item(&entry.component, ty), + instances: smallvec::smallvec![(instance_index, import_index)], + }; + + // Check to see if we've seen this import before; if so, don't bother with + // type checking, just add the instance to the list of instances + match imported.entry((component_index, import_index)) { + Entry::Occupied(e) => match self.0.get_index_mut(*e.get()).unwrap().1 { + ImportMapEntry::Component(_) => { + unreachable!("import should not be for a component") + } + ImportMapEntry::Argument(arg) => { + arg.instances.push((instance_index, import_index)); + } + }, + Entry::Vacant(e) => { + // If this is the first time an instance import is seen + // then register all of its dependencies on other + // imports. + // + // (see more below on this) + DependencyRegistrar { + types: &entry.component.types, + defining_instances, + cur: name, + deps: &mut deps, + } + .entity(ty); + let index = match self.0.entry(name.into()) { + indexmap::map::Entry::Occupied(mut e) => match e.get_mut() { + ImportMapEntry::Component(_) => { + bail!( + "cannot import {ty} `{name}` for an instantiation argument of component `{cname}` because it conflicts with a component imported with the same name", + ty = type_desc(ty), + cname = entry.component.name, + ); + } + ImportMapEntry::Argument(existing) => { + existing.merge(arg)?; + e.index() + } + }, + indexmap::map::Entry::Vacant(e) => { + let index = e.index(); + e.insert(ImportMapEntry::Argument(arg)); + index + } + }; + e.insert(index); + } + } + } + } + + // Before returning perform a topological sort of all dependencies to + // ensure that they're translated in the correct order for types to be + // connected. + // + // Why, might you be asking, is this necessary? Each component + // individually already has topologically sorted dependencies and + // they're all iterated through above, so what's the problem? + // + // The reason this loop arises is for when two different components + // are unioned together and a topological ordering between the union + // of the imports is required. While each component is sorted that's + // not enough to ensure everything is sorted. + // + // For example let's say there's three interfaces A, B, and C. C + // depends on both A and B. Then let's have one component import both A + // and C and a second component imports B and C. This can be valid where + // C can be "sliced up" where only the portions that depend on A can be + // separated from the portions that depend on B. + // When walking over the instances above we'll first generate imports + // of A and C. Next though the next instance will add and import for B, + // meaning that the import list is A, C, B. This is not a correct + // topological ordering, which is what this sort is solving. + let mut order = IndexSet::new(); + for (name, _) in self.0.iter() { + toposort(&name[..], &deps, &mut order); + } + let order = order + .into_iter() + .map(|s| s.to_string()) + .collect::>(); + self.0 + .sort_by_cached_key(|name, _| order.get_full(&name[..]).unwrap().0); + + Ok(()) + } +} + +/// Helper structure used to fill out the `deps` and `defining_instances` maps +/// when building the imports to a component. +/// +/// The goal of this structure is to take types defined within `self.cur` and +/// draw edges in the `deps` map from `cur` to those names in +/// `defining_instances`. +/// +/// For example if a type refers to a name defined in a different instance then +/// that previous instance will already be registered in `defining_instances` +/// and that'll draw a dependency from `self.cur` to that name. +struct DependencyRegistrar<'a, 'b> { + types: &'a types::Types, + defining_instances: &'b mut HashMap, + cur: &'a str, + deps: &'b mut HashMap<&'a str, Vec<&'a str>>, +} + +impl DependencyRegistrar<'_, '_> { + fn entity(&mut self, ty: ComponentEntityType) { + match ty { + ComponentEntityType::Type { + created, + referenced, + } => { + let prev = self.defining_instances.insert(created, self.cur); + assert!(prev.is_none()); + self.ty(referenced); + } + ComponentEntityType::Module(_) => {} + ComponentEntityType::Value(v) => self.val_type(v), + ComponentEntityType::Instance(e) => self.instance(e), + ComponentEntityType::Component(e) => self.component(e), + ComponentEntityType::Func(e) => self.func(e), + } + } + + fn ty(&mut self, ty: TypeId) { + match self.defining_instances.entry(ty) { + // If it's known where `ty` is defined then there's nothing else to + // do here beyond drawing a new dependency edge. Note though that + // "edges to self" are skipped explicitly here. + Entry::Occupied(e) => { + if *e.get() != self.cur { + self.deps.entry(self.cur).or_default().push(*e.get()); + } + return; + } + + // Otherwise `ty` is now registered as defined by `self.cur` and we + // continue below. + Entry::Vacant(e) => { + e.insert(self.cur); + } + } + + // Recurse for aliases to see edges across components, and otherwise + // recurse on the structure of the type below. + if let Some(ty) = self.types.peel_alias(ty) { + return self.ty(ty); + } + + match &self.types[ty] { + Type::Instance(_) | Type::Sub(_) | Type::Module(_) => {} + Type::Component(_) => self.component(ty), + Type::ComponentInstance(_) => self.instance(ty), + Type::ComponentFunc(_) => self.func(ty), + Type::Defined(_) => self.defined(ty), + Type::Resource(_) => {} + } + } + + fn val_type(&mut self, ty: types::ComponentValType) { + match ty { + types::ComponentValType::Type(t) => self.ty(t), + types::ComponentValType::Primitive(_) => {} + } + } + + fn component(&mut self, ty: TypeId) { + let ty = &self.types[ty].unwrap_component(); + for (_, ty) in ty.imports.iter().chain(&ty.exports) { + self.entity(*ty); + } + } + + fn instance(&mut self, ty: TypeId) { + for (_, ty) in self.types[ty].unwrap_component_instance().exports.iter() { + self.entity(*ty); + } + } + + fn func(&mut self, ty: TypeId) { + let ty = &self.types[ty].unwrap_component_func(); + for ty in ty + .params + .iter() + .map(|p| p.1) + .chain(ty.results.iter().map(|p| p.1)) + { + self.val_type(ty); + } + } + + fn defined(&mut self, ty: TypeId) { + match &self.types[ty].unwrap_defined() { + types::ComponentDefinedType::Primitive(_) + | types::ComponentDefinedType::Enum(_) + | types::ComponentDefinedType::Flags(_) => {} + types::ComponentDefinedType::List(t) | types::ComponentDefinedType::Option(t) => { + self.val_type(*t) + } + types::ComponentDefinedType::Own(t) | types::ComponentDefinedType::Borrow(t) => { + self.ty(*t) + } + types::ComponentDefinedType::Record(r) => { + for (_, ty) in r.fields.iter() { + self.val_type(*ty); + } + } + types::ComponentDefinedType::Tuple(r) => { + for ty in r.types.iter() { + self.val_type(*ty); + } + } + types::ComponentDefinedType::Variant(r) => { + for (_, case) in r.cases.iter() { + if let Some(ty) = case.ty { + self.val_type(ty); + } + } + } + types::ComponentDefinedType::Result { ok, err } => { + if let Some(ok) = ok { + self.val_type(*ok); + } + if let Some(err) = err { + self.val_type(*err); + } + } + } + } +} + +fn toposort<'a>( + cur: &'a str, + deps: &HashMap<&'a str, Vec<&'a str>>, + order: &mut IndexSet<&'a str>, +) { + if order.contains(cur) { + return; + } + if let Some(list) = deps.get(cur) { + for dep in list { + toposort(dep, deps, order); + } } + let ok = order.insert(cur); + assert!(ok); } -/// Used to encode an instantiation graph. -pub(crate) struct InstantiationGraphEncoder<'a> { - /// The associated composition configuration. - config: &'a Config, +/// Used to encode a composition graph as a new WebAssembly component. +pub(crate) struct CompositionGraphEncoder<'a> { + /// The options for the encoding. + options: EncodeOptions, /// The graph being encoded. - graph: &'a InstantiationGraph, + graph: &'a CompositionGraph<'a>, /// Map from graph component index to encoded component index. - component_indexes: HashMap, - /// Map from graph instance index to encoded instantiation index. - instance_indexes: HashMap, - /// The used import names during encoding. - imports: HashSet<&'a str>, - /// Map from an export on a graph instance to the aliased encoded instance index. - aliases: HashMap<(InstanceIndex, ExportIndex), u32>, - /// The number of modules encoded (i.e. current module index). - modules: u32, - /// The number of component functions encoded (i.e. current function index). - funcs: u32, - /// The number of values encoded (i.e. current value index). - values: u32, - /// The number of types encoded (i.e. current type index). - types: u32, - /// The number of component instances encoded (i.e. current instance index). - instances: u32, - /// The number of components encoded (i.e. current component index). - components: u32, + encoded_components: HashMap>, u32>, + /// Map from graph instance id to encoded instance index. + encoded_instances: HashMap, + /// Map from instance and import index to encoded item index. + /// + /// This is used for instantiation arguments that are imported. + imported_args: HashMap<(InstanceIndex, ImportIndex), u32>, + /// Map from instance id and export index to encoded item index. + /// + /// This is used to track instantiation arguments aliased from + /// other instances. + aliases: HashMap<(InstanceId, ExportIndex), u32>, } -impl<'a> InstantiationGraphEncoder<'a> { - /// Create a new encoder for the given graph. - pub(crate) fn new(config: &'a Config, graph: &'a InstantiationGraph) -> Self { +impl<'a> CompositionGraphEncoder<'a> { + pub(crate) fn new(options: EncodeOptions, graph: &'a CompositionGraph) -> Self { Self { - config, + options, graph, - component_indexes: Default::default(), - instance_indexes: Default::default(), - imports: Default::default(), + encoded_components: Default::default(), + encoded_instances: Default::default(), + imported_args: Default::default(), aliases: Default::default(), - modules: 0, - funcs: 0, - values: 0, - types: 0, - instances: 0, - components: 0, } } - /// Encodes the graph into a component. pub(crate) fn encode(mut self) -> Result> { - let mut encoded = wasm_encoder::Component::new(); - - // Encode the instances from the graph - for instance in self.graph.instantiation_order()? { - if let Some(component) = self.graph.component(instance) { - self.encode_instantiation(instance, component, &mut encoded)?; - continue; - } + let mut encoded = ComponentBuilder::default(); - if let Some(refs) = self.graph.import_refs(instance) { - self.encode_instance_import(instance, refs, &mut encoded)?; - continue; - } + self.encode_imports(&mut encoded)?; + self.encode_components(&mut encoded); + self.encode_instantiations(&mut encoded)?; - unreachable!("every instance in the graph should either be instantiated or imported"); + if let Some(id) = self.options.export { + self.encode_exports(&mut encoded, id)?; } - // Encode the exports from the root component - self.encode_exports(&mut encoded)?; - Ok(encoded.finish()) } - /// Encode an instance import in the given component. - fn encode_instance_import( - &mut self, - instance: InstanceIndex, - refs: &IndexSet, - encoded: &mut wasm_encoder::Component, - ) -> Result<()> { - // Build a map of export names to types; this will be used to encode - // the type of the imported instance - let mut exports: IndexMap<&String, (&crate::composer::Component, ComponentEntityType)> = - IndexMap::new(); - - let instance_name = self.graph.instance_name(instance); - if !self.imports.insert(instance_name) { - bail!("cannot import instance `{instance_name}` because it conflicts with an imported component of the same name"); - } - - for r in refs { - let (component, _, ty) = self.graph.resolve_import(*r); - let types = component.types(); - for (export_name, export_type) in ty.exports(types) { - match exports.entry(export_name) { - indexmap::map::Entry::Occupied(mut e) => { - // Export already exists, ensure the types are compatible - let (existing_component, existing_entity_type) = e.get(); - - // If the existing type is still a subtype, do nothing - if ComponentEntityType::is_subtype_of( - existing_entity_type, - existing_component.types(), - export_type, - types, - ) { - continue; + fn encode_imports(&mut self, encoded: &mut ComponentBuilder) -> Result<()> { + let imports = ImportMap::new(!self.options.define_components, self.graph)?; + + // Create new state to track where types are defined and in which + // instances. Temporarily "move" the `encoded` builder into this state. + let mut state = TypeState::new(); + state.cur.encodable = Encodable::Builder(mem::take(encoded)); + + for (name, entry) in imports.0 { + log::trace!("encoding instance import {name}"); + match entry { + ImportMapEntry::Component(component) => { + let encoded = match &mut state.cur.encodable { + Encodable::Builder(builder) => builder, + _ => unreachable!(), + }; + self.encode_component_import(encoded, name.as_ref(), component); + } + ImportMapEntry::Argument(arg) => { + let index = match arg.kind { + ArgumentImportKind::Item(component, ty) => { + self.encode_item_import(&mut state, name.as_ref(), component, ty) } - - // If the new type is the subtype, replace the existing type - if ComponentEntityType::is_subtype_of( - export_type, - types, - existing_entity_type, - existing_component.types(), - ) { - *e.get_mut() = (component, *export_type); - continue; + ArgumentImportKind::Instance(exports) => { + self.encode_instance_import(&mut state, name.as_ref(), exports) } + }; - // Otherwise, it's a conflict error - bail!( - "cannot import instance `{instance_name}` due to conflicting types for export `{export_name}` between components `{a}` and `{b}`", - a = existing_component.path().display(), - b = component.path().display() - ); - } - indexmap::map::Entry::Vacant(e) => { - e.insert((component, *export_type)); - } + self.imported_args + .extend(arg.instances.into_iter().map(|k| (k, index))); } } } - let mut instance_type = InstanceType::new(); - let mut types = HashMap::new(); - for (name, (component, ty)) in exports { - let encoder = TypeEncoder::new(component.types()); - let ty = encoder.component_entity_type(&mut instance_type, &mut types, ty); - instance_type.export(name, ty); + // "Move" the builder back out from the state into this function's + // parameter. + match &mut state.cur.encodable { + Encodable::Builder(builder) => *encoded = mem::take(builder), + _ => unreachable!(), } - let mut types = ComponentTypeSection::new(); - let type_index = self.types; - types.instance(&instance_type); - self.types += 1; - encoded.section(&types); - - let mut imports = ComponentImportSection::new(); - let instance_index = self.instances; - imports.import(instance_name, ComponentTypeRef::Instance(type_index)); - self.instances += 1; - encoded.section(&imports); + Ok(()) + } - log::debug!("importing instance `{instance_name}` (encoded index {instance_index})",); + fn encode_component_import( + &mut self, + encoded: &mut ComponentBuilder, + name: &str, + component: &'a crate::graph::Component, + ) -> u32 { + let type_index = self.define_component_type(encoded, component); + let index = self.import(encoded, name, ComponentTypeRef::Component(type_index)); - self.instance_indexes.insert(instance, instance_index); + assert!(self + .encoded_components + .insert(PtrKey(component), index) + .is_none()); - Ok(()) + index } - /// Encode a component instantiation in the given component. - fn encode_instantiation( + fn encode_item_import( &mut self, - instance: InstanceIndex, - component: &'a Component, - encoded: &mut wasm_encoder::Component, - ) -> Result<()> { - let instance_name = self.graph.instance_name(instance); - let dependency = self.config.dependency_name(instance_name); + state: &mut TypeState<'a>, + name: &str, + component: &'a crate::graph::Component, + ty: ComponentEntityType, + ) -> u32 { + log::trace!("encoding item import {name}"); + let encoder = TypeEncoder::new(component); + let ty = encoder.component_entity_type(state, ty); - // Encode the instance's component if it hasn't been encoded already - let component_index = match self.component_indexes.entry(component.index()) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let index = match component.import_name() { - Some(name) => { - if !self.imports.insert(name) { - bail!( - "cannot import dependency `{dependency}` (`{path}`) with name `{name}` because it conflicts with an imported instance or component of the same name", - path = component.path().display(), - ); - } + let encoded = match &mut state.cur.encodable { + Encodable::Builder(builder) => builder, + _ => unreachable!(), + }; + self.import(encoded, name, ty) + } - log::debug!( - "importing component `{dependency}` with name `{name}` (encoded index {component_index}", - component_index = self.components, - ); + fn encode_instance_import( + &mut self, + state: &mut TypeState<'a>, + name: &str, + exports: IndexMap<&'a str, Vec<(&'a crate::graph::Component, ComponentEntityType)>>, + ) -> u32 { + log::trace!("encoding instance import {name}"); + state.push(Encodable::Instance(InstanceType::new())); + for (name, types) in exports { + let (component, ty) = types[0]; + log::trace!("export {name}"); + let export = TypeEncoder::new(component).export(name, ty, state); + let t = match &mut state.cur.encodable { + Encodable::Instance(c) => c, + _ => unreachable!(), + }; + t.export(name, export); + + for (component, ty) in types.iter().skip(1) { + if let ComponentEntityType::Type { created, .. } = ty { + state + .cur + .add_type_export((PtrKey(component), *created), name); + } + } + } + let instance_type = match state.pop() { + Encodable::Instance(c) => c, + _ => unreachable!(), + }; - let mut types = ComponentTypeSection::new(); - let type_index = self.types; - types.component(&component.ty()); - self.types += 1; - encoded.section(&types); + let encoded = match &mut state.cur.encodable { + Encodable::Builder(builder) => builder, + _ => unreachable!(), + }; + let index = encoded.type_instance(&instance_type); + self.import(encoded, name, ComponentTypeRef::Instance(index)) + } - let mut imports = ComponentImportSection::new(); - let component_index = self.components; - imports.import(name, ComponentTypeRef::Component(type_index)); - self.components += 1; - encoded.section(&imports); + fn encode_instantiations(&mut self, encoded: &mut ComponentBuilder) -> Result<()> { + let ordering = self.graph.instantiation_order()?; + + // Encode the independent instances first + for id in self + .graph + .instances + .keys() + .filter(|id| !ordering.contains(*id)) + { + self.encode_instantiation(encoded, *id)?; + } - component_index - } - None => { - let component_index = self.components; - log::debug!("defining component `{dependency}` in composed component (encoded index {component_index})"); + // Encode the dependent instances last + for id in ordering { + self.encode_instantiation(encoded, id)?; + } - encoded.section(&RawSection { - id: ComponentSectionId::Component.into(), - data: component.bytes(), - }); + Ok(()) + } - self.components += 1; - component_index - } - }; + fn encode_exports( + &mut self, + encoded: &mut ComponentBuilder, + instance_id: InstanceId, + ) -> Result<()> { + let instance = self.graph.instances.get(&instance_id).ok_or_else(|| { + anyhow!("cannot export specified instance because it does not exist in the graph") + })?; + let entry = self.graph.components.get(&instance.component).unwrap(); + + let encoded_instance_index = self.encoded_instances[&instance_id]; + + for (export_index, export_name, kind, _) in entry.component.exports() { + let kind = match kind { + ComponentExternalKind::Module => ComponentExportKind::Module, + ComponentExternalKind::Func => ComponentExportKind::Func, + ComponentExternalKind::Value => ComponentExportKind::Value, + ComponentExternalKind::Type => ComponentExportKind::Type, + ComponentExternalKind::Instance => ComponentExportKind::Instance, + ComponentExternalKind::Component => ComponentExportKind::Component, + }; + + let index = match self.aliases.get(&(instance_id, export_index)) { + Some(index) => *index, + None => { + let index = self.alias(encoded, encoded_instance_index, export_name, kind); + self.aliases.insert((instance_id, export_index), index); + index + } + }; - *e.insert(index) - } - }; + encoded.export(export_name, kind, index, None); + } - let args = self.graph.instantiation_args(instance, |instance, export| { - let instance_index = self.instance_indexes[&instance]; + Ok(()) + } - // Check if we're aliasing an export from the instance - match export { - Some(export) => match self.aliases.entry((instance, export)) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let name = self.graph.component(instance).unwrap().export(export).0; - - let mut aliases = ComponentAliasSection::new(); - let alias_index = self.instances; - aliases.instance_export( - instance_index, - ComponentExportKind::Instance, - name, - ); - self.instances += 1; - encoded.section(&aliases); + fn encode_instantiation( + &mut self, + encoded: &mut ComponentBuilder, + instance_id: InstanceId, + ) -> Result<()> { + let (instance_index, _, instance) = self.graph.instances.get_full(&instance_id).unwrap(); + let entry = &self.graph.components.get(&instance.component).unwrap(); - log::debug!( - "aliasing instance export `{name}` from instance `{instance_name}` (encoded index {alias_index})", - instance_name = self.graph.instance_name(instance), - ); + let instance_index = InstanceIndex(instance_index); + let encoded_component_index = self.encoded_components[&PtrKey(&entry.component)]; - *e.insert(alias_index) - } - }, - None => instance_index, - } - }); + let args = self.instantiation_args(encoded, instance_index, &entry.component); log::debug!( - "instantiating component `{dependency}` as instance `{instance_name}` (encoded index {instance_index}) with {args:?}", - instance_index = self.instances, + "instantiating component `{name}` with {args:?}", + name = entry.component.name, ); - let mut instances = ComponentInstanceSection::new(); - let instance_index = self.instances; - instances.instantiate(component_index, args); - self.instances += 1; - encoded.section(&instances); + let encoded_instance_index = encoded.instantiate(encoded_component_index, args); - self.instance_indexes.insert(instance, instance_index); + self.encoded_instances + .insert(instance_id, encoded_instance_index); Ok(()) } - /// Encode the exports of the composed component. - /// - /// This always exports everything from the root (index 0) component. - fn encode_exports(&mut self, encoded: &mut wasm_encoder::Component) -> Result<()> { - let mut exports = ComponentExportSection::new(); - - // The root instance is always the first node in the graph - let instance = InstanceIndex::new(0); - let component = self.graph.component(instance).unwrap(); - let instance_index = self.instance_indexes[&instance]; - - // Alias all exports from the root instance - let mut aliases = ComponentAliasSection::new(); - for (name, kind, _) in component.exports() { - self.encode_alias_and_export(instance_index, name, kind, &mut aliases, &mut exports); + fn encode_components(&mut self, encoded: &mut ComponentBuilder) { + if !self.options.define_components { + return; } - if !aliases.is_empty() { - encoded.section(&aliases); + for entry in self + .graph + .components + .values() + .filter(|e| !e.instances.is_empty()) + { + let index = self.define_component(encoded, &entry.component); + assert!(self + .encoded_components + .insert(PtrKey(&entry.component), index) + .is_none()); } + } - if !exports.is_empty() { - encoded.section(&exports); - } + fn define_component_type( + &mut self, + encoded: &mut ComponentBuilder, + component: &crate::graph::Component, + ) -> u32 { + encoded.type_component(&component.ty()) + } - Ok(()) + fn define_component( + &mut self, + encoded: &mut ComponentBuilder, + component: &crate::graph::Component, + ) -> u32 { + log::debug!( + "defining component `{name}` in composed component", + name = component.name, + ); + encoded.component_raw(component.bytes()) } - /// Encode an alias for an instance export and then export the aliased item. - fn encode_alias_and_export( + fn instantiation_args( &mut self, - instance_index: u32, - name: &str, - kind: wasmparser::ComponentExternalKind, - aliases: &mut ComponentAliasSection, - exports: &mut ComponentExportSection, - ) { - let (indexes, kind) = match kind { - wasmparser::ComponentExternalKind::Module => { - (&mut self.modules, ComponentExportKind::Module) - } - wasmparser::ComponentExternalKind::Func => (&mut self.funcs, ComponentExportKind::Func), - wasmparser::ComponentExternalKind::Value => { - (&mut self.values, ComponentExportKind::Value) - } - wasmparser::ComponentExternalKind::Type => (&mut self.types, ComponentExportKind::Type), - wasmparser::ComponentExternalKind::Instance => { - (&mut self.instances, ComponentExportKind::Instance) + encoded: &mut ComponentBuilder, + instance_index: InstanceIndex, + component: &'a crate::graph::Component, + ) -> Vec<(&'a str, ComponentExportKind, u32)> { + let (instance_id, instance) = self.graph.instances.get_index(instance_index.0).unwrap(); + let mut args = Vec::with_capacity(component.imports.len()); + + // Add the arguments that are aliased exports from other instances + for (source_id, _, map) in self + .graph + .graph + .edges_directed(*instance_id, EdgeDirection::Incoming) + { + assert!(source_id != *instance_id); + let source_index = self.encoded_instances[&source_id]; + let (_, source_component) = &self.graph.get_component_of_instance(source_id).unwrap(); + + for (import_index, export_index) in map { + // Check to see if we need to alias the item from the source instance + let (name, ty) = component.import(*import_index).unwrap(); + let index = match export_index { + Some(export_index) => { + let (export_name, _, _) = source_component.export(*export_index).unwrap(); + match self.aliases.get(&(source_id, *export_index)) { + Some(index) => *index, + None => { + let index = self.alias( + encoded, + source_index, + export_name, + type_ref_to_export_kind(ty), + ); + self.aliases.insert((source_id, *export_index), index); + index + } + } + } + None => source_index, + }; + args.push((name, type_ref_to_export_kind(ty), index)); } - wasmparser::ComponentExternalKind::Component => { - (&mut self.components, ComponentExportKind::Component) + } + + // Finally, add any instantiation arguments that are being imported + for (i, (name, ty)) in component.imports.iter().enumerate() { + let import_index = ImportIndex(i); + if instance.connected.contains(&import_index) { + continue; } - }; - let index = *indexes; - aliases.instance_export(instance_index, kind, name); - *indexes += 1; - exports.export(name, kind, index); + let index = self.imported_args[&(instance_index, import_index)]; + args.push((name.as_str(), type_ref_to_export_kind(*ty), index)); + } + + args + } + + fn import(&mut self, encoded: &mut ComponentBuilder, name: &str, ty: ComponentTypeRef) -> u32 { + log::debug!("importing {ty:?} with `{name}` in composed component"); + encoded.import(name, ty) + } + + fn alias( + &mut self, + encoded: &mut ComponentBuilder, + instance: u32, + name: &str, + kind: ComponentExportKind, + ) -> u32 { + log::debug!( + "aliasing {kind:?} export `{name}` from encoded index {instance} in composed component" + ); + encoded.alias_export(instance, name, kind) } } diff --git a/crates/wasm-compose/src/graph.rs b/crates/wasm-compose/src/graph.rs new file mode 100644 index 0000000000..1f025c1e71 --- /dev/null +++ b/crates/wasm-compose/src/graph.rs @@ -0,0 +1,1349 @@ +//! Module for WebAssembly composition graphs. +use crate::encoding::{CompositionGraphEncoder, TypeEncoder}; +use anyhow::{anyhow, bail, Context, Result}; +use indexmap::{IndexMap, IndexSet}; +use petgraph::{algo::toposort, graphmap::DiGraphMap, EdgeDirection}; +use std::{ + borrow::Cow, + collections::{hash_map::Entry, HashMap, HashSet}, + path::{Path, PathBuf}, + sync::atomic::{AtomicUsize, Ordering}, +}; +use wasmparser::{ + types::{ComponentEntityType, TypeId, Types, TypesRef}, + Chunk, ComponentExternalKind, ComponentTypeRef, Encoding, Parser, Payload, ValidPayload, + Validator, WasmFeatures, +}; + +pub(crate) fn type_desc(item: ComponentEntityType) -> &'static str { + match item { + ComponentEntityType::Instance(_) => "instance", + ComponentEntityType::Module(_) => "module", + ComponentEntityType::Func(_) => "function", + ComponentEntityType::Value(_) => "value", + ComponentEntityType::Type { .. } => "type", + ComponentEntityType::Component(_) => "component", + } +} + +/// Represents a component in a composition graph. +pub struct Component<'a> { + /// The name of the component. + pub(crate) name: String, + /// The path to the component file if parsed via `Component::from_file`. + pub(crate) path: Option, + /// The raw bytes of the component. + pub(crate) bytes: Cow<'a, [u8]>, + /// The type information of the component. + pub(crate) types: Types, + /// The import map of the component. + pub(crate) imports: IndexMap, + /// The export map of the component. + pub(crate) exports: IndexMap, +} + +impl<'a> Component<'a> { + /// Constructs a new component from reading the given file. + pub fn from_file(name: impl Into, path: impl AsRef) -> Result { + let path = path.as_ref(); + log::info!("parsing WebAssembly component file `{}`", path.display()); + + let component = Self::parse( + name.into(), + Some(path.to_owned()), + wat::parse_file(path) + .with_context(|| { + format!("failed to parse component `{path}`", path = path.display()) + })? + .into(), + ) + .with_context(|| format!("failed to parse component `{path}`", path = path.display()))?; + + log::debug!( + "WebAssembly component `{path}` parsed:\n{component:#?}", + path = path.display() + ); + + Ok(component) + } + + /// Constructs a new component from the given bytes. + pub fn from_bytes(name: impl Into, bytes: impl Into>) -> Result { + let mut bytes = bytes.into(); + + match wat::parse_bytes(bytes.as_ref()).context("failed to parse component")? { + Cow::Borrowed(_) => { + // Original bytes were not modified + } + Cow::Owned(v) => bytes = v.into(), + } + + log::info!("parsing WebAssembly component from bytes"); + let component = + Self::parse(name.into(), None, bytes).context("failed to parse component")?; + + log::debug!("WebAssembly component parsed:\n{component:#?}",); + + Ok(component) + } + + fn parse(name: String, path: Option, bytes: Cow<'a, [u8]>) -> Result { + let mut parser = Parser::new(0); + let mut parsers = Vec::new(); + let mut validator = Validator::new_with_features(WasmFeatures { + component_model: true, + ..Default::default() + }); + let mut imports = IndexMap::new(); + let mut exports = IndexMap::new(); + + let mut cur = bytes.as_ref(); + loop { + match parser.parse(cur, true)? { + Chunk::Parsed { payload, consumed } => { + cur = &cur[consumed..]; + + match validator.payload(&payload)? { + ValidPayload::Ok => { + // Don't parse any sub-components or sub-modules + if !parsers.is_empty() { + continue; + } + + match payload { + Payload::Version { encoding, .. } => { + if encoding != Encoding::Component { + bail!( + "the {} is not a WebAssembly component", + if path.is_none() { "given data" } else { "file" } + ); + } + } + Payload::ComponentImportSection(s) => { + for import in s { + let import = import?; + let name = match import.name { + wasmparser::ComponentExternName::Kebab(s) + | wasmparser::ComponentExternName::Interface(s) => { + s.to_string() + } + }; + imports.insert(name, import.ty); + } + } + Payload::ComponentExportSection(s) => { + for export in s { + let export = export?; + let name = match export.name { + wasmparser::ComponentExternName::Kebab(s) + | wasmparser::ComponentExternName::Interface(s) => { + s.to_string() + } + }; + exports.insert(name, (export.kind, export.index)); + } + } + _ => {} + } + } + ValidPayload::Func(_, _) => {} + ValidPayload::Parser(next) => { + parsers.push(parser); + parser = next; + } + ValidPayload::End(types) => match parsers.pop() { + Some(parent) => parser = parent, + None => { + return Ok(Component { + name, + path, + bytes, + types, + imports, + exports, + }); + } + }, + } + } + Chunk::NeedMoreData(_) => unreachable!(), + } + } + } + + /// Gets the name of the component. + /// + /// Names must be unique within a composition graph. + pub fn name(&self) -> &str { + &self.name + } + + /// Gets the path of the component. + /// + /// Returns `None` if the component was not loaded from a file. + pub fn path(&self) -> Option<&Path> { + self.path.as_deref() + } + + /// Gets the bytes of the component. + pub fn bytes(&self) -> &[u8] { + self.bytes.as_ref() + } + + /// Gets the type information of the component. + pub fn types(&self) -> TypesRef { + self.types.as_ref() + } + + /// Gets an export from the component for the given export index. + pub fn export( + &self, + index: impl Into, + ) -> Option<(&str, ComponentExternalKind, u32)> { + let index = index.into(); + self.exports + .get_index(index.0) + .map(|(name, (kind, index))| (name.as_str(), *kind, *index)) + } + + /// Gets an export from the component for the given export name. + pub fn export_by_name(&self, name: &str) -> Option<(ExportIndex, ComponentExternalKind, u32)> { + self.exports + .get_full(name) + .map(|(i, _, (kind, index))| (ExportIndex(i), *kind, *index)) + } + + /// Gets an iterator over the component's exports. + pub fn exports( + &self, + ) -> impl ExactSizeIterator { + self.exports + .iter() + .enumerate() + .map(|(i, (name, (kind, index)))| (ExportIndex(i), name.as_str(), *kind, *index)) + } + + /// Gets an import from the component for the given import index. + pub fn import(&self, index: impl Into) -> Option<(&str, ComponentTypeRef)> { + let index = index.into(); + self.imports + .get_index(index.0) + .map(|(name, ty)| (name.as_str(), *ty)) + } + + /// Gets an import from the component for the given import name. + pub fn import_by_name(&self, name: &str) -> Option<(ImportIndex, ComponentTypeRef)> { + self.imports + .get_full(name) + .map(|(i, _, ty)| (ImportIndex(i), *ty)) + } + + /// Gets an iterator over the component's imports. + pub fn imports(&self) -> impl ExactSizeIterator { + self.imports + .iter() + .enumerate() + .map(|(i, (name, ty))| (ImportIndex(i), name.as_str(), *ty)) + } + + pub(crate) fn ty(&self) -> wasm_encoder::ComponentType { + let encoder = TypeEncoder::new(self); + + encoder.component( + &mut Default::default(), + self.imports() + .map(|(i, ..)| self.import_entity_type(i).unwrap()), + self.exports() + .map(|(i, ..)| self.export_entity_type(i).unwrap()), + ) + } + + pub(crate) fn export_entity_type( + &self, + index: ExportIndex, + ) -> Option<(&str, ComponentEntityType)> { + let (name, _kind, _index) = self.export(index)?; + Some((name, self.types.component_entity_type_of_export(name)?)) + } + + pub(crate) fn import_entity_type( + &self, + index: ImportIndex, + ) -> Option<(&str, ComponentEntityType)> { + let (name, _ty) = self.import(index)?; + Some((name, self.types.component_entity_type_of_import(name)?)) + } + + /// Finds a compatible instance export on the component for the given instance type. + pub(crate) fn find_compatible_export( + &self, + ty: TypeId, + types: TypesRef, + ) -> Option { + self.exports + .iter() + .position(|(_, (kind, index))| { + if *kind != ComponentExternalKind::Instance { + return false; + } + ComponentEntityType::is_subtype_of( + &ComponentEntityType::Instance(self.types.component_instance_at(*index)), + self.types(), + &ComponentEntityType::Instance(ty), + types, + ) + }) + .map(ExportIndex) + } + + /// Checks to see if an instance of this component would be a + /// subtype of the given instance type. + pub(crate) fn is_instance_subtype_of(&self, ty: TypeId, types: TypesRef) -> bool { + let exports = types[ty].unwrap_component_instance().exports.iter(); + + for (k, b) in exports { + match self.exports.get_full(k.as_str()) { + Some((ai, _, _)) => { + let (_, a) = self.export_entity_type(ExportIndex(ai)).unwrap(); + if !ComponentEntityType::is_subtype_of(&a, self.types(), b, types) { + return false; + } + } + None => return false, + } + } + + true + } +} + +impl std::fmt::Debug for Component<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("Component") + .field("imports", &self.imports) + .field("exports", &self.exports) + .finish_non_exhaustive() + } +} + +static NEXT_COMPONENT_ID: AtomicUsize = AtomicUsize::new(0); + +/// Represents an identifier of a component in a composition graph. +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub struct ComponentId(pub usize); + +impl ComponentId { + fn next() -> Result { + let next = NEXT_COMPONENT_ID.fetch_add(1, Ordering::SeqCst); + if next == usize::MAX { + bail!("component limit reached"); + } + Ok(Self(next)) + } +} + +impl std::fmt::Display for ComponentId { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for ComponentId { + fn from(id: usize) -> Self { + Self(id) + } +} + +static NEXT_INSTANCE_ID: AtomicUsize = AtomicUsize::new(0); + +/// Represents an identifier of an instance in a composition graph. +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub struct InstanceId(pub usize); + +impl std::fmt::Display for InstanceId { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl InstanceId { + fn next() -> Result { + let next = NEXT_INSTANCE_ID.fetch_add(1, Ordering::SeqCst); + if next == usize::MAX { + bail!("instance limit reached"); + } + Ok(Self(next)) + } +} + +impl From for InstanceId { + fn from(id: usize) -> Self { + Self(id) + } +} + +/// Represents an index into a component's import list. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct ImportIndex(pub usize); + +impl std::fmt::Display for ImportIndex { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for ImportIndex { + fn from(id: usize) -> Self { + Self(id) + } +} + +/// Represents an index into a component's export list. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct ExportIndex(pub usize); + +impl std::fmt::Display for ExportIndex { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for ExportIndex { + fn from(id: usize) -> Self { + Self(id) + } +} + +#[derive(Debug)] +pub(crate) struct ComponentEntry<'a> { + pub(crate) component: Component<'a>, + pub(crate) instances: HashSet, +} + +#[derive(Debug)] +pub(crate) struct Instance { + pub(crate) component: ComponentId, + pub(crate) connected: IndexSet, +} + +/// The options for encoding a composition graph. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] +pub struct EncodeOptions { + /// Whether or not to define instantiated components. + /// + /// If `false`, components will be imported instead. + pub define_components: bool, + + /// The instance in the graph to export. + /// + /// If `Some`, the instance's exports will be aliased and + /// exported from the resulting component. + pub export: Option, + + /// Whether or not to validate the encoded output. + pub validate: bool, +} + +/// Represents a composition graph used to compose a new component +/// from other components. +#[derive(Debug, Default)] +pub struct CompositionGraph<'a> { + names: HashMap, + pub(crate) components: IndexMap>, + pub(crate) instances: IndexMap, + // Map where each node is an instance in the graph. + // An edge between nodes stores a map of target import index to source export index. + // A source export index of `None` means that the source instance itself is being used. + pub(crate) graph: DiGraphMap>>, +} + +impl<'a> CompositionGraph<'a> { + /// Constructs a new composition graph. + pub fn new() -> Self { + Self::default() + } + + /// Adds a new component to the graph. + /// + /// The component name must be unique. + pub fn add_component(&mut self, component: Component<'a>) -> Result { + let id = match self.names.entry(component.name.clone()) { + Entry::Occupied(e) => { + bail!( + "a component with name `{name}` already exists", + name = e.key() + ) + } + Entry::Vacant(e) => *e.insert(ComponentId::next()?), + }; + + log::info!( + "adding WebAssembly component `{name}` ({id}) to the graph", + name = component.name(), + ); + + let entry = ComponentEntry { + component, + instances: HashSet::new(), + }; + + assert!(self.components.insert(id, entry).is_none()); + + Ok(id) + } + + /// Gets a component from the graph. + pub fn get_component(&self, id: impl Into) -> Option<&Component<'a>> { + self.components.get(&id.into()).map(|e| &e.component) + } + + /// Gets a component from the graph by name. + pub fn get_component_by_name(&self, name: &str) -> Option<(ComponentId, &Component<'a>)> { + let id = self.names.get(name)?; + let entry = &self.components[id]; + Some((*id, &entry.component)) + } + + /// Removes a component from the graph. + /// + /// All instances and connections relating to the component + /// will also be removed. + pub fn remove_component(&mut self, id: impl Into) { + let id = id.into(); + if let Some(entry) = self.components.remove(&id) { + log::info!( + "removing WebAssembly component `{name}` ({id}) from the graph", + name = entry.component.name(), + ); + + assert!(self.names.remove(&entry.component.name).is_some()); + + for instance_id in entry.instances.iter().copied() { + self.instances.remove(&instance_id); + + // Remove any connected indexes from outward edges from the instance being removed + for (_, target_id, map) in self + .graph + .edges_directed(instance_id, EdgeDirection::Outgoing) + { + let target = self.instances.get_mut(&target_id).unwrap(); + for index in map.keys() { + target.connected.remove(index); + } + } + + self.graph.remove_node(instance_id); + } + } + } + + /// Creates a new instance of a component in the composition graph. + pub fn instantiate(&mut self, id: impl Into) -> Result { + let id = id.into(); + let entry = self + .components + .get_mut(&id) + .ok_or_else(|| anyhow!("component does not exist in the graph"))?; + + let instance_id = InstanceId::next()?; + + log::info!( + "instantiating WebAssembly component `{name}` ({id}) with instance identifier {instance_id}", + name = entry.component.name(), + ); + + self.instances.insert( + instance_id, + Instance { + component: id, + connected: Default::default(), + }, + ); + + entry.instances.insert(instance_id); + + Ok(instance_id) + } + + /// Gets the component of the given instance. + pub fn get_component_of_instance( + &self, + id: impl Into, + ) -> Option<(ComponentId, &Component)> { + let id = id.into(); + let instance = self.instances.get(&id)?; + + Some(( + instance.component, + self.get_component(instance.component).unwrap(), + )) + } + + /// Removes an instance from the graph. + /// + /// All connections relating to the instance will also be removed. + pub fn remove_instance(&mut self, id: impl Into) { + let id = id.into(); + if let Some(instance) = self.instances.remove(&id) { + let entry = self.components.get_mut(&instance.component).unwrap(); + + log::info!( + "removing instance ({id}) of component `{name}` ({cid}) from the graph", + name = entry.component.name(), + cid = instance.component.0, + ); + + entry.instances.remove(&id); + + // Remove any connected indexes from outward edges from this instance + for (_, target, map) in self.graph.edges_directed(id, EdgeDirection::Outgoing) { + let target = self.instances.get_mut(&target).unwrap(); + for index in map.keys() { + target.connected.remove(index); + } + } + + self.graph.remove_node(id); + } + } + + /// Creates a connection (edge) between instances in the composition graph. + /// + /// A connection represents an instantiation argument. + /// + /// If `source_export` is `None`, the source instance itself + /// is used as the instantiation argument. + pub fn connect( + &mut self, + source: impl Into + Copy, + source_export: Option + Copy>, + target: impl Into + Copy, + target_import: impl Into + Copy, + ) -> Result<()> { + self.validate_connection(source, source_export, target, target_import)?; + + let source = source.into(); + let source_export = source_export.map(Into::into); + let target = target.into(); + let target_import = target_import.into(); + + match source_export { + Some(export) => log::info!("connecting export {export} of instance {source} to import `{target_import}` of instance {target}"), + None => log::info!("connecting instance {source} to import {target_import} of instance {target}"), + } + + self.instances + .get_mut(&target) + .unwrap() + .connected + .insert(target_import); + + if let Some(map) = self.graph.edge_weight_mut(source, target) { + assert!(map.insert(target_import, source_export).is_none()); + } else { + let mut map = IndexMap::new(); + map.insert(target_import, source_export); + self.graph.add_edge(source, target, map); + } + + Ok(()) + } + + /// Disconnects a previous connection between instances. + /// + /// Requires that the source and target instances are valid. + /// + /// If the source and target are not connected via the target's import, + /// then this is a no-op. + pub fn disconnect( + &mut self, + source: impl Into, + target: impl Into, + target_import: impl Into, + ) -> Result<()> { + let source = source.into(); + let target = target.into(); + let target_import = target_import.into(); + + log::info!("disconnecting import {target_import} of instance {target}"); + + if !self.instances.contains_key(&source) { + bail!("the source instance does not exist in the graph"); + } + + let target_instance = self + .instances + .get_mut(&target) + .ok_or_else(|| anyhow!("the target instance does not exist in the graph"))?; + + target_instance.connected.remove(&target_import); + + let remove_edge = if let Some(set) = self.graph.edge_weight_mut(source, target) { + set.remove(&target_import); + set.is_empty() + } else { + false + }; + + if remove_edge { + self.graph.remove_edge(source, target); + } + + Ok(()) + } + + /// Validates a connection between two instances in the graph. + /// + /// Use `None` for `source_export` to signify that the instance + /// itself should be the source for the connection. + /// + /// Returns `Err(_)` if the connection would not be valid. + pub fn validate_connection( + &self, + source: impl Into, + source_export: Option>, + target: impl Into, + target_import: impl Into, + ) -> Result<()> { + let source = source.into(); + let source_export = source_export.map(Into::into); + let target = target.into(); + let target_import = target_import.into(); + + if source == target { + bail!("an instance cannot be connected to itself"); + } + + let source_instance = self + .instances + .get(&source) + .ok_or_else(|| anyhow!("the source instance does not exist in the graph"))?; + + let source_component = &self.components[&source_instance.component].component; + + let target_instance = self + .instances + .get(&target) + .ok_or_else(|| anyhow!("the target instance does not exist in the graph"))?; + + let target_component = &self.components[&target_instance.component].component; + let (import_name, import_ty) = target_component + .import_entity_type(target_import) + .ok_or_else(|| anyhow!("the target import index is invalid"))?; + + if target_instance.connected.contains(&target_import) { + bail!( + "{import_ty} import `{import_name}` is already connected", + import_ty = type_desc(import_ty) + ); + } + + if let Some(export_index) = source_export { + let (export_name, export_ty) = source_component + .export_entity_type(export_index) + .ok_or_else(|| anyhow!("the source export index is invalid"))?; + + if !ComponentEntityType::is_subtype_of( + &export_ty, + source_component.types(), + &import_ty, + target_component.types(), + ) { + bail!( + "source {export_ty} export `{export_name}` is not compatible with target {import_ty} import `{import_name}`", + export_ty = type_desc(export_ty), + import_ty = type_desc(import_ty), + ); + } + } else { + let ty = match import_ty { + ComponentEntityType::Instance(id) => id, + _ => bail!( + "source instance is not compatible with target {import_ty} import `{import_name}`", + import_ty = type_desc(import_ty) + ), + }; + + if !source_component.is_instance_subtype_of(ty, target_component.types()) { + bail!( + "source instance is not compatible with target {import_ty} import `{import_name}`", + import_ty = type_desc(import_ty) + ); + } + }; + + Ok(()) + } + + /// Encodes the current composition graph as a WebAssembly component. + pub fn encode(&self, options: EncodeOptions) -> Result> { + let bytes = CompositionGraphEncoder::new(options, self).encode()?; + + if options.validate { + Validator::new_with_features(WasmFeatures { + component_model: true, + ..Default::default() + }) + .validate_all(&bytes) + .context("failed to validate encoded graph bytes")?; + } + + Ok(bytes) + } + + /// Gets the topological instantiation order based on the composition graph. + /// + /// If an instance is not in the returned set, it is considered to be + /// "independent" (i.e it has no dependencies on other instances). + pub(crate) fn instantiation_order(&self) -> Result> { + toposort(&self.graph, None).map_err(|e| { + let id = e.node_id(); + let instance = &self.instances[&id]; + anyhow!( + "an instantiation of component `{name}` and its dependencies form a cycle in the instantiation graph", + name = self.components[&instance.component].component.name, + ) + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + use pretty_assertions::assert_eq; + + #[test] + fn it_rejects_modules() -> Result<()> { + match Component::from_bytes("a", b"(module)".as_ref()) { + Ok(_) => panic!("expected a failure to parse"), + Err(e) => assert_eq!( + format!("{e:#}"), + "failed to parse component: the given data is not a WebAssembly component" + ), + } + + Ok(()) + } + + #[test] + fn it_rejects_invalid_components() -> Result<()> { + match Component::from_bytes("a", b"(component (export \"x\" (func 0)))".as_ref()) { + Ok(_) => panic!("expected a failure to parse"), + Err(e) => assert_eq!(format!("{e:#}"), "failed to parse component: unknown function 0: function index out of bounds (at offset 0xb)"), + } + + Ok(()) + } + + #[test] + fn it_ensures_unique_component_names() -> Result<()> { + let mut graph = CompositionGraph::new(); + graph.add_component(Component::from_bytes("a", b"(component)".as_ref())?)?; + + match graph.add_component(Component::from_bytes("a", b"(component)".as_ref())?) { + Ok(_) => panic!("expected a failure to add component"), + Err(e) => assert_eq!(format!("{e:#}"), "a component with name `a` already exists"), + } + + Ok(()) + } + + #[test] + fn it_fails_to_instantiate_a_missing_component() -> Result<()> { + let mut graph = CompositionGraph::new(); + match graph.instantiate(ComponentId(0)) { + Ok(_) => panic!("expected a failure to instantiate"), + Err(e) => assert_eq!(format!("{e:#}"), "component does not exist in the graph"), + } + + Ok(()) + } + + #[test] + fn it_instantiates_a_component() -> Result<()> { + let mut graph = CompositionGraph::new(); + let id = graph.add_component(Component::from_bytes("a", b"(component)".as_ref())?)?; + let id = graph.instantiate(id)?; + assert_eq!(graph.get_component_of_instance(id).unwrap().1.name(), "a"); + Ok(()) + } + + #[test] + fn it_cannot_get_a_component_of_missing_instance() -> Result<()> { + let graph = CompositionGraph::new(); + assert!(graph.get_component_of_instance(InstanceId(0)).is_none()); + Ok(()) + } + + #[test] + fn it_gets_a_component() -> Result<()> { + let mut graph = CompositionGraph::new(); + let id = graph.add_component(Component::from_bytes("a", b"(component)".as_ref())?)?; + assert_eq!(graph.get_component(id).unwrap().name(), "a"); + assert_eq!(graph.get_component_by_name("a").unwrap().1.name(), "a"); + Ok(()) + } + + #[test] + fn it_removes_a_component() -> Result<()> { + let mut graph = CompositionGraph::new(); + let a = graph.add_component(Component::from_bytes( + "a", + b"(component (import \"x\" (func)))".as_ref(), + )?)?; + let b = graph.add_component(Component::from_bytes( + "b", + b"(component (import \"x\" (func)) (export \"y\" (func 0)))".as_ref(), + )?)?; + let ai = graph.instantiate(a)?; + let bi = graph.instantiate(b)?; + graph.connect(bi, Some(0), ai, 0)?; + + assert!(graph.get_component(a).is_some()); + assert!(graph.get_component(b).is_some()); + assert_eq!(graph.components.len(), 2); + assert_eq!(graph.instances.len(), 2); + assert_eq!(graph.graph.node_count(), 2); + assert_eq!(graph.graph.edge_count(), 1); + + graph.remove_component(b); + + assert!(graph.get_component(a).is_some()); + assert!(graph.get_component(b).is_none()); + assert_eq!(graph.components.len(), 1); + assert_eq!(graph.instances.len(), 1); + assert_eq!(graph.graph.node_count(), 1); + assert_eq!(graph.graph.edge_count(), 0); + Ok(()) + } + + #[test] + fn it_removes_a_connection() -> Result<()> { + let mut graph = CompositionGraph::new(); + let a = graph.add_component(Component::from_bytes( + "a", + b"(component (import \"x\" (func)))".as_ref(), + )?)?; + let b = graph.add_component(Component::from_bytes( + "b", + b"(component (import \"x\" (func)) (export \"y\" (func 0)))".as_ref(), + )?)?; + let ai = graph.instantiate(a)?; + let bi = graph.instantiate(b)?; + graph.connect(bi, Some(0), ai, 0)?; + + assert_eq!(graph.graph.node_count(), 2); + assert_eq!(graph.graph.edge_count(), 1); + + graph.disconnect(bi, ai, 0)?; + + assert_eq!(graph.graph.node_count(), 2); + assert_eq!(graph.graph.edge_count(), 0); + Ok(()) + } + + #[test] + fn it_requires_source_to_disconnect() -> Result<()> { + let mut graph = CompositionGraph::new(); + let a = graph.add_component(Component::from_bytes( + "a", + b"(component (import \"x\" (func)))".as_ref(), + )?)?; + let b = graph.add_component(Component::from_bytes( + "b", + b"(component (import \"x\" (func)) (export \"y\" (func 0)))".as_ref(), + )?)?; + let ai = graph.instantiate(a)?; + let bi = graph.instantiate(b)?; + graph.connect(bi, Some(0), ai, 0)?; + + match graph.disconnect(101, ai, 0) { + Ok(_) => panic!("expected a failure to disconnect"), + Err(e) => assert_eq!( + format!("{e:#}"), + "the source instance does not exist in the graph" + ), + } + + Ok(()) + } + + #[test] + fn it_requires_a_target_to_disconnect() -> Result<()> { + let mut graph = CompositionGraph::new(); + let a = graph.add_component(Component::from_bytes( + "a", + b"(component (import \"x\" (func)))".as_ref(), + )?)?; + let b = graph.add_component(Component::from_bytes( + "b", + b"(component (import \"x\" (func)) (export \"y\" (func 0)))".as_ref(), + )?)?; + let ai = graph.instantiate(a)?; + let bi = graph.instantiate(b)?; + graph.connect(bi, Some(0), ai, 0)?; + + match graph.disconnect(bi, 101, 0) { + Ok(_) => panic!("expected a failure to disconnect"), + Err(e) => assert_eq!( + format!("{e:#}"), + "the target instance does not exist in the graph" + ), + } + + Ok(()) + } + + #[test] + fn it_validates_connections() -> Result<()> { + let mut graph = CompositionGraph::new(); + let a = graph.add_component(Component::from_bytes( + "a", + b"(component (import \"i1\" (func)) (import \"i2\" (instance (export \"no\" (func)))))" + .as_ref(), + )?)?; + let b = graph.add_component(Component::from_bytes( + "b", + b"(component (import \"i1\" (func)) (import \"i2\" (core module)) (export \"e1\" (func 0)) (export \"e2\" (core module 0)))".as_ref(), + )?)?; + let ai = graph.instantiate(a)?; + let bi = graph.instantiate(b)?; + + match graph.connect(ai, None::, ai, 0) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!( + format!("{e:#}"), + "an instance cannot be connected to itself" + ), + } + + match graph.connect(ai, Some(0), bi, 0) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!(format!("{e:#}"), "the source export index is invalid"), + } + + match graph.connect(101, Some(0), ai, 0) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!( + format!("{e:#}"), + "the source instance does not exist in the graph" + ), + } + + match graph.connect(bi, Some(0), 101, 0) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!( + format!("{e:#}"), + "the target instance does not exist in the graph" + ), + } + + match graph.connect(bi, Some(101), ai, 0) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!(format!("{e:#}"), "the source export index is invalid"), + } + + match graph.connect(bi, Some(0), ai, 101) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!(format!("{e:#}"), "the target import index is invalid"), + } + + match graph.connect(bi, Some(1), ai, 0) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!( + format!("{e:#}"), + "source module export `e2` is not compatible with target function import `i1`" + ), + } + + match graph.connect(bi, None::, ai, 0) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!( + format!("{e:#}"), + "source instance is not compatible with target function import `i1`" + ), + } + + match graph.connect(bi, None::, ai, 1) { + Ok(_) => panic!("expected a failure to connect"), + Err(e) => assert_eq!( + format!("{e:#}"), + "source instance is not compatible with target instance import `i2`" + ), + } + + Ok(()) + } + + #[test] + fn it_cannot_encode_a_cycle() -> Result<()> { + let mut graph = CompositionGraph::new(); + let a = graph.add_component(Component::from_bytes( + "a", + b"(component (import \"i1\" (func)) (export \"e1\" (func 0)))".as_ref(), + )?)?; + let b = graph.add_component(Component::from_bytes( + "b", + b"(component (import \"i1\" (func)) (export \"e1\" (func 0)))".as_ref(), + )?)?; + let ai = graph.instantiate(a)?; + let bi = graph.instantiate(b)?; + + graph.connect(ai, Some(0), bi, 0)?; + graph.connect(bi, Some(0), ai, 0)?; + + match graph.encode(EncodeOptions { + define_components: false, + export: None, + validate: true, + }) { + Ok(_) => panic!("graph should not encode"), + Err(e) => assert_eq!(format!("{e:#}"), "an instantiation of component `b` and its dependencies form a cycle in the instantiation graph"), + } + + Ok(()) + } + + #[test] + fn it_encodes_an_empty_component() -> Result<()> { + let mut graph = CompositionGraph::new(); + graph.add_component(Component::from_bytes("a", b"(component)".as_ref())?)?; + graph.add_component(Component::from_bytes("b", b"(component)".as_ref())?)?; + + let encoded = graph.encode(EncodeOptions { + define_components: false, + export: None, + validate: true, + })?; + + let wat = wasmprinter::print_bytes(encoded)?; + assert_eq!(r#"(component)"#, wat); + + Ok(()) + } + + #[test] + fn it_encodes_component_imports() -> Result<()> { + let mut graph = CompositionGraph::new(); + // Add a component that doesn't get instantiated (shouldn't be imported) + graph.add_component(Component::from_bytes("a", b"(component)".as_ref())?)?; + let b = graph.add_component(Component::from_bytes("b", b"(component)".as_ref())?)?; + graph.instantiate(b)?; + + let encoded = graph.encode(EncodeOptions { + define_components: false, + export: None, + validate: true, + })?; + + let wat = wasmprinter::print_bytes(encoded)?.replace("\r\n", "\n"); + assert_eq!( + r#"(component + (type (;0;) + (component) + ) + (import "b" (component (;0;) (type 0))) + (instance (;0;) (instantiate 0)) +)"#, + wat + ); + + Ok(()) + } + + #[test] + fn it_encodes_defined_components() -> Result<()> { + let mut graph = CompositionGraph::new(); + // Add a component that doesn't get instantiated (shouldn't be imported) + graph.add_component(Component::from_bytes("a", b"(component)".as_ref())?)?; + let b = graph.add_component(Component::from_bytes("b", b"(component)".as_ref())?)?; + graph.instantiate(b)?; + + let encoded = graph.encode(EncodeOptions { + define_components: true, + export: None, + validate: true, + })?; + + let wat = wasmprinter::print_bytes(encoded)?.replace("\r\n", "\n"); + assert_eq!( + r#"(component + (component (;0;)) + (instance (;0;) (instantiate 0)) +)"#, + wat + ); + + Ok(()) + } + + #[test] + fn it_encodes_a_simple_composition() -> Result<()> { + let mut graph = CompositionGraph::new(); + let a = graph.add_component(Component::from_bytes( + "a", + b"(component + (type (tuple u32 u32)) + (import \"i1\" (instance (export \"e1\" (func)) (export \"e3\" (func (param \"a\" u32))))) + (import \"i2\" (func)) + (import \"i3\" (component)) + (import \"i4\" (core module)) + (import \"i5\" (type (eq 0))) + (export \"e1\" (instance 0)) + (export \"e2\" (func 0)) + (export \"e3\" (component 0)) + (export \"e4\" (core module 0)) + (export \"e5\" (type 1)) +)" + .as_ref(), + )?)?; + let b = graph.add_component(Component::from_bytes( + "b", + b"(component + (type (tuple u32 u32)) + (import \"i1\" (instance (export \"e2\" (func)) (export \"e3\" (func (param \"a\" u32))))) + (import \"i2\" (func)) + (import \"i3\" (component)) + (import \"i4\" (core module)) + (import \"i5\" (type (eq 0))) +)" + .as_ref(), + )?)?; + + let ai = graph.instantiate(a)?; + let bi1 = graph.instantiate(b)?; + let bi2 = graph.instantiate(b)?; + let bi3 = graph.instantiate(b)?; + + // Skip the instance arguments so a merged instance is imported + for i in 1..=3 { + graph.connect(ai, Some(i), bi1, i)?; + graph.connect(ai, Some(i), bi2, i)?; + graph.connect(ai, Some(i), bi3, i)?; + } + + let encoded = graph.encode(EncodeOptions { + define_components: true, + export: None, + validate: true, + })?; + + let wat = wasmprinter::print_bytes(encoded)?.replace("\r\n", "\n"); + assert_eq!( + r#"(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "e1" (func (type 0))) + (type (;1;) (func (param "a" u32))) + (export (;1;) "e3" (func (type 1))) + (type (;2;) (func)) + (export (;2;) "e2" (func (type 2))) + ) + ) + (import "i1" (instance (;0;) (type 0))) + (type (;1;) (func)) + (import "i2" (func (;0;) (type 1))) + (type (;2;) + (component) + ) + (import "i3" (component (;0;) (type 2))) + (core type (;0;) + (module) + ) + (import "i4" (core module (;0;) (type 0))) + (type (;3;) (tuple u32 u32)) + (import "i5" (type (;4;) (eq 3))) + (component (;1;) + (type (;0;) (tuple u32 u32)) + (type (;1;) + (instance + (type (;0;) (func)) + (export (;0;) "e1" (func (type 0))) + (type (;1;) (func (param "a" u32))) + (export (;1;) "e3" (func (type 1))) + ) + ) + (import "i1" (instance (;0;) (type 1))) + (type (;2;) (func)) + (import "i2" (func (;0;) (type 2))) + (type (;3;) + (component) + ) + (import "i3" (component (;0;) (type 3))) + (core type (;0;) + (module) + ) + (import "i4" (core module (;0;) (type 0))) + (import "i5" (type (;4;) (eq 0))) + (export (;1;) "e1" (instance 0)) + (export (;1;) "e2" (func 0)) + (export (;1;) "e3" (component 0)) + (export (;1;) "e4" (core module 0)) + (export (;5;) "e5" (type 1)) + ) + (component (;2;) + (type (;0;) (tuple u32 u32)) + (type (;1;) + (instance + (type (;0;) (func)) + (export (;0;) "e2" (func (type 0))) + (type (;1;) (func (param "a" u32))) + (export (;1;) "e3" (func (type 1))) + ) + ) + (import "i1" (instance (;0;) (type 1))) + (type (;2;) (func)) + (import "i2" (func (;0;) (type 2))) + (type (;3;) + (component) + ) + (import "i3" (component (;0;) (type 3))) + (core type (;0;) + (module) + ) + (import "i4" (core module (;0;) (type 0))) + (import "i5" (type (;4;) (eq 0))) + ) + (instance (;1;) (instantiate 1 + (with "i1" (instance 0)) + (with "i2" (func 0)) + (with "i3" (component 0)) + (with "i4" (core module 0)) + (with "i5" (type 4)) + ) + ) + (alias export 1 "e2" (func (;1;))) + (alias export 1 "e3" (component (;3;))) + (alias export 1 "e4" (core module (;1;))) + (instance (;2;) (instantiate 2 + (with "i2" (func 1)) + (with "i3" (component 3)) + (with "i4" (core module 1)) + (with "i1" (instance 0)) + (with "i5" (type 4)) + ) + ) + (instance (;3;) (instantiate 2 + (with "i2" (func 1)) + (with "i3" (component 3)) + (with "i4" (core module 1)) + (with "i1" (instance 0)) + (with "i5" (type 4)) + ) + ) + (instance (;4;) (instantiate 2 + (with "i2" (func 1)) + (with "i3" (component 3)) + (with "i4" (core module 1)) + (with "i1" (instance 0)) + (with "i5" (type 4)) + ) + ) +)"#, + wat + ); + + Ok(()) + } +} diff --git a/crates/wasm-compose/src/lib.rs b/crates/wasm-compose/src/lib.rs index affea3c340..2833f4a29b 100644 --- a/crates/wasm-compose/src/lib.rs +++ b/crates/wasm-compose/src/lib.rs @@ -2,8 +2,7 @@ #![deny(missing_docs)] -#[cfg(feature = "cli")] -pub mod cli; pub mod composer; pub mod config; pub(crate) mod encoding; +pub mod graph; diff --git a/crates/wasm-compose/tests/.gitignore b/crates/wasm-compose/tests/.gitignore new file mode 100644 index 0000000000..9365962f41 --- /dev/null +++ b/crates/wasm-compose/tests/.gitignore @@ -0,0 +1,2 @@ +!*.wasm +!*.wat diff --git a/crates/wasm-compose/tests/compose.rs b/crates/wasm-compose/tests/compose.rs index 6e30626f8f..118ffeaa0b 100644 --- a/crates/wasm-compose/tests/compose.rs +++ b/crates/wasm-compose/tests/compose.rs @@ -1,6 +1,7 @@ use anyhow::{bail, Context, Result}; use pretty_assertions::assert_eq; use std::fs; +use std::io; use wasm_compose::{composer::ComponentComposer, config::Config}; use wasmparser::{Validator, WasmFeatures}; @@ -33,6 +34,7 @@ fn component_composing() -> Result<()> { } let test_case = path.file_stem().unwrap().to_str().unwrap(); + println!("================ {test_case:30} ==============="); let root_path = path.join("root.wat"); let output_path = path.join("composed.wat"); let error_path = path.join("error.txt"); @@ -51,13 +53,29 @@ fn component_composing() -> Result<()> { let (output, baseline_path) = if error_path.is_file() { match r { Ok(_) => bail!("composition should fail for test case `{}`", test_case), - Err(e) => ( - format!("{:?}", e).replace('\\', "/").replace( - "The system cannot find the file specified.", - "No such file or directory", - ), - &error_path, - ), + Err(e) => { + let mut err = format!("{e}"); + let causes = e.chain(); + let ncauses = causes.len(); + if ncauses > 1 { + err.push_str("\n\nCaused by:"); + } + for (i, cause) in causes.skip(1).enumerate() { + err.push_str("\n "); + if ncauses > 2 { + err.push_str(&format!("{i}: ")) + } + match cause.downcast_ref::() { + Some(_) => { + err.push_str("platform-specific error"); + } + None => { + err.push_str(&cause.to_string()); + } + } + } + (err.replace('\\', "/"), &error_path) + } } } else { let bytes = @@ -75,6 +93,13 @@ fn component_composing() -> Result<()> { ) })?; + wit_component::decode(&bytes).with_context(|| { + format!( + "failed to decode WIT from component bytes for test case `{}`", + test_case + ) + })?; + ( wasmprinter::print_bytes(&bytes).with_context(|| { format!( @@ -87,10 +112,10 @@ fn component_composing() -> Result<()> { }; if std::env::var_os("BLESS").is_some() { - fs::write(&baseline_path, output + "\n")?; + fs::write(baseline_path, output + "\n")?; } else { assert_eq!( - fs::read_to_string(&baseline_path) + fs::read_to_string(baseline_path) .with_context(|| format!( "failed to read component baseline `{}`", baseline_path.display() diff --git a/crates/wasm-compose/tests/compositions/complex-import/composed.wat b/crates/wasm-compose/tests/compositions/complex-import/composed.wat index ef0bb42544..3466f2c287 100644 --- a/crates/wasm-compose/tests/compositions/complex-import/composed.wat +++ b/crates/wasm-compose/tests/compositions/complex-import/composed.wat @@ -1,139 +1,155 @@ (component - (type (;0;) + (type (;0;) (component - (type (;0;) (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) - (export "record1" (type (eq 0))) - (type (;1;) (flags "a" "b" "c")) - (export "flags1" (type (eq 1))) - (type (;2;) (enum "a" "b" "c")) - (export "enum1" (type (eq 2))) - (type (;3;) (union s8 string 0)) - (export "union1" (type (eq 3))) - (type (;4;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 0))) - (export "variant1" (type (eq 4))) - (type (;5;) (func)) - (export "a" (func (type 5))) - (type (;6;) (func (param "x" s8))) - (export "b" (func (type 6))) - (type (;7;) (func (param "x" u8))) - (export "c" (func (type 7))) - (type (;8;) (func (param "x" s16))) - (export "d" (func (type 8))) - (type (;9;) (func (param "x" u16))) - (export "e" (func (type 9))) - (type (;10;) (func (param "x" s32))) - (export "f" (func (type 10))) - (type (;11;) (func (param "x" u32))) - (export "g" (func (type 11))) - (type (;12;) (func (param "x" s64))) - (export "h" (func (type 12))) - (type (;13;) (func (param "x" u64))) - (export "i" (func (type 13))) - (type (;14;) (func (param "x" float32))) - (export "j" (func (type 14))) - (type (;15;) (func (param "x" float64))) - (export "k" (func (type 15))) - (type (;16;) (func (param "x" bool))) - (export "l" (func (type 16))) - (type (;17;) (func (param "x" string))) - (export "m" (func (type 17))) - (type (;18;) (func (param "x" 0))) - (export "n" (func (type 18))) - (type (;19;) (list 0)) - (type (;20;) (func (param "x" 19))) - (export "o" (func (type 20))) - (type (;21;) (tuple 0 string)) - (type (;22;) (func (param "x" 21))) - (export "p" (func (type 22))) - (type (;23;) (func (param "x" 1))) - (export "q" (func (type 23))) - (type (;24;) (func (param "x" 2))) - (export "r" (func (type 24))) - (type (;25;) (func (param "x" 3))) - (export "s" (func (type 25))) - (type (;26;) (option 4)) - (type (;27;) (func (param "x" 26))) - (export "t" (func (type 27))) - (type (;28;) (result 0 (error string))) - (type (;29;) (func (result 28))) - (export "u" (func (type 29))) + (type (;0;) + (instance + (type (;0;) (func (param "x" string) (result string))) + (export (;0;) "m" (func (type 0))) + ) + ) + (import "b1" (instance (;0;) (type 0))) + (import "b2" (instance (;1;) (type 0))) + (type (;1;) (func (param "x" string) (result string))) + (export (;0;) "m1" (func (type 1))) + (export (;1;) "m2" (func (type 1))) ) ) - (import "a" (component (;0;) (type 0))) - (instance (;0;) (instantiate 0)) - (type (;1;) + (import "input" (component (;0;) (type 0))) + (type (;1;) (component - (type (;0;) + (type (;0;) (instance (type (;0;) (func)) - (export "a" (func (type 0))) + (export (;0;) "a" (func (type 0))) (type (;1;) (func (param "x" s8))) - (export "b" (func (type 1))) + (export (;1;) "b" (func (type 1))) (type (;2;) (func (param "x" u8))) - (export "c" (func (type 2))) + (export (;2;) "c" (func (type 2))) (type (;3;) (func (param "x" s16))) - (export "d" (func (type 3))) + (export (;3;) "d" (func (type 3))) (type (;4;) (func (param "x" u16))) - (export "e" (func (type 4))) + (export (;4;) "e" (func (type 4))) (type (;5;) (func (param "x" s32))) - (export "f" (func (type 5))) + (export (;5;) "f" (func (type 5))) (type (;6;) (func (param "x" u32))) - (export "g" (func (type 6))) + (export (;6;) "g" (func (type 6))) (type (;7;) (func (param "x" s64))) - (export "h" (func (type 7))) + (export (;7;) "h" (func (type 7))) (type (;8;) (func (param "x" u64))) - (export "i" (func (type 8))) + (export (;8;) "i" (func (type 8))) (type (;9;) (func (param "x" float32))) - (export "j" (func (type 9))) + (export (;9;) "j" (func (type 9))) (type (;10;) (func (param "x" float64))) - (export "k" (func (type 10))) + (export (;10;) "k" (func (type 10))) (type (;11;) (func (param "x" bool))) - (export "l" (func (type 11))) + (export (;11;) "l" (func (type 11))) (type (;12;) (func (param "x" string))) - (export "m" (func (type 12))) + (export (;12;) "m" (func (type 12))) (type (;13;) (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) - (export "record1" (type (eq 13))) - (type (;14;) (func (param "x" 13))) - (export "n" (func (type 14))) - (type (;15;) (list 13)) - (type (;16;) (func (param "x" 15))) - (export "o" (func (type 16))) - (type (;17;) (tuple 13 string)) - (type (;18;) (func (param "x" 17))) - (export "p" (func (type 18))) - (type (;19;) (flags "a" "b" "c")) - (export "flags1" (type (eq 19))) - (type (;20;) (func (param "x" 19))) - (export "q" (func (type 20))) - (type (;21;) (enum "a" "b" "c")) - (export "enum1" (type (eq 21))) + (export (;14;) "record1" (type (eq 13))) + (type (;15;) (func (param "x" 14))) + (export (;13;) "n" (func (type 15))) + (type (;16;) (list 14)) + (type (;17;) (func (param "x" 16))) + (export (;14;) "o" (func (type 17))) + (type (;18;) (tuple 14 string)) + (type (;19;) (func (param "x" 18))) + (export (;15;) "p" (func (type 19))) + (type (;20;) (flags "a" "b" "c")) + (export (;21;) "flags1" (type (eq 20))) (type (;22;) (func (param "x" 21))) - (export "r" (func (type 22))) - (type (;23;) (union s8 string 13)) - (export "union1" (type (eq 23))) - (type (;24;) (func (param "x" 23))) - (export "s" (func (type 24))) - (type (;25;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) - (export "variant1" (type (eq 25))) - (type (;26;) (option 25)) - (type (;27;) (func (param "x" 26))) - (export "t" (func (type 27))) - (type (;28;) (result 13 (error string))) - (type (;29;) (func (result 28))) - (export "u" (func (type 29))) + (export (;16;) "q" (func (type 22))) + (type (;23;) (enum "a" "b" "c")) + (export (;24;) "enum1" (type (eq 23))) + (type (;25;) (func (param "x" 24))) + (export (;17;) "r" (func (type 25))) + (type (;26;) (option 14)) + (export (;27;) "option1" (type (eq 26))) + (type (;28;) (func (param "x" 27))) + (export (;18;) "s" (func (type 28))) + (type (;29;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 14))) + (export (;30;) "variant1" (type (eq 29))) + (type (;31;) (option 30)) + (type (;32;) (func (param "x" 31))) + (export (;19;) "t" (func (type 32))) + (type (;33;) (result 14 (error string))) + (type (;34;) (func (result 33))) + (export (;20;) "u" (func (type 34))) ) ) - (import "a" (instance (type 0))) - (type (;1;) + (import "a" (instance (;0;) (type 0))) + (type (;1;) (instance (type (;0;) (func (param "x" string) (result string))) - (export "m" (func (type 0))) + (export (;0;) "m" (func (type 0))) ) ) - (export "x" (instance (type 1))) + (export (;1;) "x" (instance (type 1))) ) ) (import "b" (component (;1;) (type 1))) + (type (;2;) + (component + (type (;0;) (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) + (export (;1;) "record1" (type (eq 0))) + (type (;2;) (flags "a" "b" "c")) + (export (;3;) "flags1" (type (eq 2))) + (type (;4;) (enum "a" "b" "c")) + (export (;5;) "enum1" (type (eq 4))) + (type (;6;) (option 1)) + (export (;7;) "option1" (type (eq 6))) + (type (;8;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 1))) + (export (;9;) "variant1" (type (eq 8))) + (type (;10;) (func)) + (export (;0;) "a" (func (type 10))) + (type (;11;) (func (param "x" s8))) + (export (;1;) "b" (func (type 11))) + (type (;12;) (func (param "x" u8))) + (export (;2;) "c" (func (type 12))) + (type (;13;) (func (param "x" s16))) + (export (;3;) "d" (func (type 13))) + (type (;14;) (func (param "x" u16))) + (export (;4;) "e" (func (type 14))) + (type (;15;) (func (param "x" s32))) + (export (;5;) "f" (func (type 15))) + (type (;16;) (func (param "x" u32))) + (export (;6;) "g" (func (type 16))) + (type (;17;) (func (param "x" s64))) + (export (;7;) "h" (func (type 17))) + (type (;18;) (func (param "x" u64))) + (export (;8;) "i" (func (type 18))) + (type (;19;) (func (param "x" float32))) + (export (;9;) "j" (func (type 19))) + (type (;20;) (func (param "x" float64))) + (export (;10;) "k" (func (type 20))) + (type (;21;) (func (param "x" bool))) + (export (;11;) "l" (func (type 21))) + (type (;22;) (func (param "x" string))) + (export (;12;) "m" (func (type 22))) + (type (;23;) (func (param "x" 1))) + (export (;13;) "n" (func (type 23))) + (type (;24;) (list 1)) + (type (;25;) (func (param "x" 24))) + (export (;14;) "o" (func (type 25))) + (type (;26;) (tuple 1 string)) + (type (;27;) (func (param "x" 26))) + (export (;15;) "p" (func (type 27))) + (type (;28;) (func (param "x" 3))) + (export (;16;) "q" (func (type 28))) + (type (;29;) (func (param "x" 5))) + (export (;17;) "r" (func (type 29))) + (type (;30;) (func (param "x" 7))) + (export (;18;) "s" (func (type 30))) + (type (;31;) (option 9)) + (type (;32;) (func (param "x" 31))) + (export (;19;) "t" (func (type 32))) + (type (;33;) (result 1 (error string))) + (type (;34;) (func (result 33))) + (export (;20;) "u" (func (type 34))) + ) + ) + (import "a" (component (;2;) (type 2))) + (instance (;0;) (instantiate 2)) (instance (;1;) (instantiate 1 (with "a" (instance 0)) ) @@ -142,29 +158,15 @@ (with "a" (instance 0)) ) ) - (component (;2;) - (type (;0;) - (instance - (type (;0;) (func (param "x" string) (result string))) - (export "m" (func (type 0))) - ) - ) - (import "b1" (instance (;0;) (type 0))) - (import "b2" (instance (;1;) (type 0))) - (alias export 0 "m" (func (;0;))) - (alias export 1 "m" (func (;1;))) - (export "m1" (func 0)) - (export "m2" (func 1)) - ) - (alias export 1 "x" (instance (;3;))) - (alias export 2 "x" (instance (;4;))) - (instance (;5;) (instantiate 2 - (with "b2" (instance 3)) - (with "b1" (instance 4)) + (alias export 2 "x" (instance (;3;))) + (alias export 1 "x" (instance (;4;))) + (instance (;5;) (instantiate 0 + (with "b1" (instance 3)) + (with "b2" (instance 4)) ) ) (alias export 5 "m1" (func (;0;))) - (alias export 5 "m2" (func (;1;))) - (export "m1" (func 0)) - (export "m2" (func 1)) + (export (;1;) "m1" (func 0)) + (alias export 5 "m2" (func (;2;))) + (export (;3;) "m2" (func 2)) ) diff --git a/crates/wasm-compose/tests/compositions/complex-import/config.yml b/crates/wasm-compose/tests/compositions/complex-import/config.yml index b950b08664..4e474d794a 100644 --- a/crates/wasm-compose/tests/compositions/complex-import/config.yml +++ b/crates/wasm-compose/tests/compositions/complex-import/config.yml @@ -1,10 +1,7 @@ +import-components: true dependencies: - a: - path: ../complex/a.wat - import: a - b: - path: ../complex/b.wat - import: b + a: ../complex/a.wat + b: ../complex/b.wat instantiations: b1: diff --git a/crates/wasm-compose/tests/compositions/complex/a.wat b/crates/wasm-compose/tests/compositions/complex/a.wat index 3491a03dd2..f1d3170ff6 100644 --- a/crates/wasm-compose/tests/compositions/complex/a.wat +++ b/crates/wasm-compose/tests/compositions/complex/a.wat @@ -1,39 +1,39 @@ (component - (type (func)) - (type (func (param "x" s8))) - (type (func (param "x" u8))) - (type (func (param "x" s16))) - (type (func (param "x" u16))) - (type (func (param "x" s32))) - (type (func (param "x" u32))) - (type (func (param "x" s64))) - (type (func (param "x" u64))) - (type (func (param "x" float32))) - (type (func (param "x" float64))) - (type (func (param "x" bool))) - (type (func (param "x" string))) - (type (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) - (type (func (param "x" 13))) - (type (list 13)) - (type (func (param "x" 15))) - (type (tuple 13 string)) - (type (func (param "x" 17))) - (type (flags "a" "b" "c")) - (type (func (param "x" 19))) - (type (enum "a" "b" "c")) - (type (func (param "x" 21))) - (type (union s8 string 13)) - (type (func (param "x" 23))) - (type (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) - (type (option 25)) - (type (func (param "x" 26))) - (type (result 13 (error string))) - (type (func (result 28))) - (export "record1" (type 13)) - (export "flags1" (type 19)) - (export "enum1" (type 21)) - (export "union1" (type 23)) - (export "variant1" (type 25)) + (type $t0 (func)) + (type $t1 (func (param "x" s8))) + (type $t2 (func (param "x" u8))) + (type $t3 (func (param "x" s16))) + (type $t4 (func (param "x" u16))) + (type $t5 (func (param "x" s32))) + (type $t6 (func (param "x" u32))) + (type $t7 (func (param "x" s64))) + (type $t8 (func (param "x" u64))) + (type $t9 (func (param "x" float32))) + (type $t10 (func (param "x" float64))) + (type $t11 (func (param "x" bool))) + (type $t12 (func (param "x" string))) + (type $t13' (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) + (export $t13 "record1" (type $t13')) + (type $t14 (func (param "x" $t13))) + (type $t15 (list $t13)) + (type $t16 (func (param "x" $t15))) + (type $t17 (tuple $t13 string)) + (type $t18 (func (param "x" $t17))) + (type $t19' (flags "a" "b" "c")) + (export $t19 "flags1" (type $t19')) + (type $t20 (func (param "x" $t19))) + (type $t21' (enum "a" "b" "c")) + (export $t21 "enum1" (type $t21')) + (type $t22 (func (param "x" $t21))) + (type $t23' (option $t13)) + (export $t23 "option1" (type $t23')) + (type $t24 (func (param "x" $t23))) + (type $t25' (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" $t13))) + (export $t25 "variant1" (type $t25')) + (type $t26 (option $t25)) + (type $t27 (func (param "x" $t26))) + (type $t28 (result $t13 (error string))) + (type $t29 (func (result $t28))) (core module (func $a unreachable) (func $b (param i32) unreachable) @@ -83,69 +83,69 @@ (export "canonical_abi_realloc" (func $canonical_abi_realloc)) ) (core instance (instantiate 0)) - (alias core export 0 "memory" (core memory)) - (alias core export 0 "canonical_abi_realloc" (core func)) - (alias core export 0 "a" (core func)) - (alias core export 0 "b" (core func)) - (alias core export 0 "c" (core func)) - (alias core export 0 "d" (core func)) - (alias core export 0 "e" (core func)) - (alias core export 0 "f" (core func)) - (alias core export 0 "g" (core func)) - (alias core export 0 "h" (core func)) - (alias core export 0 "i" (core func)) - (alias core export 0 "j" (core func)) - (alias core export 0 "k" (core func)) - (alias core export 0 "l" (core func)) - (alias core export 0 "m" (core func)) - (alias core export 0 "n" (core func)) - (alias core export 0 "o" (core func)) - (alias core export 0 "p" (core func)) - (alias core export 0 "q" (core func)) - (alias core export 0 "r" (core func)) - (alias core export 0 "s" (core func)) - (alias core export 0 "t" (core func)) - (alias core export 0 "u" (core func)) - (func (type 0) (canon lift (core func 1))) - (func (type 1) (canon lift (core func 2))) - (func (type 2) (canon lift (core func 3))) - (func (type 3) (canon lift (core func 4))) - (func (type 4) (canon lift (core func 5))) - (func (type 5) (canon lift (core func 6))) - (func (type 6) (canon lift (core func 7))) - (func (type 7) (canon lift (core func 8))) - (func (type 8) (canon lift (core func 9))) - (func (type 9) (canon lift (core func 10))) - (func (type 10) (canon lift (core func 11))) - (func (type 11) (canon lift (core func 12))) - (func (type 12) (canon lift (core func 13) (memory 0) (realloc 0) string-encoding=utf8)) - (func (type 14) (canon lift (core func 14) (memory 0) (realloc 0) string-encoding=utf8)) - (func (type 16) (canon lift (core func 15) (memory 0) (realloc 0) string-encoding=utf8)) - (func (type 18) (canon lift (core func 16) (memory 0) (realloc 0) string-encoding=utf8)) - (func (type 20) (canon lift (core func 17))) - (func (type 22) (canon lift (core func 18))) - (func (type 24) (canon lift (core func 19) (memory 0) (realloc 0) string-encoding=utf8)) - (func (type 27) (canon lift (core func 20) (memory 0) (realloc 0) string-encoding=utf8)) - (func (type 29) (canon lift (core func 21) (memory 0) (realloc 0) string-encoding=utf8)) - (export "a" (func 0)) - (export "b" (func 1)) - (export "c" (func 2)) - (export "d" (func 3)) - (export "e" (func 4)) - (export "f" (func 5)) - (export "g" (func 6)) - (export "h" (func 7)) - (export "i" (func 8)) - (export "j" (func 9)) - (export "k" (func 10)) - (export "l" (func 11)) - (export "m" (func 12)) - (export "n" (func 13)) - (export "o" (func 14)) - (export "p" (func 15)) - (export "q" (func 16)) - (export "r" (func 17)) - (export "s" (func 18)) - (export "t" (func 19)) - (export "u" (func 20)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "canonical_abi_realloc" (core func (;0;))) + (alias core export 0 "a" (core func (;1;))) + (alias core export 0 "b" (core func (;2;))) + (alias core export 0 "c" (core func (;3;))) + (alias core export 0 "d" (core func (;4;))) + (alias core export 0 "e" (core func (;5;))) + (alias core export 0 "f" (core func (;6;))) + (alias core export 0 "g" (core func (;7;))) + (alias core export 0 "h" (core func (;8;))) + (alias core export 0 "i" (core func (;9;))) + (alias core export 0 "j" (core func (;10;))) + (alias core export 0 "k" (core func (;11;))) + (alias core export 0 "l" (core func (;12;))) + (alias core export 0 "m" (core func (;13;))) + (alias core export 0 "n" (core func (;14;))) + (alias core export 0 "o" (core func (;15;))) + (alias core export 0 "p" (core func (;16;))) + (alias core export 0 "q" (core func (;17;))) + (alias core export 0 "r" (core func (;18;))) + (alias core export 0 "s" (core func (;19;))) + (alias core export 0 "t" (core func (;20;))) + (alias core export 0 "u" (core func (;21;))) + (func (;0;) (type $t0) (canon lift (core func 1))) + (func (;1;) (type $t1) (canon lift (core func 2))) + (func (;2;) (type $t2) (canon lift (core func 3))) + (func (;3;) (type $t3) (canon lift (core func 4))) + (func (;4;) (type $t4) (canon lift (core func 5))) + (func (;5;) (type $t5) (canon lift (core func 6))) + (func (;6;) (type $t6) (canon lift (core func 7))) + (func (;7;) (type $t7) (canon lift (core func 8))) + (func (;8;) (type $t8) (canon lift (core func 9))) + (func (;9;) (type $t9) (canon lift (core func 10))) + (func (;10;) (type $t10) (canon lift (core func 11))) + (func (;11;) (type $t11) (canon lift (core func 12))) + (func (;12;) (type $t12) (canon lift (core func 13) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;13;) (type $t14) (canon lift (core func 14) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;14;) (type $t16) (canon lift (core func 15) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;15;) (type $t18) (canon lift (core func 16) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;16;) (type $t20) (canon lift (core func 17))) + (func (;17;) (type $t22) (canon lift (core func 18))) + (func (;18;) (type $t24) (canon lift (core func 19) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;19;) (type $t27) (canon lift (core func 20) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;20;) (type $t29) (canon lift (core func 21) (memory 0) (realloc 0) string-encoding=utf8)) + (export (;21;) "a" (func 0)) + (export (;22;) "b" (func 1)) + (export (;23;) "c" (func 2)) + (export (;24;) "d" (func 3)) + (export (;25;) "e" (func 4)) + (export (;26;) "f" (func 5)) + (export (;27;) "g" (func 6)) + (export (;28;) "h" (func 7)) + (export (;29;) "i" (func 8)) + (export (;30;) "j" (func 9)) + (export (;31;) "k" (func 10)) + (export (;32;) "l" (func 11)) + (export (;33;) "m" (func 12)) + (export (;34;) "n" (func 13)) + (export (;35;) "o" (func 14)) + (export (;36;) "p" (func 15)) + (export (;37;) "q" (func 16)) + (export (;38;) "r" (func 17)) + (export (;39;) "s" (func 18)) + (export (;40;) "t" (func 19)) + (export (;41;) "u" (func 20)) ) diff --git a/crates/wasm-compose/tests/compositions/complex/a.wit b/crates/wasm-compose/tests/compositions/complex/a.wit deleted file mode 100644 index cfdf4f6aa3..0000000000 --- a/crates/wasm-compose/tests/compositions/complex/a.wit +++ /dev/null @@ -1,78 +0,0 @@ -;; This is just to show the WIT definition of component `a`. - -a: func() -b: func(x: s8) -c: func(x: u8) -d: func(x: s16) -e: func(x: u16) -f: func(x: s32) -g: func(x: u32) -h: func(x: s64) -i: func(x: u64) -j: func(x: float32) -k: func(x: float64) -l: func(x: bool) -m: func(x: string) - -record record1 { - a: s8, - b: u8, - c: s16, - d: u16, - e: s32, - f: u32, - g: s64, - h: u64, - i: float32, - j: float64, - k: bool, - l: string, -} - -n: func(x: record1) - -variant variant1 { - a(s8), - b(u8), - c(s16), - d(u16), - e(s32), - f(u32), - g(s64), - h(u64), - i(float32), - j(float64), - k(bool), - l(string), - m(record1), -} - -o: func(x: list) -p: func(x: tuple) - -flags flags1 { - a, - b, - c -} - -q: func(x: flags1) - -enum enum1 { - a, - b, - c -} - -r: func(x: enum1) - -union union1 { - s8, - string, - record1 -} - -s: func(x: union1) - -t: func(x: option) -u: func() -> expected diff --git a/crates/wasm-compose/tests/compositions/complex/b.wat b/crates/wasm-compose/tests/compositions/complex/b.wat index 9c69e8fae1..86b9cf2b1e 100644 --- a/crates/wasm-compose/tests/compositions/complex/b.wat +++ b/crates/wasm-compose/tests/compositions/complex/b.wat @@ -1,93 +1,67 @@ (component - (type (func)) - (type (func (param "x" s8))) - (type (func (param "x" u8))) - (type (func (param "x" s16))) - (type (func (param "x" u16))) - (type (func (param "x" s32))) - (type (func (param "x" u32))) - (type (func (param "x" s64))) - (type (func (param "x" u64))) - (type (func (param "x" float32))) - (type (func (param "x" float64))) - (type (func (param "x" bool))) - (type (func (param "x" string))) - (type (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) - (type (func (param "x" 13))) - (type (list 13)) - (type (func (param "x" 15))) - (type (tuple 13 string)) - (type (func (param "x" 17))) - (type (flags "a" "b" "c")) - (type (func (param "x" 19))) - (type (enum "a" "b" "c")) - (type (func (param "x" 21))) - (type (union s8 string 13)) - (type (func (param "x" 23))) - (type (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) - (type (option 25)) - (type (func (param "x" 26))) - (type (result 13 (error string))) - (type (func (result 28))) - (type + (type $i1 (instance - (alias outer 1 0 (type)) - (export "a" (func (type 0))) - (alias outer 1 1 (type)) - (export "b" (func (type 1))) - (alias outer 1 2 (type)) - (export "c" (func (type 2))) - (alias outer 1 3 (type)) - (export "d" (func (type 3))) - (alias outer 1 4 (type)) - (export "e" (func (type 4))) - (alias outer 1 5 (type)) - (export "f" (func (type 5))) - (alias outer 1 6 (type)) - (export "g" (func (type 6))) - (alias outer 1 7 (type)) - (export "h" (func (type 7))) - (alias outer 1 8 (type)) - (export "i" (func (type 8))) - (alias outer 1 9 (type)) - (export "j" (func (type 9))) - (alias outer 1 10 (type)) - (export "k" (func (type 10))) - (alias outer 1 11 (type)) - (export "l" (func (type 11))) - (alias outer 1 12 (type)) - (export "m" (func (type 12))) - (alias outer 1 13 (type)) - (export "record1" (type (eq 13))) - (alias outer 1 14 (type)) - (export "n" (func (type 14))) - (alias outer 1 16 (type)) - (export "o" (func (type 15))) - (alias outer 1 18 (type)) - (export "p" (func (type 16))) - (alias outer 1 19 (type)) - (export "flags1" (type (eq 17))) - (alias outer 1 20 (type)) - (export "q" (func (type 18))) - (alias outer 1 21 (type)) - (export "enum1" (type (eq 19))) - (alias outer 1 22 (type)) - (export "r" (func (type 20))) - (alias outer 1 23 (type)) - (export "union1" (type (eq 21))) - (alias outer 1 24 (type)) - (export "s" (func (type 22))) - (alias outer 1 25 (type)) - (export "variant1" (type (eq 23))) - (alias outer 1 27 (type)) - (export "t" (func (type 24))) - (alias outer 1 29 (type)) - (export "u" (func (type 25))) + (type $f1 (func)) + (type $f2 (func (param "x" s8))) + (type $f3 (func (param "x" u8))) + (type $f4 (func (param "x" s16))) + (type $f5 (func (param "x" u16))) + (type $f6 (func (param "x" s32))) + (type $f7 (func (param "x" u32))) + (type $f8 (func (param "x" s64))) + (type $f9 (func (param "x" u64))) + (type $f10 (func (param "x" float32))) + (type $f11 (func (param "x" float64))) + (type $f12 (func (param "x" bool))) + (type $f13 (func (param "x" string))) + (export "a" (func (type $f1))) + (export "b" (func (type $f2))) + (export "c" (func (type $f3))) + (export "d" (func (type $f4))) + (export "e" (func (type $f5))) + (export "f" (func (type $f6))) + (export "g" (func (type $f7))) + (export "h" (func (type $f8))) + (export "i" (func (type $f9))) + (export "j" (func (type $f10))) + (export "k" (func (type $f11))) + (export "l" (func (type $f12))) + (export "m" (func (type $f13))) + (type $t1' (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) + (export $t1 "record1" (type (eq $t1'))) + (type $f14 (func (param "x" $t1))) + (export "n" (func (type $f14))) + (type $t2 (list $t1)) + (type $f15 (func (param "x" $t2))) + (export "o" (func (type $f15))) + (type $t3 (tuple $t1 string)) + (type $f16 (func (param "x" $t3))) + (export "p" (func (type $f16))) + (type $t4' (flags "a" "b" "c")) + (export $t4 "flags1" (type (eq $t4'))) + (type $f17 (func (param "x" $t4))) + (export "q" (func (type $f17))) + (type $t5' (enum "a" "b" "c")) + (export $t5 "enum1" (type (eq $t5'))) + (type $f18 (func (param "x" $t5))) + (export "r" (func (type $f18))) + (type $t6' (option $t1)) + (export $t6 "option1" (type (eq $t6'))) + (type $f19 (func (param "x" $t6))) + (export "s" (func (type $f19))) + (type $t7' (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" $t1))) + (export $t7 "variant1" (type (eq $t7'))) + (type $t8 (option $t7)) + (type $f20 (func (param "x" $t8))) + (export "t" (func (type $f20))) + (type $t9 (result $t1 (error string))) + (type $f21 (func (result $t9))) + (export "u" (func (type $f21))) ) ) - (type (func (param "x" string) (result string))) - (import "a" (instance (type 30))) - (core module + (type $f22 (func (param "x" string) (result string))) + (import "a" (instance $i1 (type $i1))) + (core module $m0 (import "a" "m" (func (param i32 i32))) (func $m (param i32 i32) (result i32) unreachable) (func $canonical_abi_realloc (param i32 i32 i32 i32) (result i32) unreachable) @@ -96,7 +70,7 @@ (export "m" (func $m)) (export "canonical_abi_realloc" (func $canonical_abi_realloc)) ) - (core module + (core module $m1 (type (func (param i32 i32))) (type (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) (type (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32 i32 i32))) @@ -203,7 +177,7 @@ (export "6" (func 6)) (export "$imports" (table 0)) ) - (core module + (core module $m2 (type (func (param i32 i32))) (type (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) (type (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32 i32 i32))) @@ -220,102 +194,72 @@ (import "" "$imports" (table 7 7 funcref)) (elem (i32.const 0) func 0 1 2 3 4 5 6) ) - (core instance (instantiate 1)) - (alias core export 0 "0" (core func)) - (alias core export 0 "1" (core func)) - (alias core export 0 "2" (core func)) - (alias core export 0 "3" (core func)) - (alias core export 0 "4" (core func)) - (alias core export 0 "5" (core func)) - (alias core export 0 "6" (core func)) - (alias export 0 "a" (func)) - (alias export 0 "b" (func)) - (alias export 0 "c" (func)) - (alias export 0 "d" (func)) - (alias export 0 "e" (func)) - (alias export 0 "f" (func)) - (alias export 0 "g" (func)) - (alias export 0 "h" (func)) - (alias export 0 "i" (func)) - (alias export 0 "j" (func)) - (alias export 0 "k" (func)) - (alias export 0 "l" (func)) - (alias export 0 "q" (func)) - (alias export 0 "r" (func)) - (core func (canon lower (func 0))) - (core func (canon lower (func 1))) - (core func (canon lower (func 2))) - (core func (canon lower (func 3))) - (core func (canon lower (func 4))) - (core func (canon lower (func 5))) - (core func (canon lower (func 6))) - (core func (canon lower (func 7))) - (core func (canon lower (func 8))) - (core func (canon lower (func 9))) - (core func (canon lower (func 10))) - (core func (canon lower (func 11))) - (core func (canon lower (func 12))) - (core func (canon lower (func 13))) - (core instance - (export "m" (func 0)) - (export "n" (func 1)) - (export "o" (func 2)) - (export "p" (func 3)) - (export "s" (func 4)) - (export "t" (func 5)) - (export "u" (func 6)) - (export "a" (func 7)) - (export "b" (func 8)) - (export "c" (func 9)) - (export "d" (func 10)) - (export "e" (func 11)) - (export "f" (func 12)) - (export "g" (func 13)) - (export "h" (func 14)) - (export "i" (func 15)) - (export "j" (func 16)) - (export "k" (func 17)) - (export "l" (func 18)) - (export "q" (func 19)) - (export "r" (func 20)) - ) - (core instance (instantiate 0 - (with "a" (instance 1)) + (core instance $m1 (instantiate $m1)) + (core func $a (canon lower (func $i1 "a"))) + (core func $b (canon lower (func $i1 "b"))) + (core func $c (canon lower (func $i1 "c"))) + (core func $d (canon lower (func $i1 "d"))) + (core func $e (canon lower (func $i1 "e"))) + (core func $f (canon lower (func $i1 "f"))) + (core func $g (canon lower (func $i1 "g"))) + (core func $h (canon lower (func $i1 "h"))) + (core func $i (canon lower (func $i1 "i"))) + (core func $j (canon lower (func $i1 "j"))) + (core func $k (canon lower (func $i1 "k"))) + (core func $l (canon lower (func $i1 "l"))) + (core func $q (canon lower (func $i1 "q"))) + (core func $r (canon lower (func $i1 "r"))) + (core instance $m0 (instantiate $m0 + (with "a" (instance + (export "m" (func $m1 "0")) + (export "n" (func $m1 "1")) + (export "o" (func $m1 "2")) + (export "p" (func $m1 "3")) + (export "s" (func $m1 "4")) + (export "t" (func $m1 "5")) + (export "u" (func $m1 "6")) + (export "a" (func $a)) + (export "b" (func $b)) + (export "c" (func $c)) + (export "d" (func $d)) + (export "e" (func $e)) + (export "f" (func $f)) + (export "g" (func $g)) + (export "h" (func $h)) + (export "i" (func $i)) + (export "j" (func $j)) + (export "k" (func $k)) + (export "l" (func $l)) + (export "q" (func $q)) + (export "r" (func $r)) + )) ) ) - (alias core export 2 "memory" (core memory)) - (alias core export 2 "canonical_abi_realloc" (core func)) - (alias core export 0 "$imports" (core table)) - (alias export 0 "m" (func)) - (alias export 0 "n" (func)) - (alias export 0 "o" (func)) - (alias export 0 "p" (func)) - (alias export 0 "s" (func)) - (alias export 0 "t" (func)) - (alias export 0 "u" (func)) - (core func (canon lower (func 14) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (canon lower (func 15) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (canon lower (func 16) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (canon lower (func 17) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (canon lower (func 18) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (canon lower (func 19) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (canon lower (func 20) (memory 0) (realloc 21) string-encoding=utf8)) - (core instance - (export "$imports" (table 0)) - (export "0" (func 22)) - (export "1" (func 23)) - (export "2" (func 24)) - (export "3" (func 25)) - (export "4" (func 26)) - (export "5" (func 27)) - (export "6" (func 28)) - ) - (core instance (instantiate 2 - (with "" (instance 3)) - ) + (alias core export $m0 "memory" (core memory $m)) + (alias core export $m0 "canonical_abi_realloc" (core func $realloc)) + (alias core export $m1 "$imports" (core table $t)) + (core func (canon lower (func $i1 "m") (memory $m) (realloc $realloc) string-encoding=utf8)) + (core func (canon lower (func $i1 "n") (memory $m) (realloc $realloc) string-encoding=utf8)) + (core func (canon lower (func $i1 "o") (memory $m) (realloc $realloc) string-encoding=utf8)) + (core func (canon lower (func $i1 "p") (memory $m) (realloc $realloc) string-encoding=utf8)) + (core func (canon lower (func $i1 "s") (memory $m) (realloc $realloc) string-encoding=utf8)) + (core func (canon lower (func $i1 "t") (memory $m) (realloc $realloc) string-encoding=utf8)) + (core func (canon lower (func $i1 "u") (memory $m) (realloc $realloc) string-encoding=utf8)) + (core instance (instantiate $m2 + (with "" (instance + (export "$imports" (table $t)) + (export "0" (func 22)) + (export "1" (func 23)) + (export "2" (func 24)) + (export "3" (func 25)) + (export "4" (func 26)) + (export "5" (func 27)) + (export "6" (func 28)) + )) + )) + (func $m (type $f22) + (canon lift (core func $m0 "m") (memory $m) (realloc $realloc) string-encoding=utf8) ) - (alias core export 2 "m" (core func)) - (func (type 31) (canon lift (core func 29) (memory 0) (realloc 21) string-encoding=utf8)) - (instance (export "m" (func 21))) - (export "x" (instance 1)) + (instance $x (export "m" (func $m))) + (export "x" (instance $x)) ) diff --git a/crates/wasm-compose/tests/compositions/complex/b.wit b/crates/wasm-compose/tests/compositions/complex/b.wit deleted file mode 100644 index cfe85a755a..0000000000 --- a/crates/wasm-compose/tests/compositions/complex/b.wit +++ /dev/null @@ -1 +0,0 @@ -m: func(x: string) -> string diff --git a/crates/wasm-compose/tests/compositions/complex/composed.wat b/crates/wasm-compose/tests/compositions/complex/composed.wat index d5eec4189e..25f20639aa 100644 --- a/crates/wasm-compose/tests/compositions/complex/composed.wat +++ b/crates/wasm-compose/tests/compositions/complex/composed.wat @@ -1,302 +1,82 @@ (component (component (;0;) - (type (;0;) (func)) - (type (;1;) (func (param "x" s8))) - (type (;2;) (func (param "x" u8))) - (type (;3;) (func (param "x" s16))) - (type (;4;) (func (param "x" u16))) - (type (;5;) (func (param "x" s32))) - (type (;6;) (func (param "x" u32))) - (type (;7;) (func (param "x" s64))) - (type (;8;) (func (param "x" u64))) - (type (;9;) (func (param "x" float32))) - (type (;10;) (func (param "x" float64))) - (type (;11;) (func (param "x" bool))) - (type (;12;) (func (param "x" string))) - (type (;13;) (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) - (type (;14;) (func (param "x" 13))) - (type (;15;) (list 13)) - (type (;16;) (func (param "x" 15))) - (type (;17;) (tuple 13 string)) - (type (;18;) (func (param "x" 17))) - (type (;19;) (flags "a" "b" "c")) - (type (;20;) (func (param "x" 19))) - (type (;21;) (enum "a" "b" "c")) - (type (;22;) (func (param "x" 21))) - (type (;23;) (union s8 string 13)) - (type (;24;) (func (param "x" 23))) - (type (;25;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) - (type (;26;) (option 25)) - (type (;27;) (func (param "x" 26))) - (type (;28;) (result 13 (error string))) - (type (;29;) (func (result 28))) - (export "record1" (type 13)) - (export "flags1" (type 19)) - (export "enum1" (type 21)) - (export "union1" (type 23)) - (export "variant1" (type 25)) - (core module (;0;) - (type (;0;) (func)) - (type (;1;) (func (param i32))) - (type (;2;) (func (param i64))) - (type (;3;) (func (param f32))) - (type (;4;) (func (param f64))) - (type (;5;) (func (param i32 i32))) - (type (;6;) (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) - (type (;7;) (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32 i32 i32))) - (type (;8;) (func (param i32 i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) - (type (;9;) (func (param i32 i32 i64 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) - (type (;10;) (func (result i32))) - (type (;11;) (func (param i32 i32 i32 i32) (result i32))) - (func $a (;0;) (type 0) - unreachable - ) - (func $b (;1;) (type 1) (param i32) - unreachable - ) - (func $c (;2;) (type 1) (param i32) - unreachable - ) - (func $d (;3;) (type 1) (param i32) - unreachable - ) - (func $e (;4;) (type 1) (param i32) - unreachable - ) - (func $f (;5;) (type 1) (param i32) - unreachable - ) - (func $g (;6;) (type 1) (param i32) - unreachable - ) - (func $h (;7;) (type 2) (param i64) - unreachable - ) - (func $i (;8;) (type 2) (param i64) - unreachable - ) - (func $j (;9;) (type 3) (param f32) - unreachable - ) - (func $k (;10;) (type 4) (param f64) - unreachable - ) - (func $l (;11;) (type 1) (param i32) - unreachable - ) - (func $m (;12;) (type 5) (param i32 i32) - unreachable - ) - (func $n (;13;) (type 6) (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32) - unreachable - ) - (func $o (;14;) (type 5) (param i32 i32) - unreachable - ) - (func $p (;15;) (type 7) (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32 i32 i32) - unreachable - ) - (func $q (;16;) (type 1) (param i32) - unreachable - ) - (func $r (;17;) (type 1) (param i32) - unreachable - ) - (func $s (;18;) (type 8) (param i32 i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32) - unreachable - ) - (func $t (;19;) (type 9) (param i32 i32 i64 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32) - unreachable - ) - (func $u (;20;) (type 10) (result i32) - unreachable - ) - (func $canonical_abi_realloc (;21;) (type 11) (param i32 i32 i32 i32) (result i32) - unreachable + (type (;0;) + (instance + (type (;0;) (func (param "x" string) (result string))) + (export (;0;) "m" (func (type 0))) ) - (memory (;0;) 0) - (export "memory" (memory 0)) - (export "a" (func $a)) - (export "b" (func $b)) - (export "c" (func $c)) - (export "d" (func $d)) - (export "e" (func $e)) - (export "f" (func $f)) - (export "g" (func $g)) - (export "h" (func $h)) - (export "i" (func $i)) - (export "j" (func $j)) - (export "k" (func $k)) - (export "l" (func $l)) - (export "m" (func $m)) - (export "n" (func $n)) - (export "o" (func $o)) - (export "p" (func $p)) - (export "q" (func $q)) - (export "r" (func $r)) - (export "s" (func $s)) - (export "t" (func $t)) - (export "u" (func $u)) - (export "canonical_abi_realloc" (func $canonical_abi_realloc)) ) - (core instance (;0;) (instantiate 0)) - (alias core export 0 "memory" (core memory (;0;))) - (alias core export 0 "canonical_abi_realloc" (core func (;0;))) - (alias core export 0 "a" (core func (;1;))) - (alias core export 0 "b" (core func (;2;))) - (alias core export 0 "c" (core func (;3;))) - (alias core export 0 "d" (core func (;4;))) - (alias core export 0 "e" (core func (;5;))) - (alias core export 0 "f" (core func (;6;))) - (alias core export 0 "g" (core func (;7;))) - (alias core export 0 "h" (core func (;8;))) - (alias core export 0 "i" (core func (;9;))) - (alias core export 0 "j" (core func (;10;))) - (alias core export 0 "k" (core func (;11;))) - (alias core export 0 "l" (core func (;12;))) - (alias core export 0 "m" (core func (;13;))) - (alias core export 0 "n" (core func (;14;))) - (alias core export 0 "o" (core func (;15;))) - (alias core export 0 "p" (core func (;16;))) - (alias core export 0 "q" (core func (;17;))) - (alias core export 0 "r" (core func (;18;))) - (alias core export 0 "s" (core func (;19;))) - (alias core export 0 "t" (core func (;20;))) - (alias core export 0 "u" (core func (;21;))) - (func (;0;) (type 0) (canon lift (core func 1))) - (func (;1;) (type 1) (canon lift (core func 2))) - (func (;2;) (type 2) (canon lift (core func 3))) - (func (;3;) (type 3) (canon lift (core func 4))) - (func (;4;) (type 4) (canon lift (core func 5))) - (func (;5;) (type 5) (canon lift (core func 6))) - (func (;6;) (type 6) (canon lift (core func 7))) - (func (;7;) (type 7) (canon lift (core func 8))) - (func (;8;) (type 8) (canon lift (core func 9))) - (func (;9;) (type 9) (canon lift (core func 10))) - (func (;10;) (type 10) (canon lift (core func 11))) - (func (;11;) (type 11) (canon lift (core func 12))) - (func (;12;) (type 12) (canon lift (core func 13) (memory 0) (realloc 0) string-encoding=utf8)) - (func (;13;) (type 14) (canon lift (core func 14) (memory 0) (realloc 0) string-encoding=utf8)) - (func (;14;) (type 16) (canon lift (core func 15) (memory 0) (realloc 0) string-encoding=utf8)) - (func (;15;) (type 18) (canon lift (core func 16) (memory 0) (realloc 0) string-encoding=utf8)) - (func (;16;) (type 20) (canon lift (core func 17))) - (func (;17;) (type 22) (canon lift (core func 18))) - (func (;18;) (type 24) (canon lift (core func 19) (memory 0) (realloc 0) string-encoding=utf8)) - (func (;19;) (type 27) (canon lift (core func 20) (memory 0) (realloc 0) string-encoding=utf8)) - (func (;20;) (type 29) (canon lift (core func 21) (memory 0) (realloc 0) string-encoding=utf8)) - (export "a" (func 0)) - (export "b" (func 1)) - (export "c" (func 2)) - (export "d" (func 3)) - (export "e" (func 4)) - (export "f" (func 5)) - (export "g" (func 6)) - (export "h" (func 7)) - (export "i" (func 8)) - (export "j" (func 9)) - (export "k" (func 10)) - (export "l" (func 11)) - (export "m" (func 12)) - (export "n" (func 13)) - (export "o" (func 14)) - (export "p" (func 15)) - (export "q" (func 16)) - (export "r" (func 17)) - (export "s" (func 18)) - (export "t" (func 19)) - (export "u" (func 20)) + (import "b1" (instance (;0;) (type 0))) + (import "b2" (instance (;1;) (type 0))) + (alias export 0 "m" (func (;0;))) + (alias export 1 "m" (func (;1;))) + (export (;2;) "m1" (func 0)) + (export (;3;) "m2" (func 1)) ) - (instance (;0;) (instantiate 0)) (component (;1;) - (type (;0;) (func)) - (type (;1;) (func (param "x" s8))) - (type (;2;) (func (param "x" u8))) - (type (;3;) (func (param "x" s16))) - (type (;4;) (func (param "x" u16))) - (type (;5;) (func (param "x" s32))) - (type (;6;) (func (param "x" u32))) - (type (;7;) (func (param "x" s64))) - (type (;8;) (func (param "x" u64))) - (type (;9;) (func (param "x" float32))) - (type (;10;) (func (param "x" float64))) - (type (;11;) (func (param "x" bool))) - (type (;12;) (func (param "x" string))) - (type (;13;) (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) - (type (;14;) (func (param "x" 13))) - (type (;15;) (list 13)) - (type (;16;) (func (param "x" 15))) - (type (;17;) (tuple 13 string)) - (type (;18;) (func (param "x" 17))) - (type (;19;) (flags "a" "b" "c")) - (type (;20;) (func (param "x" 19))) - (type (;21;) (enum "a" "b" "c")) - (type (;22;) (func (param "x" 21))) - (type (;23;) (union s8 string 13)) - (type (;24;) (func (param "x" 23))) - (type (;25;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) - (type (;26;) (option 25)) - (type (;27;) (func (param "x" 26))) - (type (;28;) (result 13 (error string))) - (type (;29;) (func (result 28))) - (type (;30;) + (type $i1 (;0;) (instance - (alias outer 1 0 (type (;0;))) - (export "a" (func (type 0))) - (alias outer 1 1 (type (;1;))) - (export "b" (func (type 1))) - (alias outer 1 2 (type (;2;))) - (export "c" (func (type 2))) - (alias outer 1 3 (type (;3;))) - (export "d" (func (type 3))) - (alias outer 1 4 (type (;4;))) - (export "e" (func (type 4))) - (alias outer 1 5 (type (;5;))) - (export "f" (func (type 5))) - (alias outer 1 6 (type (;6;))) - (export "g" (func (type 6))) - (alias outer 1 7 (type (;7;))) - (export "h" (func (type 7))) - (alias outer 1 8 (type (;8;))) - (export "i" (func (type 8))) - (alias outer 1 9 (type (;9;))) - (export "j" (func (type 9))) - (alias outer 1 10 (type (;10;))) - (export "k" (func (type 10))) - (alias outer 1 11 (type (;11;))) - (export "l" (func (type 11))) - (alias outer 1 12 (type (;12;))) - (export "m" (func (type 12))) - (alias outer 1 13 (type (;13;))) - (export "record1" (type (eq 13))) - (alias outer 1 14 (type (;14;))) - (export "n" (func (type 14))) - (alias outer 1 16 (type (;15;))) - (export "o" (func (type 15))) - (alias outer 1 18 (type (;16;))) - (export "p" (func (type 16))) - (alias outer 1 19 (type (;17;))) - (export "flags1" (type (eq 17))) - (alias outer 1 20 (type (;18;))) - (export "q" (func (type 18))) - (alias outer 1 21 (type (;19;))) - (export "enum1" (type (eq 19))) - (alias outer 1 22 (type (;20;))) - (export "r" (func (type 20))) - (alias outer 1 23 (type (;21;))) - (export "union1" (type (eq 21))) - (alias outer 1 24 (type (;22;))) - (export "s" (func (type 22))) - (alias outer 1 25 (type (;23;))) - (export "variant1" (type (eq 23))) - (alias outer 1 27 (type (;24;))) - (export "t" (func (type 24))) - (alias outer 1 29 (type (;25;))) - (export "u" (func (type 25))) + (type (;0;) (func)) + (type (;1;) (func (param "x" s8))) + (type (;2;) (func (param "x" u8))) + (type (;3;) (func (param "x" s16))) + (type (;4;) (func (param "x" u16))) + (type (;5;) (func (param "x" s32))) + (type (;6;) (func (param "x" u32))) + (type (;7;) (func (param "x" s64))) + (type (;8;) (func (param "x" u64))) + (type (;9;) (func (param "x" float32))) + (type (;10;) (func (param "x" float64))) + (type (;11;) (func (param "x" bool))) + (type (;12;) (func (param "x" string))) + (export (;0;) "a" (func (type 0))) + (export (;1;) "b" (func (type 1))) + (export (;2;) "c" (func (type 2))) + (export (;3;) "d" (func (type 3))) + (export (;4;) "e" (func (type 4))) + (export (;5;) "f" (func (type 5))) + (export (;6;) "g" (func (type 6))) + (export (;7;) "h" (func (type 7))) + (export (;8;) "i" (func (type 8))) + (export (;9;) "j" (func (type 9))) + (export (;10;) "k" (func (type 10))) + (export (;11;) "l" (func (type 11))) + (export (;12;) "m" (func (type 12))) + (type (;13;) (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) + (export (;14;) "record1" (type (eq 13))) + (type (;15;) (func (param "x" 14))) + (export (;13;) "n" (func (type 15))) + (type (;16;) (list 14)) + (type (;17;) (func (param "x" 16))) + (export (;14;) "o" (func (type 17))) + (type (;18;) (tuple 14 string)) + (type (;19;) (func (param "x" 18))) + (export (;15;) "p" (func (type 19))) + (type (;20;) (flags "a" "b" "c")) + (export (;21;) "flags1" (type (eq 20))) + (type (;22;) (func (param "x" 21))) + (export (;16;) "q" (func (type 22))) + (type (;23;) (enum "a" "b" "c")) + (export (;24;) "enum1" (type (eq 23))) + (type (;25;) (func (param "x" 24))) + (export (;17;) "r" (func (type 25))) + (type (;26;) (option 14)) + (export (;27;) "option1" (type (eq 26))) + (type (;28;) (func (param "x" 27))) + (export (;18;) "s" (func (type 28))) + (type (;29;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 14))) + (export (;30;) "variant1" (type (eq 29))) + (type (;31;) (option 30)) + (type (;32;) (func (param "x" 31))) + (export (;19;) "t" (func (type 32))) + (type (;33;) (result 14 (error string))) + (type (;34;) (func (result 33))) + (export (;20;) "u" (func (type 34))) ) ) - (type (;31;) (func (param "x" string) (result string))) - (import "a" (instance (;0;) (type 30))) - (core module (;0;) + (type $f22 (;1;) (func (param "x" string) (result string))) + (import "a" (instance $i1 (;0;) (type $i1))) + (core module $m0 (;0;) (type (;0;) (func (param i32 i32))) (type (;1;) (func (param i32 i32) (result i32))) (type (;2;) (func (param i32 i32 i32 i32) (result i32))) @@ -312,7 +92,7 @@ (export "m" (func $m)) (export "canonical_abi_realloc" (func $canonical_abi_realloc)) ) - (core module (;1;) + (core module $m1 (;1;) (type (;0;) (func (param i32 i32))) (type (;1;) (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) (type (;2;) (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32 i32 i32))) @@ -419,7 +199,7 @@ (export "6" (func 6)) (export "$imports" (table 0)) ) - (core module (;2;) + (core module $m2 (;2;) (type (;0;) (func (param i32 i32))) (type (;1;) (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) (type (;2;) (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32 i32 i32))) @@ -436,88 +216,88 @@ (import "" "$imports" (table (;0;) 7 7 funcref)) (elem (;0;) (i32.const 0) func 0 1 2 3 4 5 6) ) - (core instance (;0;) (instantiate 1)) - (alias core export 0 "0" (core func (;0;))) - (alias core export 0 "1" (core func (;1;))) - (alias core export 0 "2" (core func (;2;))) - (alias core export 0 "3" (core func (;3;))) - (alias core export 0 "4" (core func (;4;))) - (alias core export 0 "5" (core func (;5;))) - (alias core export 0 "6" (core func (;6;))) - (alias export 0 "a" (func (;0;))) - (alias export 0 "b" (func (;1;))) - (alias export 0 "c" (func (;2;))) - (alias export 0 "d" (func (;3;))) - (alias export 0 "e" (func (;4;))) - (alias export 0 "f" (func (;5;))) - (alias export 0 "g" (func (;6;))) - (alias export 0 "h" (func (;7;))) - (alias export 0 "i" (func (;8;))) - (alias export 0 "j" (func (;9;))) - (alias export 0 "k" (func (;10;))) - (alias export 0 "l" (func (;11;))) - (alias export 0 "q" (func (;12;))) - (alias export 0 "r" (func (;13;))) - (core func (;7;) (canon lower (func 0))) - (core func (;8;) (canon lower (func 1))) - (core func (;9;) (canon lower (func 2))) - (core func (;10;) (canon lower (func 3))) - (core func (;11;) (canon lower (func 4))) - (core func (;12;) (canon lower (func 5))) - (core func (;13;) (canon lower (func 6))) - (core func (;14;) (canon lower (func 7))) - (core func (;15;) (canon lower (func 8))) - (core func (;16;) (canon lower (func 9))) - (core func (;17;) (canon lower (func 10))) - (core func (;18;) (canon lower (func 11))) - (core func (;19;) (canon lower (func 12))) - (core func (;20;) (canon lower (func 13))) - (core instance (;1;) - (export "m" (func 0)) - (export "n" (func 1)) - (export "o" (func 2)) - (export "p" (func 3)) - (export "s" (func 4)) - (export "t" (func 5)) - (export "u" (func 6)) - (export "a" (func 7)) - (export "b" (func 8)) - (export "c" (func 9)) - (export "d" (func 10)) - (export "e" (func 11)) - (export "f" (func 12)) - (export "g" (func 13)) - (export "h" (func 14)) - (export "i" (func 15)) - (export "j" (func 16)) - (export "k" (func 17)) - (export "l" (func 18)) - (export "q" (func 19)) - (export "r" (func 20)) + (core instance $m1 (;0;) (instantiate $m1)) + (alias export $i1 "a" (func (;0;))) + (core func $a (;0;) (canon lower (func 0))) + (alias export $i1 "b" (func (;1;))) + (core func $b (;1;) (canon lower (func 1))) + (alias export $i1 "c" (func (;2;))) + (core func $c (;2;) (canon lower (func 2))) + (alias export $i1 "d" (func (;3;))) + (core func $d (;3;) (canon lower (func 3))) + (alias export $i1 "e" (func (;4;))) + (core func $e (;4;) (canon lower (func 4))) + (alias export $i1 "f" (func (;5;))) + (core func $f (;5;) (canon lower (func 5))) + (alias export $i1 "g" (func (;6;))) + (core func $g (;6;) (canon lower (func 6))) + (alias export $i1 "h" (func (;7;))) + (core func $h (;7;) (canon lower (func 7))) + (alias export $i1 "i" (func (;8;))) + (core func $i (;8;) (canon lower (func 8))) + (alias export $i1 "j" (func (;9;))) + (core func $j (;9;) (canon lower (func 9))) + (alias export $i1 "k" (func (;10;))) + (core func $k (;10;) (canon lower (func 10))) + (alias export $i1 "l" (func (;11;))) + (core func $l (;11;) (canon lower (func 11))) + (alias export $i1 "q" (func (;12;))) + (core func $q (;12;) (canon lower (func 12))) + (alias export $i1 "r" (func (;13;))) + (core func $r (;13;) (canon lower (func 13))) + (alias core export $m1 "0" (core func (;14;))) + (alias core export $m1 "1" (core func (;15;))) + (alias core export $m1 "2" (core func (;16;))) + (alias core export $m1 "3" (core func (;17;))) + (alias core export $m1 "4" (core func (;18;))) + (alias core export $m1 "5" (core func (;19;))) + (alias core export $m1 "6" (core func (;20;))) + (core instance (;1;) + (export "m" (func 14)) + (export "n" (func 15)) + (export "o" (func 16)) + (export "p" (func 17)) + (export "s" (func 18)) + (export "t" (func 19)) + (export "u" (func 20)) + (export "a" (func $a)) + (export "b" (func $b)) + (export "c" (func $c)) + (export "d" (func $d)) + (export "e" (func $e)) + (export "f" (func $f)) + (export "g" (func $g)) + (export "h" (func $h)) + (export "i" (func $i)) + (export "j" (func $j)) + (export "k" (func $k)) + (export "l" (func $l)) + (export "q" (func $q)) + (export "r" (func $r)) ) - (core instance (;2;) (instantiate 0 + (core instance $m0 (;2;) (instantiate $m0 (with "a" (instance 1)) ) ) - (alias core export 2 "memory" (core memory (;0;))) - (alias core export 2 "canonical_abi_realloc" (core func (;21;))) - (alias core export 0 "$imports" (core table (;0;))) - (alias export 0 "m" (func (;14;))) - (alias export 0 "n" (func (;15;))) - (alias export 0 "o" (func (;16;))) - (alias export 0 "p" (func (;17;))) - (alias export 0 "s" (func (;18;))) - (alias export 0 "t" (func (;19;))) - (alias export 0 "u" (func (;20;))) - (core func (;22;) (canon lower (func 14) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (;23;) (canon lower (func 15) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (;24;) (canon lower (func 16) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (;25;) (canon lower (func 17) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (;26;) (canon lower (func 18) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (;27;) (canon lower (func 19) (memory 0) (realloc 21) string-encoding=utf8)) - (core func (;28;) (canon lower (func 20) (memory 0) (realloc 21) string-encoding=utf8)) - (core instance (;3;) - (export "$imports" (table 0)) + (alias core export $m0 "memory" (core memory $m (;0;))) + (alias core export $m0 "canonical_abi_realloc" (core func $realloc (;21;))) + (alias core export $m1 "$imports" (core table $t (;0;))) + (alias export $i1 "m" (func (;14;))) + (core func (;22;) (canon lower (func 14) (memory $m) (realloc $realloc) string-encoding=utf8)) + (alias export $i1 "n" (func (;15;))) + (core func (;23;) (canon lower (func 15) (memory $m) (realloc $realloc) string-encoding=utf8)) + (alias export $i1 "o" (func (;16;))) + (core func (;24;) (canon lower (func 16) (memory $m) (realloc $realloc) string-encoding=utf8)) + (alias export $i1 "p" (func (;17;))) + (core func (;25;) (canon lower (func 17) (memory $m) (realloc $realloc) string-encoding=utf8)) + (alias export $i1 "s" (func (;18;))) + (core func (;26;) (canon lower (func 18) (memory $m) (realloc $realloc) string-encoding=utf8)) + (alias export $i1 "t" (func (;19;))) + (core func (;27;) (canon lower (func 19) (memory $m) (realloc $realloc) string-encoding=utf8)) + (alias export $i1 "u" (func (;20;))) + (core func (;28;) (canon lower (func 20) (memory $m) (realloc $realloc) string-encoding=utf8)) + (core instance (;3;) + (export "$imports" (table $t)) (export "0" (func 22)) (export "1" (func 23)) (export "2" (func 24)) @@ -526,17 +306,225 @@ (export "5" (func 27)) (export "6" (func 28)) ) - (core instance (;4;) (instantiate 2 + (core instance (;4;) (instantiate $m2 (with "" (instance 3)) ) ) - (alias core export 2 "m" (core func (;29;))) - (func (;21;) (type 31) (canon lift (core func 29) (memory 0) (realloc 21) string-encoding=utf8)) - (instance (;1;) - (export "m" (func 21)) + (alias core export $m0 "m" (core func (;29;))) + (func $m (;21;) (type $f22) (canon lift (core func 29) (memory $m) (realloc $realloc) string-encoding=utf8)) + (instance $x (;1;) + (export "m" (func $m)) + ) + (export (;2;) "x" (instance $x)) + ) + (component (;2;) + (type $t0 (;0;) (func)) + (type $t1 (;1;) (func (param "x" s8))) + (type $t2 (;2;) (func (param "x" u8))) + (type $t3 (;3;) (func (param "x" s16))) + (type $t4 (;4;) (func (param "x" u16))) + (type $t5 (;5;) (func (param "x" s32))) + (type $t6 (;6;) (func (param "x" u32))) + (type $t7 (;7;) (func (param "x" s64))) + (type $t8 (;8;) (func (param "x" u64))) + (type $t9 (;9;) (func (param "x" float32))) + (type $t10 (;10;) (func (param "x" float64))) + (type $t11 (;11;) (func (param "x" bool))) + (type $t12 (;12;) (func (param "x" string))) + (type $t13' (;13;) (record (field "a" s8) (field "b" u8) (field "c" s16) (field "d" u16) (field "e" s32) (field "f" u32) (field "g" s64) (field "h" u64) (field "i" float32) (field "j" float64) (field "k" bool) (field "l" string))) + (export $t13 (;14;) "record1" (type $t13')) + (type $t14 (;15;) (func (param "x" $t13))) + (type $t15 (;16;) (list $t13)) + (type $t16 (;17;) (func (param "x" $t15))) + (type $t17 (;18;) (tuple $t13 string)) + (type $t18 (;19;) (func (param "x" $t17))) + (type $t19' (;20;) (flags "a" "b" "c")) + (export $t19 (;21;) "flags1" (type $t19')) + (type $t20 (;22;) (func (param "x" $t19))) + (type $t21' (;23;) (enum "a" "b" "c")) + (export $t21 (;24;) "enum1" (type $t21')) + (type $t22 (;25;) (func (param "x" $t21))) + (type $t23' (;26;) (option $t13)) + (export $t23 (;27;) "option1" (type $t23')) + (type $t24 (;28;) (func (param "x" $t23))) + (type $t25' (;29;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" $t13))) + (export $t25 (;30;) "variant1" (type $t25')) + (type $t26 (;31;) (option $t25)) + (type $t27 (;32;) (func (param "x" $t26))) + (type $t28 (;33;) (result $t13 (error string))) + (type $t29 (;34;) (func (result $t28))) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i64))) + (type (;3;) (func (param f32))) + (type (;4;) (func (param f64))) + (type (;5;) (func (param i32 i32))) + (type (;6;) (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) + (type (;7;) (func (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32 i32 i32))) + (type (;8;) (func (param i32 i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) + (type (;9;) (func (param i32 i32 i64 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32))) + (type (;10;) (func (result i32))) + (type (;11;) (func (param i32 i32 i32 i32) (result i32))) + (func $a (;0;) (type 0) + unreachable + ) + (func $b (;1;) (type 1) (param i32) + unreachable + ) + (func $c (;2;) (type 1) (param i32) + unreachable + ) + (func $d (;3;) (type 1) (param i32) + unreachable + ) + (func $e (;4;) (type 1) (param i32) + unreachable + ) + (func $f (;5;) (type 1) (param i32) + unreachable + ) + (func $g (;6;) (type 1) (param i32) + unreachable + ) + (func $h (;7;) (type 2) (param i64) + unreachable + ) + (func $i (;8;) (type 2) (param i64) + unreachable + ) + (func $j (;9;) (type 3) (param f32) + unreachable + ) + (func $k (;10;) (type 4) (param f64) + unreachable + ) + (func $l (;11;) (type 1) (param i32) + unreachable + ) + (func $m (;12;) (type 5) (param i32 i32) + unreachable + ) + (func $n (;13;) (type 6) (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32) + unreachable + ) + (func $o (;14;) (type 5) (param i32 i32) + unreachable + ) + (func $p (;15;) (type 7) (param i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32 i32 i32) + unreachable + ) + (func $q (;16;) (type 1) (param i32) + unreachable + ) + (func $r (;17;) (type 1) (param i32) + unreachable + ) + (func $s (;18;) (type 8) (param i32 i32 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32) + unreachable + ) + (func $t (;19;) (type 9) (param i32 i32 i64 i32 i32 i32 i32 i32 i64 i64 f32 f64 i32 i32 i32) + unreachable + ) + (func $u (;20;) (type 10) (result i32) + unreachable + ) + (func $canonical_abi_realloc (;21;) (type 11) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 0) + (export "memory" (memory 0)) + (export "a" (func $a)) + (export "b" (func $b)) + (export "c" (func $c)) + (export "d" (func $d)) + (export "e" (func $e)) + (export "f" (func $f)) + (export "g" (func $g)) + (export "h" (func $h)) + (export "i" (func $i)) + (export "j" (func $j)) + (export "k" (func $k)) + (export "l" (func $l)) + (export "m" (func $m)) + (export "n" (func $n)) + (export "o" (func $o)) + (export "p" (func $p)) + (export "q" (func $q)) + (export "r" (func $r)) + (export "s" (func $s)) + (export "t" (func $t)) + (export "u" (func $u)) + (export "canonical_abi_realloc" (func $canonical_abi_realloc)) ) - (export "x" (instance 1)) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "canonical_abi_realloc" (core func (;0;))) + (alias core export 0 "a" (core func (;1;))) + (alias core export 0 "b" (core func (;2;))) + (alias core export 0 "c" (core func (;3;))) + (alias core export 0 "d" (core func (;4;))) + (alias core export 0 "e" (core func (;5;))) + (alias core export 0 "f" (core func (;6;))) + (alias core export 0 "g" (core func (;7;))) + (alias core export 0 "h" (core func (;8;))) + (alias core export 0 "i" (core func (;9;))) + (alias core export 0 "j" (core func (;10;))) + (alias core export 0 "k" (core func (;11;))) + (alias core export 0 "l" (core func (;12;))) + (alias core export 0 "m" (core func (;13;))) + (alias core export 0 "n" (core func (;14;))) + (alias core export 0 "o" (core func (;15;))) + (alias core export 0 "p" (core func (;16;))) + (alias core export 0 "q" (core func (;17;))) + (alias core export 0 "r" (core func (;18;))) + (alias core export 0 "s" (core func (;19;))) + (alias core export 0 "t" (core func (;20;))) + (alias core export 0 "u" (core func (;21;))) + (func (;0;) (type $t0) (canon lift (core func 1))) + (func (;1;) (type $t1) (canon lift (core func 2))) + (func (;2;) (type $t2) (canon lift (core func 3))) + (func (;3;) (type $t3) (canon lift (core func 4))) + (func (;4;) (type $t4) (canon lift (core func 5))) + (func (;5;) (type $t5) (canon lift (core func 6))) + (func (;6;) (type $t6) (canon lift (core func 7))) + (func (;7;) (type $t7) (canon lift (core func 8))) + (func (;8;) (type $t8) (canon lift (core func 9))) + (func (;9;) (type $t9) (canon lift (core func 10))) + (func (;10;) (type $t10) (canon lift (core func 11))) + (func (;11;) (type $t11) (canon lift (core func 12))) + (func (;12;) (type $t12) (canon lift (core func 13) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;13;) (type $t14) (canon lift (core func 14) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;14;) (type $t16) (canon lift (core func 15) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;15;) (type $t18) (canon lift (core func 16) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;16;) (type $t20) (canon lift (core func 17))) + (func (;17;) (type $t22) (canon lift (core func 18))) + (func (;18;) (type $t24) (canon lift (core func 19) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;19;) (type $t27) (canon lift (core func 20) (memory 0) (realloc 0) string-encoding=utf8)) + (func (;20;) (type $t29) (canon lift (core func 21) (memory 0) (realloc 0) string-encoding=utf8)) + (export (;21;) "a" (func 0)) + (export (;22;) "b" (func 1)) + (export (;23;) "c" (func 2)) + (export (;24;) "d" (func 3)) + (export (;25;) "e" (func 4)) + (export (;26;) "f" (func 5)) + (export (;27;) "g" (func 6)) + (export (;28;) "h" (func 7)) + (export (;29;) "i" (func 8)) + (export (;30;) "j" (func 9)) + (export (;31;) "k" (func 10)) + (export (;32;) "l" (func 11)) + (export (;33;) "m" (func 12)) + (export (;34;) "n" (func 13)) + (export (;35;) "o" (func 14)) + (export (;36;) "p" (func 15)) + (export (;37;) "q" (func 16)) + (export (;38;) "r" (func 17)) + (export (;39;) "s" (func 18)) + (export (;40;) "t" (func 19)) + (export (;41;) "u" (func 20)) ) + (instance (;0;) (instantiate 2)) (instance (;1;) (instantiate 1 (with "a" (instance 0)) ) @@ -545,29 +533,15 @@ (with "a" (instance 0)) ) ) - (component (;2;) - (type (;0;) - (instance - (type (;0;) (func (param "x" string) (result string))) - (export "m" (func (type 0))) - ) - ) - (import "b1" (instance (;0;) (type 0))) - (import "b2" (instance (;1;) (type 0))) - (alias export 0 "m" (func (;0;))) - (alias export 1 "m" (func (;1;))) - (export "m1" (func 0)) - (export "m2" (func 1)) - ) - (alias export 1 "x" (instance (;3;))) - (alias export 2 "x" (instance (;4;))) - (instance (;5;) (instantiate 2 - (with "b2" (instance 3)) - (with "b1" (instance 4)) + (alias export 2 "x" (instance (;3;))) + (alias export 1 "x" (instance (;4;))) + (instance (;5;) (instantiate 0 + (with "b1" (instance 3)) + (with "b2" (instance 4)) ) ) (alias export 5 "m1" (func (;0;))) - (alias export 5 "m2" (func (;1;))) - (export "m1" (func 0)) - (export "m2" (func 1)) + (export (;1;) "m1" (func 0)) + (alias export 5 "m2" (func (;2;))) + (export (;3;) "m2" (func 2)) ) diff --git a/crates/wasm-compose/tests/compositions/component-incorrect-version/error.txt b/crates/wasm-compose/tests/compositions/component-incorrect-version/error.txt index fe98507768..1607f4dbf6 100644 --- a/crates/wasm-compose/tests/compositions/component-incorrect-version/error.txt +++ b/crates/wasm-compose/tests/compositions/component-incorrect-version/error.txt @@ -1,4 +1,4 @@ failed to parse component `tests/compositions/component-incorrect-version/a.wasm` Caused by: - unknown binary version (at offset 0x4) + unknown binary version: 0x101000a (at offset 0x4) diff --git a/crates/wasm-compose/tests/compositions/component-missing/error.txt b/crates/wasm-compose/tests/compositions/component-missing/error.txt index 61c880b6a6..8b88baf34a 100644 --- a/crates/wasm-compose/tests/compositions/component-missing/error.txt +++ b/crates/wasm-compose/tests/compositions/component-missing/error.txt @@ -1,5 +1,5 @@ failed to parse component `tests/compositions/component-missing/a.wat` Caused by: - 0: failed to read from `tests/compositions/component-missing/a.wat`: No such file or directory (os error 2) - 1: No such file or directory (os error 2) + 0: failed to read from `tests/compositions/component-missing/a.wat` + 1: platform-specific error diff --git a/crates/wasm-compose/tests/compositions/component-not-valid/error.txt b/crates/wasm-compose/tests/compositions/component-not-valid/error.txt index 8c365ffc7b..62b3a24fc9 100644 --- a/crates/wasm-compose/tests/compositions/component-not-valid/error.txt +++ b/crates/wasm-compose/tests/compositions/component-not-valid/error.txt @@ -1,4 +1,4 @@ -failed to validate WebAssembly component `tests/compositions/component-not-valid/root.wat` +failed to parse component `tests/compositions/component-not-valid/root.wat` Caused by: - unknown core function 0: function index out of bounds (at offset 0x13) + unknown core function 0: function index out of bounds (at offset 0x12) diff --git a/crates/wasm-compose/tests/compositions/component-not-wat/error.txt b/crates/wasm-compose/tests/compositions/component-not-wat/error.txt index 39d3ab0458..8d8d29ed84 100644 --- a/crates/wasm-compose/tests/compositions/component-not-wat/error.txt +++ b/crates/wasm-compose/tests/compositions/component-not-wat/error.txt @@ -2,7 +2,7 @@ failed to parse component `tests/compositions/component-not-wat/root.wat` Caused by: expected `(` - --> tests/compositions/component-not-wat/root.wat:1:1 - | - 1 | not valid - | ^ + --> tests/compositions/component-not-wat/root.wat:1:1 + | + 1 | not valid + | ^ diff --git a/crates/wasm-compose/tests/compositions/conflict-on-import/b.wat b/crates/wasm-compose/tests/compositions/conflict-on-import/b.wat index bf897c5560..330f8c8c72 100644 --- a/crates/wasm-compose/tests/compositions/conflict-on-import/b.wat +++ b/crates/wasm-compose/tests/compositions/conflict-on-import/b.wat @@ -1,3 +1,3 @@ (component - (import "a" (instance (export "x" (func (param string))))) + (import "a" (instance (export "x" (func (param "x" string))))) ) diff --git a/crates/wasm-compose/tests/compositions/conflict-on-import/error.txt b/crates/wasm-compose/tests/compositions/conflict-on-import/error.txt index 2fb1d40846..2b5cf6dafd 100644 --- a/crates/wasm-compose/tests/compositions/conflict-on-import/error.txt +++ b/crates/wasm-compose/tests/compositions/conflict-on-import/error.txt @@ -1 +1 @@ -cannot import instance `a` due to conflicting types for export `x` between components `tests/compositions/conflict-on-import/root.wat` and `tests/compositions/conflict-on-import/b.wat` +cannot import instance with name `a` for an instantiation argument of component `b` because it conflicts with an imported instantiation argument of component `$input` diff --git a/crates/wasm-compose/tests/compositions/def-mismatch/config.yml b/crates/wasm-compose/tests/compositions/def-mismatch/config.yml new file mode 100644 index 0000000000..77a13f0fca --- /dev/null +++ b/crates/wasm-compose/tests/compositions/def-mismatch/config.yml @@ -0,0 +1 @@ +definitions: ['definitions.wat'] diff --git a/crates/wasm-compose/tests/compositions/def-mismatch/definitions.wat b/crates/wasm-compose/tests/compositions/def-mismatch/definitions.wat new file mode 100644 index 0000000000..7e263d1485 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/def-mismatch/definitions.wat @@ -0,0 +1,4 @@ +(component + (instance) + (export "foo" (instance 0)) +) diff --git a/crates/wasm-compose/tests/compositions/def-mismatch/error.txt b/crates/wasm-compose/tests/compositions/def-mismatch/error.txt new file mode 100644 index 0000000000..984c585471 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/def-mismatch/error.txt @@ -0,0 +1,4 @@ +failed to connect instance `$input` to definition component `tests/compositions/def-mismatch/definitions.wat` + +Caused by: + source instance export `foo` is not compatible with target instance import `foo` diff --git a/crates/wasm-compose/tests/compositions/def-mismatch/root.wat b/crates/wasm-compose/tests/compositions/def-mismatch/root.wat new file mode 100644 index 0000000000..2fc7c23a15 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/def-mismatch/root.wat @@ -0,0 +1,3 @@ +(component + (import "foo" (instance (export "foo" (func)))) +) diff --git a/crates/wasm-compose/tests/compositions/defs/cli.wat b/crates/wasm-compose/tests/compositions/defs/cli.wat new file mode 100644 index 0000000000..425e23fd5b --- /dev/null +++ b/crates/wasm-compose/tests/compositions/defs/cli.wat @@ -0,0 +1,70 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32))) + (type (;3;) (func (param i32 i32) (result i32))) + (type (;4;) (func (param i32 i32 i32))) + (type (;5;) (func (param i32 i32 i32 i32) (result i32))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (param i32 i32))) + (type (;8;) (func (param i32 i32 i32) (result i32))) + (func $__wasm_call_ctors (;0;) (type 0)) + (func $wasi:cli-base/environment#get-environment (;1;) (type 1) (result i32) + i32.const 0 + ) + (func $cabi_post_wasi:cli-base/environment#get-environment (;2;) (type 2) (param i32)) + (func $wasi:cli-base/environment#get-arguments (;3;) (type 1) (result i32) + i32.const 0 + ) + (func $cabi_post_wasi:cli-base/environment#get-arguments (;4;) (type 2) (param i32)) + (func $cabi_realloc (;10;) (type 5) (param i32 i32 i32 i32) (result i32) + i32.const 0 + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 17) + (global $__stack_pointer (;0;) (mut i32) i32.const 1048576) + (export "memory" (memory 0)) + (export "wasi:cli-base/environment#get-environment" (func $wasi:cli-base/environment#get-environment)) + (export "cabi_post_wasi:cli-base/environment#get-environment" (func $cabi_post_wasi:cli-base/environment#get-environment)) + (export "wasi:cli-base/environment#get-arguments" (func $wasi:cli-base/environment#get-arguments)) + (export "cabi_post_wasi:cli-base/environment#get-arguments" (func $cabi_post_wasi:cli-base/environment#get-arguments)) + (export "cabi_realloc" (func $cabi_realloc)) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "cabi_realloc" (core func (;0;))) + (type (;0;) (tuple string string)) + (type (;1;) (list 0)) + (type (;2;) (func (result 1))) + (alias core export 0 "wasi:cli-base/environment#get-environment" (core func (;1;))) + (alias core export 0 "cabi_post_wasi:cli-base/environment#get-environment" (core func (;2;))) + (func (;0;) (type 2) (canon lift (core func 1) (memory 0) string-encoding=utf8 (post-return 2))) + (type (;3;) (list string)) + (type (;4;) (func (result 3))) + (alias core export 0 "wasi:cli-base/environment#get-arguments" (core func (;3;))) + (alias core export 0 "cabi_post_wasi:cli-base/environment#get-arguments" (core func (;4;))) + (func (;1;) (type 4) (canon lift (core func 3) (memory 0) string-encoding=utf8 (post-return 4))) + (component (;0;) + (type (;0;) (tuple string string)) + (type (;1;) (list 0)) + (type (;2;) (func (result 1))) + (import "import-func-get-environment" (func (;0;) (type 2))) + (type (;3;) (list string)) + (type (;4;) (func (result 3))) + (import "import-func-get-arguments" (func (;1;) (type 4))) + (type (;5;) (tuple string string)) + (type (;6;) (list 5)) + (type (;7;) (func (result 6))) + (export (;2;) "get-environment" (func 0) (func (type 7))) + (type (;8;) (list string)) + (type (;9;) (func (result 8))) + (export (;3;) "get-arguments" (func 1) (func (type 9))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-get-environment" (func 0)) + (with "import-func-get-arguments" (func 1)) + ) + ) + (export (;1;) (interface "wasi:cli-base/environment") (instance 0)) +) diff --git a/crates/wasm-compose/tests/compositions/defs/composed.wat b/crates/wasm-compose/tests/compositions/defs/composed.wat new file mode 100644 index 0000000000..16b1d39d93 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/defs/composed.wat @@ -0,0 +1,185 @@ +(component + (component (;0;) + (type (;0;) + (instance + (type (;0;) (tuple string string)) + (type (;1;) (list 0)) + (type (;2;) (func (result 1))) + (export (;0;) "get-environment" (func (type 2))) + (type (;3;) (list string)) + (type (;4;) (func (result 3))) + (export (;1;) "get-arguments" (func (type 4))) + ) + ) + (import (interface "wasi:cli-base/environment") (instance (;0;) (type 0))) + (type (;1;) + (instance) + ) + (import "other1" (instance (;1;) (type 1))) + (type (;2;) + (instance) + ) + (import "other2" (instance (;2;) (type 2))) + (core module (;0;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "wasi:cli-base/environment" "get-environment" (func (;0;) (type 0))) + (import "wasi:cli-base/environment" "get-arguments" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 0) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 2)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (func $indirect-wasi:cli-base/environment-get-environment (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $indirect-wasi:cli-base/environment-get-arguments (;1;) (type 0) (param i32) + local.get 0 + i32.const 1 + call_indirect (type 0) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-wasi:cli-base/environment-get-environment)) + (export "1" (func $indirect-wasi:cli-base/environment-get-arguments)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (core instance (;0;) (instantiate 1)) + (alias core export 0 "0" (core func (;0;))) + (alias core export 0 "1" (core func (;1;))) + (core instance (;1;) + (export "get-environment" (func 0)) + (export "get-arguments" (func 1)) + ) + (core instance (;2;) (instantiate 0 + (with "wasi:cli-base/environment" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;2;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "get-environment" (func (;0;))) + (core func (;3;) (canon lower (func 0) (memory 0) (realloc 2) string-encoding=utf8)) + (alias export 0 "get-arguments" (func (;1;))) + (core func (;4;) (canon lower (func 1) (memory 0) (realloc 2) string-encoding=utf8)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + (core instance (;3;) + (export "$imports" (table 0)) + (export "0" (func 3)) + (export "1" (func 4)) + ) + (core instance (;4;) (instantiate 2 + (with "" (instance 3)) + ) + ) + ) + (component (;1;) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32))) + (type (;3;) (func (param i32 i32) (result i32))) + (type (;4;) (func (param i32 i32 i32))) + (type (;5;) (func (param i32 i32 i32 i32) (result i32))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (param i32 i32))) + (type (;8;) (func (param i32 i32 i32) (result i32))) + (func $__wasm_call_ctors (;0;) (type 0)) + (func $wasi:cli-base/environment#get-environment (;1;) (type 1) (result i32) + i32.const 0 + ) + (func $cabi_post_wasi:cli-base/environment#get-environment (;2;) (type 2) (param i32)) + (func $wasi:cli-base/environment#get-arguments (;3;) (type 1) (result i32) + i32.const 0 + ) + (func $cabi_post_wasi:cli-base/environment#get-arguments (;4;) (type 2) (param i32)) + (func $cabi_realloc (;5;) (type 5) (param i32 i32 i32 i32) (result i32) + i32.const 0 + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 17) + (global $__stack_pointer (;0;) (mut i32) i32.const 1048576) + (export "memory" (memory 0)) + (export "wasi:cli-base/environment#get-environment" (func $wasi:cli-base/environment#get-environment)) + (export "cabi_post_wasi:cli-base/environment#get-environment" (func $cabi_post_wasi:cli-base/environment#get-environment)) + (export "wasi:cli-base/environment#get-arguments" (func $wasi:cli-base/environment#get-arguments)) + (export "cabi_post_wasi:cli-base/environment#get-arguments" (func $cabi_post_wasi:cli-base/environment#get-arguments)) + (export "cabi_realloc" (func $cabi_realloc)) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "cabi_realloc" (core func (;0;))) + (type (;0;) (tuple string string)) + (type (;1;) (list 0)) + (type (;2;) (func (result 1))) + (alias core export 0 "wasi:cli-base/environment#get-environment" (core func (;1;))) + (alias core export 0 "cabi_post_wasi:cli-base/environment#get-environment" (core func (;2;))) + (func (;0;) (type 2) (canon lift (core func 1) (memory 0) string-encoding=utf8 (post-return 2))) + (type (;3;) (list string)) + (type (;4;) (func (result 3))) + (alias core export 0 "wasi:cli-base/environment#get-arguments" (core func (;3;))) + (alias core export 0 "cabi_post_wasi:cli-base/environment#get-arguments" (core func (;4;))) + (func (;1;) (type 4) (canon lift (core func 3) (memory 0) string-encoding=utf8 (post-return 4))) + (component (;0;) + (type (;0;) (tuple string string)) + (type (;1;) (list 0)) + (type (;2;) (func (result 1))) + (import "import-func-get-environment" (func (;0;) (type 2))) + (type (;3;) (list string)) + (type (;4;) (func (result 3))) + (import "import-func-get-arguments" (func (;1;) (type 4))) + (type (;5;) (tuple string string)) + (type (;6;) (list 5)) + (type (;7;) (func (result 6))) + (export (;2;) "get-environment" (func 0) (func (type 7))) + (type (;8;) (list string)) + (type (;9;) (func (result 8))) + (export (;3;) "get-arguments" (func 1) (func (type 9))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-get-environment" (func 0)) + (with "import-func-get-arguments" (func 1)) + ) + ) + (export (;1;) (interface "wasi:cli-base/environment") (instance 0)) + ) + (component (;2;) + (instance (;0;)) + (export (;1;) "other1" (instance 0)) + (export (;2;) "other2" (instance 0)) + ) + (instance (;0;) (instantiate 2)) + (instance (;1;) (instantiate 1)) + (alias export 1 "wasi:cli-base/environment" (instance (;2;))) + (alias export 0 "other1" (instance (;3;))) + (alias export 0 "other2" (instance (;4;))) + (instance (;5;) (instantiate 0 + (with "wasi:cli-base/environment" (instance 2)) + (with "other1" (instance 3)) + (with "other2" (instance 4)) + ) + ) +) diff --git a/crates/wasm-compose/tests/compositions/defs/config.yml b/crates/wasm-compose/tests/compositions/defs/config.yml new file mode 100644 index 0000000000..f6633e022a --- /dev/null +++ b/crates/wasm-compose/tests/compositions/defs/config.yml @@ -0,0 +1 @@ +definitions: ['cli.wat', 'other.wat'] diff --git a/crates/wasm-compose/tests/compositions/defs/other.wat b/crates/wasm-compose/tests/compositions/defs/other.wat new file mode 100644 index 0000000000..6670a482ac --- /dev/null +++ b/crates/wasm-compose/tests/compositions/defs/other.wat @@ -0,0 +1,5 @@ +(component + (instance) + (export "other1" (instance 0)) + (export "other2" (instance 0)) +) diff --git a/crates/wasm-compose/tests/compositions/defs/root.wat b/crates/wasm-compose/tests/compositions/defs/root.wat new file mode 100644 index 0000000000..59a6114da3 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/defs/root.wat @@ -0,0 +1,91 @@ +(component + (type (;0;) + (instance + (type (;0;) (tuple string string)) + (type (;1;) (list 0)) + (type (;2;) (func (result 1))) + (export (;0;) "get-environment" (func (type 2))) + (type (;3;) (list string)) + (type (;4;) (func (result 3))) + (export (;1;) "get-arguments" (func (type 4))) + ) + ) + (import (interface "wasi:cli-base/environment") (instance (;0;) (type 0))) + (import "other1" (instance (;0;))) + (import "other2" (instance (;0;))) + (core module (;0;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "wasi:cli-base/environment" "get-environment" (func (;0;) (type 0))) + (import "wasi:cli-base/environment" "get-arguments" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 0) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 2)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (func $indirect-wasi:cli-base/environment-get-environment (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $indirect-wasi:cli-base/environment-get-arguments (;1;) (type 0) (param i32) + local.get 0 + i32.const 1 + call_indirect (type 0) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-wasi:cli-base/environment-get-environment)) + (export "1" (func $indirect-wasi:cli-base/environment-get-arguments)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (core instance (;0;) (instantiate 1)) + (alias core export 0 "0" (core func (;0;))) + (alias core export 0 "1" (core func (;1;))) + (core instance (;1;) + (export "get-environment" (func 0)) + (export "get-arguments" (func 1)) + ) + (core instance (;2;) (instantiate 0 + (with "wasi:cli-base/environment" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;2;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "get-environment" (func (;0;))) + (core func (;3;) (canon lower (func 0) (memory 0) (realloc 2) string-encoding=utf8)) + (alias export 0 "get-arguments" (func (;1;))) + (core func (;4;) (canon lower (func 1) (memory 0) (realloc 2) string-encoding=utf8)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + (core instance (;3;) + (export "$imports" (table 0)) + (export "0" (func 3)) + (export "1" (func 4)) + ) + (core instance (;4;) (instantiate 2 + (with "" (instance 3)) + ) + ) +) \ No newline at end of file diff --git a/crates/wasm-compose/tests/compositions/export-on-import/config.yml b/crates/wasm-compose/tests/compositions/export-on-import/config.yml index 4d21d91d02..0a0d48cca5 100644 --- a/crates/wasm-compose/tests/compositions/export-on-import/config.yml +++ b/crates/wasm-compose/tests/compositions/export-on-import/config.yml @@ -1,5 +1,5 @@ instantiations: - $component: + $input: arguments: a: instance: a diff --git a/crates/wasm-compose/tests/compositions/import-conflict/a.wat b/crates/wasm-compose/tests/compositions/import-conflict/a.wat deleted file mode 100644 index e5627d1d0f..0000000000 --- a/crates/wasm-compose/tests/compositions/import-conflict/a.wat +++ /dev/null @@ -1 +0,0 @@ -(component) diff --git a/crates/wasm-compose/tests/compositions/import-conflict/config.yml b/crates/wasm-compose/tests/compositions/import-conflict/config.yml deleted file mode 100644 index e935abbc8b..0000000000 --- a/crates/wasm-compose/tests/compositions/import-conflict/config.yml +++ /dev/null @@ -1,4 +0,0 @@ -dependencies: - a: - path: a.wat - import: b diff --git a/crates/wasm-compose/tests/compositions/import-conflict/error.txt b/crates/wasm-compose/tests/compositions/import-conflict/error.txt deleted file mode 100644 index 3348ce5c4e..0000000000 --- a/crates/wasm-compose/tests/compositions/import-conflict/error.txt +++ /dev/null @@ -1 +0,0 @@ -cannot import dependency `a` (`tests/compositions/import-conflict/a.wat`) with name `b` because it conflicts with an imported instance or component of the same name diff --git a/crates/wasm-compose/tests/compositions/import-conflict/root.wat b/crates/wasm-compose/tests/compositions/import-conflict/root.wat deleted file mode 100644 index e163155980..0000000000 --- a/crates/wasm-compose/tests/compositions/import-conflict/root.wat +++ /dev/null @@ -1,4 +0,0 @@ -(component - (import "a" (instance)) - (import "b" (instance)) -) diff --git a/crates/wasm-compose/tests/compositions/incompatible-explicit-export/config.yml b/crates/wasm-compose/tests/compositions/incompatible-explicit-export/config.yml index 4d21d91d02..0a0d48cca5 100644 --- a/crates/wasm-compose/tests/compositions/incompatible-explicit-export/config.yml +++ b/crates/wasm-compose/tests/compositions/incompatible-explicit-export/config.yml @@ -1,5 +1,5 @@ instantiations: - $component: + $input: arguments: a: instance: a diff --git a/crates/wasm-compose/tests/compositions/instantiation-cycle/a.wat b/crates/wasm-compose/tests/compositions/instantiation-cycle/a.wat index fde728d1dd..c026d7b837 100644 --- a/crates/wasm-compose/tests/compositions/instantiation-cycle/a.wat +++ b/crates/wasm-compose/tests/compositions/instantiation-cycle/a.wat @@ -1,5 +1,5 @@ (component - (import "a" (instance (export "a" (func)))) + (import "b" (instance (export "a" (func)))) (alias export 0 "a" (func)) (export "a" (func 0)) ) diff --git a/crates/wasm-compose/tests/compositions/instantiation-cycle/config.yml b/crates/wasm-compose/tests/compositions/instantiation-cycle/config.yml index 01691bd5d4..b95f8ad691 100644 --- a/crates/wasm-compose/tests/compositions/instantiation-cycle/config.yml +++ b/crates/wasm-compose/tests/compositions/instantiation-cycle/config.yml @@ -1,12 +1,12 @@ instantiations: - $component: + $input: arguments: - a: a1 + b: a1 a1: dependency: a arguments: - a: a2 + b: a2 a2: dependency: a arguments: - a: a1 + b: a1 diff --git a/crates/wasm-compose/tests/compositions/instantiation-cycle/error.txt b/crates/wasm-compose/tests/compositions/instantiation-cycle/error.txt index 7b0a2610f8..363960b3b5 100644 --- a/crates/wasm-compose/tests/compositions/instantiation-cycle/error.txt +++ b/crates/wasm-compose/tests/compositions/instantiation-cycle/error.txt @@ -1 +1 @@ -instantiation `a2` and its dependencies form a cycle in the instantiation graph +an instantiation of component `a` and its dependencies form a cycle in the instantiation graph diff --git a/crates/wasm-compose/tests/compositions/instantiation-cycle/root.wat b/crates/wasm-compose/tests/compositions/instantiation-cycle/root.wat index d440336f4d..12042d438e 100644 --- a/crates/wasm-compose/tests/compositions/instantiation-cycle/root.wat +++ b/crates/wasm-compose/tests/compositions/instantiation-cycle/root.wat @@ -1,3 +1,3 @@ (component - (import "a" (instance (export "a" (func)))) + (import "b" (instance (export "a" (func)))) ) diff --git a/crates/wasm-compose/tests/compositions/invalid-instantiation-arg/config.yml b/crates/wasm-compose/tests/compositions/invalid-instantiation-arg/config.yml index 176e093107..9117c70abf 100644 --- a/crates/wasm-compose/tests/compositions/invalid-instantiation-arg/config.yml +++ b/crates/wasm-compose/tests/compositions/invalid-instantiation-arg/config.yml @@ -1,4 +1,4 @@ instantiations: - $component: + $input: arguments: invalid: a diff --git a/crates/wasm-compose/tests/compositions/merged-import/b.wat b/crates/wasm-compose/tests/compositions/merged-import/b.wat index 3e4d69c0fb..cf222f21da 100644 --- a/crates/wasm-compose/tests/compositions/merged-import/b.wat +++ b/crates/wasm-compose/tests/compositions/merged-import/b.wat @@ -1,3 +1,3 @@ (component - (import "a" (instance (export "a" (func (param string))) (export "c" (func (param u64))))) + (import "a" (instance (export "a" (func (param "x" string))) (export "c" (func (param "y" u32))))) ) diff --git a/crates/wasm-compose/tests/compositions/merged-import/composed.wat b/crates/wasm-compose/tests/compositions/merged-import/composed.wat index a355a785ce..fcf4db2832 100644 --- a/crates/wasm-compose/tests/compositions/merged-import/composed.wat +++ b/crates/wasm-compose/tests/compositions/merged-import/composed.wat @@ -1,46 +1,46 @@ (component - (type (;0;) + (type (;0;) (instance (type (;0;) (func)) - (export "b" (func (type 0))) - (type (;1;) (func (param u64))) - (export "c" (func (type 1))) - (type (;2;) (func (param string))) - (export "a" (func (type 2))) + (export (;0;) "b" (func (type 0))) + (type (;1;) (func (param "y" u32))) + (export (;1;) "c" (func (type 1))) + (type (;2;) (func (param "x" string))) + (export (;2;) "a" (func (type 2))) ) ) (import "a" (instance (;0;) (type 0))) (component (;0;) - (type (;0;) + (type (;0;) (instance - (type (;0;) (func (param string))) - (export "a" (func (type 0))) - (type (;1;) (func (param u64))) - (export "c" (func (type 1))) + (type (;0;) (func)) + (export (;0;) "b" (func (type 0))) + (type (;1;) (func (param "y" u32))) + (export (;1;) "c" (func (type 1))) ) ) (import "a" (instance (;0;) (type 0))) - ) - (instance (;1;) (instantiate 0 - (with "a" (instance 0)) + (type (;1;) + (instance) ) + (import "b" (instance (;1;) (type 1))) ) (component (;1;) - (type (;0;) + (type (;0;) (instance - (type (;0;) (func)) - (export "b" (func (type 0))) - (type (;1;) (func (param u32))) - (export "c" (func (type 1))) + (type (;0;) (func (param "x" string))) + (export (;0;) "a" (func (type 0))) + (type (;1;) (func (param "y" u32))) + (export (;1;) "c" (func (type 1))) ) ) (import "a" (instance (;0;) (type 0))) - (type (;1;) - (instance) + ) + (instance (;1;) (instantiate 1 + (with "a" (instance 0)) ) - (import "b" (instance (;1;) (type 1))) ) - (instance (;2;) (instantiate 1 + (instance (;2;) (instantiate 0 (with "b" (instance 1)) (with "a" (instance 0)) ) diff --git a/crates/wasm-compose/tests/compositions/merged-import/root.wat b/crates/wasm-compose/tests/compositions/merged-import/root.wat index 95057e9915..3516fe2814 100644 --- a/crates/wasm-compose/tests/compositions/merged-import/root.wat +++ b/crates/wasm-compose/tests/compositions/merged-import/root.wat @@ -1,4 +1,4 @@ (component - (import "a" (instance (export "b" (func)) (export "c" (func (param u32))))) + (import "a" (instance (export "b" (func)) (export "c" (func (param "y" u32))))) (import "b" (instance)) ) diff --git a/crates/wasm-compose/tests/compositions/missing-explicit-dep/config.yml b/crates/wasm-compose/tests/compositions/missing-explicit-dep/config.yml index 9db16d0bd6..fbc245fb7a 100644 --- a/crates/wasm-compose/tests/compositions/missing-explicit-dep/config.yml +++ b/crates/wasm-compose/tests/compositions/missing-explicit-dep/config.yml @@ -1,7 +1,2 @@ dependencies: a: a.wat - -instantiations: - $component: - arguments: - '': a diff --git a/crates/wasm-compose/tests/compositions/missing-explicit-dep/error.txt b/crates/wasm-compose/tests/compositions/missing-explicit-dep/error.txt index 36521b6996..ed7bb6813f 100644 --- a/crates/wasm-compose/tests/compositions/missing-explicit-dep/error.txt +++ b/crates/wasm-compose/tests/compositions/missing-explicit-dep/error.txt @@ -1,5 +1,5 @@ failed to parse component `tests/compositions/missing-explicit-dep/a.wat` Caused by: - 0: failed to read from `tests/compositions/missing-explicit-dep/a.wat`: No such file or directory (os error 2) - 1: No such file or directory (os error 2) + 0: failed to read from `tests/compositions/missing-explicit-dep/a.wat` + 1: platform-specific error diff --git a/crates/wasm-compose/tests/compositions/missing-explicit-dep/root.wat b/crates/wasm-compose/tests/compositions/missing-explicit-dep/root.wat index 32d696c472..6c6d721b97 100644 --- a/crates/wasm-compose/tests/compositions/missing-explicit-dep/root.wat +++ b/crates/wasm-compose/tests/compositions/missing-explicit-dep/root.wat @@ -1,3 +1,3 @@ (component - (import "" (instance)) + (import "a" (instance)) ) diff --git a/crates/wasm-compose/tests/compositions/missing-explicit-export/config.yml b/crates/wasm-compose/tests/compositions/missing-explicit-export/config.yml index 4d21d91d02..0a0d48cca5 100644 --- a/crates/wasm-compose/tests/compositions/missing-explicit-export/config.yml +++ b/crates/wasm-compose/tests/compositions/missing-explicit-export/config.yml @@ -1,5 +1,5 @@ instantiations: - $component: + $input: arguments: a: instance: a diff --git a/crates/wasm-compose/tests/compositions/missing-root/error.txt b/crates/wasm-compose/tests/compositions/missing-root/error.txt index 8778fc129c..d3d92144f4 100644 --- a/crates/wasm-compose/tests/compositions/missing-root/error.txt +++ b/crates/wasm-compose/tests/compositions/missing-root/error.txt @@ -1,5 +1,5 @@ failed to parse component `tests/compositions/missing-root/root.wat` Caused by: - 0: failed to read from `tests/compositions/missing-root/root.wat`: No such file or directory (os error 2) - 1: No such file or directory (os error 2) + 0: failed to read from `tests/compositions/missing-root/root.wat` + 1: platform-specific error diff --git a/crates/wasm-compose/tests/compositions/module/error.txt b/crates/wasm-compose/tests/compositions/module/error.txt index 06441813f2..94c1e8c4fa 100644 --- a/crates/wasm-compose/tests/compositions/module/error.txt +++ b/crates/wasm-compose/tests/compositions/module/error.txt @@ -1 +1,4 @@ -file `tests/compositions/module/root.wat` is not a WebAssembly component +failed to parse component `tests/compositions/module/root.wat` + +Caused by: + the file is not a WebAssembly component diff --git a/crates/wasm-compose/tests/compositions/not-instance-import/error.txt b/crates/wasm-compose/tests/compositions/not-instance-import/error.txt index f63d52e40d..712f641ee6 100644 --- a/crates/wasm-compose/tests/compositions/not-instance-import/error.txt +++ b/crates/wasm-compose/tests/compositions/not-instance-import/error.txt @@ -1 +1 @@ -component `tests/compositions/not-instance-import/root.wat` has a non-instance import named `` +component `tests/compositions/not-instance-import/root.wat` has a non-instance import named `a` diff --git a/crates/wasm-compose/tests/compositions/not-instance-import/root.wat b/crates/wasm-compose/tests/compositions/not-instance-import/root.wat index 51e933a8ef..6e38697eec 100644 --- a/crates/wasm-compose/tests/compositions/not-instance-import/root.wat +++ b/crates/wasm-compose/tests/compositions/not-instance-import/root.wat @@ -1,3 +1,3 @@ (component - (import "" (func)) + (import "a" (func)) ) diff --git a/crates/wasm-compose/tests/compositions/resort-imports/a.wat b/crates/wasm-compose/tests/compositions/resort-imports/a.wat new file mode 100644 index 0000000000..36d2768298 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/resort-imports/a.wat @@ -0,0 +1,10 @@ +(component + (import "dep1" (instance $dep1 + (type $t' u32) + (export $t "t" (type (eq $t'))) + )) + (alias export $dep1 "t" (type $t-dep1)) + (import "dep2" (instance + (export "f1" (func (result $t-dep1))) + )) +) diff --git a/crates/wasm-compose/tests/compositions/resort-imports/b.wat b/crates/wasm-compose/tests/compositions/resort-imports/b.wat new file mode 100644 index 0000000000..c8eac434a7 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/resort-imports/b.wat @@ -0,0 +1,10 @@ +(component + (import "dep0" (instance $dep0 + (type $t' u32) + (export $t "t" (type (eq $t'))) + )) + (alias export $dep0 "t" (type $t-dep0)) + (import "dep2" (instance + (export "f2" (func (result $t-dep0))) + )) +) diff --git a/crates/wasm-compose/tests/compositions/resort-imports/composed.wat b/crates/wasm-compose/tests/compositions/resort-imports/composed.wat new file mode 100644 index 0000000000..3f78b7095d --- /dev/null +++ b/crates/wasm-compose/tests/compositions/resort-imports/composed.wat @@ -0,0 +1,90 @@ +(component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import "dep0" (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import "dep1" (instance (;1;) (type 1))) + (alias export 0 "t" (type (;2;))) + (alias export 1 "t" (type (;3;))) + (type (;4;) + (instance + (alias outer 1 2 (type (;0;))) + (type (;1;) (func (result 0))) + (export (;0;) "f2" (func (type 1))) + (alias outer 1 3 (type (;2;))) + (type (;3;) (func (result 2))) + (export (;1;) "f1" (func (type 3))) + ) + ) + (import "dep2" (instance (;2;) (type 4))) + (component (;0;) + (type (;0;) + (instance) + ) + (import "b" (instance (;0;) (type 0))) + (type (;1;) + (instance) + ) + (import "a" (instance (;1;) (type 1))) + ) + (component (;1;) + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import "dep0" (instance $dep0 (;0;) (type 0))) + (alias export $dep0 "t" (type $t-dep0 (;1;))) + (type (;2;) + (instance + (alias outer 1 $t-dep0 (type (;0;))) + (type (;1;) (func (result 0))) + (export (;0;) "f2" (func (type 1))) + ) + ) + (import "dep2" (instance (;1;) (type 2))) + ) + (component (;2;) + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import "dep1" (instance $dep1 (;0;) (type 0))) + (alias export $dep1 "t" (type $t-dep1 (;1;))) + (type (;2;) + (instance + (alias outer 1 $t-dep1 (type (;0;))) + (type (;1;) (func (result 0))) + (export (;0;) "f1" (func (type 1))) + ) + ) + (import "dep2" (instance (;1;) (type 2))) + ) + (instance (;3;) (instantiate 2 + (with "dep1" (instance 1)) + (with "dep2" (instance 2)) + ) + ) + (instance (;4;) (instantiate 1 + (with "dep0" (instance 0)) + (with "dep2" (instance 2)) + ) + ) + (instance (;5;) (instantiate 0 + (with "b" (instance 4)) + (with "a" (instance 3)) + ) + ) +) diff --git a/crates/wasm-compose/tests/compositions/resort-imports/root.wat b/crates/wasm-compose/tests/compositions/resort-imports/root.wat new file mode 100644 index 0000000000..865cb352a1 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/resort-imports/root.wat @@ -0,0 +1,4 @@ +(component + (import "b" (instance)) + (import "a" (instance)) +) diff --git a/crates/wasm-compose/tests/compositions/type-use-and-merge/a.wat b/crates/wasm-compose/tests/compositions/type-use-and-merge/a.wat new file mode 100644 index 0000000000..ede507d55a --- /dev/null +++ b/crates/wasm-compose/tests/compositions/type-use-and-merge/a.wat @@ -0,0 +1,8 @@ +(component + (import "c" (instance + (type $dummy u32) + (type $t' u32) + (export $t "t" (type (eq $t'))) + (export "f1" (func (result $t))) + )) +) diff --git a/crates/wasm-compose/tests/compositions/type-use-and-merge/b.wat b/crates/wasm-compose/tests/compositions/type-use-and-merge/b.wat new file mode 100644 index 0000000000..66f6c5bdd5 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/type-use-and-merge/b.wat @@ -0,0 +1,7 @@ +(component + (import "c" (instance + (type $t' u32) + (export $t "t" (type (eq $t'))) + (export "f2" (func (result $t))) + )) +) diff --git a/crates/wasm-compose/tests/compositions/type-use-and-merge/composed.wat b/crates/wasm-compose/tests/compositions/type-use-and-merge/composed.wat new file mode 100644 index 0000000000..ff98075310 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/type-use-and-merge/composed.wat @@ -0,0 +1,59 @@ +(component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + (type (;2;) (func (result 1))) + (export (;0;) "f2" (func (type 2))) + (type (;3;) (func (result 1))) + (export (;1;) "f1" (func (type 3))) + ) + ) + (import "c" (instance (;0;) (type 0))) + (component (;0;) + (type (;0;) + (instance) + ) + (import "b" (instance (;0;) (type 0))) + (type (;1;) + (instance) + ) + (import "a" (instance (;1;) (type 1))) + ) + (component (;1;) + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + (type (;2;) (func (result 1))) + (export (;0;) "f2" (func (type 2))) + ) + ) + (import "c" (instance (;0;) (type 0))) + ) + (component (;2;) + (type (;0;) + (instance + (type (;0;) u32) + (type (;1;) u32) + (export (;2;) "t" (type (eq 1))) + (type (;3;) (func (result 2))) + (export (;0;) "f1" (func (type 3))) + ) + ) + (import "c" (instance (;0;) (type 0))) + ) + (instance (;1;) (instantiate 2 + (with "c" (instance 0)) + ) + ) + (instance (;2;) (instantiate 1 + (with "c" (instance 0)) + ) + ) + (instance (;3;) (instantiate 0 + (with "b" (instance 2)) + (with "a" (instance 1)) + ) + ) +) diff --git a/crates/wasm-compose/tests/compositions/type-use-and-merge/root.wat b/crates/wasm-compose/tests/compositions/type-use-and-merge/root.wat new file mode 100644 index 0000000000..865cb352a1 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/type-use-and-merge/root.wat @@ -0,0 +1,4 @@ +(component + (import "b" (instance)) + (import "a" (instance)) +) diff --git a/crates/wasm-compose/tests/compositions/type-use/a.wat b/crates/wasm-compose/tests/compositions/type-use/a.wat new file mode 100644 index 0000000000..019d3b0058 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/type-use/a.wat @@ -0,0 +1,41 @@ +(component + (import (interface "a:b/type-def") (instance $type-def + (type $r1' (record (field "f" u32))) + (export $r1 "r1" (type (eq $r1'))) + (type $r2' (record (field "r1" $r1))) + (export $r2 "r2" (type (eq $r2'))) + )) + (alias export $type-def "r1" (type $r1)) + (alias export $type-def "r2" (type $r2)) + (import (interface "a:b/type-use") (instance + (export "r1" (type (eq $r1))) + (export "r2" (type (eq $r2))) + )) + + (import (interface "a:b/type-use-in-same-interface") (instance + (type $t1' u32) + (export $t1 "t1" (type (eq $t1'))) + (export $t2 "t2" (type (eq $t1))) + )) + + (import (interface "a:b/diamond-base") (instance $diamond-base + (type $t u32) + (export "t" (type (eq $t))) + )) + (alias export $diamond-base "t" (type $t-diamond-base)) + + (import (interface "a:b/diamond1") (instance $diamond1 + (export "t" (type (eq $t-diamond-base))) + )) + (import (interface "a:b/diamond2") (instance $diamond2 + (export "t" (type (eq $t-diamond-base))) + )) + + (alias export $diamond1 "t" (type $t-diamond1)) + (alias export $diamond2 "t" (type $t-diamond2)) + + (import (interface "a:b/diamond-join") (instance + (export "t1" (type (eq $t-diamond1))) + (export "t2" (type (eq $t-diamond2))) + )) +) diff --git a/crates/wasm-compose/tests/compositions/type-use/composed.wat b/crates/wasm-compose/tests/compositions/type-use/composed.wat new file mode 100644 index 0000000000..18e2cd7a4c --- /dev/null +++ b/crates/wasm-compose/tests/compositions/type-use/composed.wat @@ -0,0 +1,147 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "f" u32))) + (export (;1;) "r1" (type (eq 0))) + (type (;2;) (record (field "r1" 1))) + (export (;3;) "r2" (type (eq 2))) + ) + ) + (import (interface "a:b/type-def") (instance (;0;) (type 0))) + (alias export 0 "r1" (type (;1;))) + (alias export 0 "r2" (type (;2;))) + (type (;3;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "r1" (type (eq 0))) + (alias outer 1 2 (type (;2;))) + (export (;3;) "r2" (type (eq 2))) + ) + ) + (import (interface "a:b/type-use") (instance (;1;) (type 3))) + (type (;4;) + (instance + (type (;0;) u32) + (export (;1;) "t1" (type (eq 0))) + (export (;2;) "t2" (type (eq 1))) + ) + ) + (import (interface "a:b/type-use-in-same-interface") (instance (;2;) (type 4))) + (type (;5;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import (interface "a:b/diamond-base") (instance (;3;) (type 5))) + (alias export 3 "t" (type (;6;))) + (type (;7;) + (instance + (alias outer 1 6 (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import (interface "a:b/diamond1") (instance (;4;) (type 7))) + (alias export 3 "t" (type (;8;))) + (type (;9;) + (instance + (alias outer 1 8 (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import (interface "a:b/diamond2") (instance (;5;) (type 9))) + (alias export 4 "t" (type (;10;))) + (alias export 5 "t" (type (;11;))) + (type (;12;) + (instance + (alias outer 1 10 (type (;0;))) + (export (;1;) "t1" (type (eq 0))) + (alias outer 1 11 (type (;2;))) + (export (;3;) "t2" (type (eq 2))) + ) + ) + (import (interface "a:b/diamond-join") (instance (;6;) (type 12))) + (component (;0;) + (type (;0;) + (instance) + ) + (import "a" (instance (;0;) (type 0))) + ) + (component (;1;) + (type (;0;) + (instance + (type (;0;) (record (field "f" u32))) + (export (;1;) "r1" (type (eq 0))) + (type (;2;) (record (field "r1" 1))) + (export (;3;) "r2" (type (eq 2))) + ) + ) + (import (interface "a:b/type-def") (instance $type-def (;0;) (type 0))) + (alias export $type-def "r1" (type $r1 (;1;))) + (alias export $type-def "r2" (type $r2 (;2;))) + (type (;3;) + (instance + (alias outer 1 $r1 (type (;0;))) + (export (;1;) "r1" (type (eq 0))) + (alias outer 1 $r2 (type (;2;))) + (export (;3;) "r2" (type (eq 2))) + ) + ) + (import (interface "a:b/type-use") (instance (;1;) (type 3))) + (type (;4;) + (instance + (type (;0;) u32) + (export (;1;) "t1" (type (eq 0))) + (export (;2;) "t2" (type (eq 1))) + ) + ) + (import (interface "a:b/type-use-in-same-interface") (instance (;2;) (type 4))) + (type (;5;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import (interface "a:b/diamond-base") (instance $diamond-base (;3;) (type 5))) + (alias export $diamond-base "t" (type $t-diamond-base (;6;))) + (type (;7;) + (instance + (alias outer 1 $t-diamond-base (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import (interface "a:b/diamond1") (instance $diamond1 (;4;) (type 7))) + (type (;8;) + (instance + (alias outer 1 $t-diamond-base (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import (interface "a:b/diamond2") (instance $diamond2 (;5;) (type 8))) + (alias export $diamond1 "t" (type $t-diamond1 (;9;))) + (alias export $diamond2 "t" (type $t-diamond2 (;10;))) + (type (;11;) + (instance + (alias outer 1 $t-diamond1 (type (;0;))) + (export (;1;) "t1" (type (eq 0))) + (alias outer 1 $t-diamond2 (type (;2;))) + (export (;3;) "t2" (type (eq 2))) + ) + ) + (import (interface "a:b/diamond-join") (instance (;6;) (type 11))) + ) + (instance (;7;) (instantiate 1 + (with "a:b/type-def" (instance 0)) + (with "a:b/type-use" (instance 1)) + (with "a:b/type-use-in-same-interface" (instance 2)) + (with "a:b/diamond-base" (instance 3)) + (with "a:b/diamond1" (instance 4)) + (with "a:b/diamond2" (instance 5)) + (with "a:b/diamond-join" (instance 6)) + ) + ) + (instance (;8;) (instantiate 0 + (with "a" (instance 7)) + ) + ) +) diff --git a/crates/wasm-compose/tests/compositions/type-use/root.wat b/crates/wasm-compose/tests/compositions/type-use/root.wat new file mode 100644 index 0000000000..6c6d721b97 --- /dev/null +++ b/crates/wasm-compose/tests/compositions/type-use/root.wat @@ -0,0 +1,3 @@ +(component + (import "a" (instance)) +) diff --git a/crates/wasm-encoder/Cargo.toml b/crates/wasm-encoder/Cargo.toml index 1a8b837cf6..0e29837614 100644 --- a/crates/wasm-encoder/Cargo.toml +++ b/crates/wasm-encoder/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "wasm-encoder" -version = "0.16.0" +version = "0.35.0" authors = ["Nick Fitzgerald "] -edition = "2021" +edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" readme = "README.md" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder" @@ -13,9 +13,13 @@ A low-level WebAssembly encoder. """ [dependencies] -leb128 = "0.2.4" +leb128 = { workspace = true } + +# Enable this dependency to get a bunch of `From for +# wasm_encoder::Foo` impls. +wasmparser = { optional = true, workspace = true } [dev-dependencies] -anyhow = "1.0.38" +anyhow = { workspace = true } tempfile = "3.2.0" wasmparser = { path = "../wasmparser" } diff --git a/crates/wasm-encoder/README.md b/crates/wasm-encoder/README.md index bc15ae2b21..5f2efbe210 100644 --- a/crates/wasm-encoder/README.md +++ b/crates/wasm-encoder/README.md @@ -16,11 +16,10 @@ ## Usage -Add this to your `Cargo.toml`: +Add `wasm-encoder` to your `Cargo.toml` -```toml -[dependencies] -wasm-encoder = "0.16.0" +```sh +$ cargo add wasm-encoder ``` And then you can encode WebAssembly binaries via: diff --git a/crates/wasm-encoder/src/component.rs b/crates/wasm-encoder/src/component.rs index f3d53003ee..e3f36a88a2 100644 --- a/crates/wasm-encoder/src/component.rs +++ b/crates/wasm-encoder/src/component.rs @@ -1,24 +1,28 @@ mod aliases; +mod builder; mod canonicals; mod components; mod exports; mod imports; mod instances; mod modules; +mod names; mod start; mod types; pub use self::aliases::*; +pub use self::builder::*; pub use self::canonicals::*; pub use self::components::*; pub use self::exports::*; pub use self::imports::*; pub use self::instances::*; pub use self::modules::*; +pub use self::names::*; pub use self::start::*; pub use self::types::*; -use crate::{CustomSection, Encode}; +use crate::{CustomSection, Encode, ProducersSection, RawCustomSection}; // Core sorts extended by the component model const CORE_TYPE_SORT: u8 = 0x10; @@ -40,6 +44,12 @@ const INSTANCE_SORT: u8 = 0x05; pub trait ComponentSection: Encode { /// Gets the section identifier for this section. fn id(&self) -> u8; + + /// Appends this section to the specified destination list of bytes. + fn append_to_component(&self, dst: &mut Vec) { + dst.push(self.id()); + self.encode(dst); + } } /// Known section identifiers of WebAssembly components. @@ -99,13 +109,19 @@ pub struct Component { } impl Component { + /// The 8-byte header at the beginning of all components. + #[rustfmt::skip] + pub const HEADER: [u8; 8] = [ + // Magic + 0x00, 0x61, 0x73, 0x6D, + // Version + 0x0d, 0x00, 0x01, 0x00, + ]; + /// Begin writing a new `Component`. pub fn new() -> Self { Self { - bytes: vec![ - 0x00, 0x61, 0x73, 0x6D, // magic (`\0asm`) - 0x0a, 0x00, 0x01, 0x00, // version - ], + bytes: Self::HEADER.to_vec(), } } @@ -120,6 +136,11 @@ impl Component { section.encode(&mut self.bytes); self } + + /// View the encoded bytes. + pub fn as_slice(&self) -> &[u8] { + &self.bytes + } } impl Default for Component { @@ -133,3 +154,15 @@ impl ComponentSection for CustomSection<'_> { ComponentSectionId::CoreCustom.into() } } + +impl ComponentSection for RawCustomSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::CoreCustom.into() + } +} + +impl ComponentSection for ProducersSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreCustom.into() + } +} diff --git a/crates/wasm-encoder/src/component/aliases.rs b/crates/wasm-encoder/src/component/aliases.rs index a78d52643a..1e317fb0e2 100644 --- a/crates/wasm-encoder/src/component/aliases.rs +++ b/crates/wasm-encoder/src/component/aliases.rs @@ -38,11 +38,11 @@ impl Encode for ComponentOuterAliasKind { /// # Example /// /// ```rust -/// use wasm_encoder::{Component, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind}; +/// use wasm_encoder::{Component, Alias, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind}; /// /// let mut aliases = ComponentAliasSection::new(); -/// aliases.instance_export(0, ComponentExportKind::Func, "f"); -/// aliases.outer(0, ComponentOuterAliasKind::Type, 1); +/// aliases.alias(Alias::InstanceExport { instance: 0, kind: ComponentExportKind::Func, name: "f" }); +/// aliases.alias(Alias::Outer { count: 0, kind: ComponentOuterAliasKind::Type, index: 1 }); /// /// let mut component = Component::new(); /// component.section(&aliases); @@ -55,6 +55,40 @@ pub struct ComponentAliasSection { num_added: u32, } +/// Different forms of aliases that can be inserted into a +/// [`ComponentAliasSection`]. +#[derive(Copy, Clone, Debug)] +pub enum Alias<'a> { + /// An alias of a component instance export. + InstanceExport { + /// The index of the component instance that's being aliased from. + instance: u32, + /// The kind of item that's being extracted from the component + /// instance. + kind: ComponentExportKind, + /// The name of the export that's being aliased. + name: &'a str, + }, + /// Same as `InstanceExport`, but for core instances. + #[allow(missing_docs)] + CoreInstanceExport { + instance: u32, + kind: ExportKind, + name: &'a str, + }, + /// Aliasing an item from an outer component. + Outer { + /// The kind of item being aliased, either a type or a component. + kind: ComponentOuterAliasKind, + /// Number of levels "up" to go to lookup the index within. Level 0 is + /// the current scope and level 1 is the enclosing scope, and so on. + count: u32, + /// The index of the item to alias within the scope referenced by + /// `count`. + index: u32, + }, +} + impl ComponentAliasSection { /// Create a new alias section encoder. pub fn new() -> Self { @@ -72,45 +106,8 @@ impl ComponentAliasSection { } /// Define an alias to a component instance's export. - pub fn instance_export( - &mut self, - instance_index: u32, - kind: ComponentExportKind, - name: &str, - ) -> &mut Self { - kind.encode(&mut self.bytes); - self.bytes.push(0x00); - instance_index.encode(&mut self.bytes); - name.encode(&mut self.bytes); - self.num_added += 1; - self - } - - /// Define an alias to a core instance's export. - pub fn core_instance_export( - &mut self, - instance_index: u32, - kind: ExportKind, - name: &str, - ) -> &mut Self { - self.bytes.push(CORE_SORT); - kind.encode(&mut self.bytes); - self.bytes.push(0x01); - instance_index.encode(&mut self.bytes); - name.encode(&mut self.bytes); - self.num_added += 1; - self - } - - /// Define an alias to an outer component item. - /// - /// The count starts at 0 to indicate the current component, 1 indicates the direct - /// parent, 2 the grandparent, etc. - pub fn outer(&mut self, count: u32, kind: ComponentOuterAliasKind, index: u32) -> &mut Self { - kind.encode(&mut self.bytes); - self.bytes.push(0x02); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); + pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self { + alias.encode(&mut self.bytes); self.num_added += 1; self } @@ -127,3 +124,37 @@ impl ComponentSection for ComponentAliasSection { ComponentSectionId::Alias.into() } } + +impl Encode for Alias<'_> { + fn encode(&self, sink: &mut Vec) { + match self { + Alias::InstanceExport { + instance, + kind, + name, + } => { + kind.encode(sink); + sink.push(0x00); + instance.encode(sink); + name.encode(sink); + } + Alias::CoreInstanceExport { + instance, + kind, + name, + } => { + sink.push(CORE_SORT); + kind.encode(sink); + sink.push(0x01); + instance.encode(sink); + name.encode(sink); + } + Alias::Outer { kind, count, index } => { + kind.encode(sink); + sink.push(0x02); + count.encode(sink); + index.encode(sink); + } + } + } +} diff --git a/crates/wasm-encoder/src/component/builder.rs b/crates/wasm-encoder/src/component/builder.rs new file mode 100644 index 0000000000..579106ad23 --- /dev/null +++ b/crates/wasm-encoder/src/component/builder.rs @@ -0,0 +1,449 @@ +use crate::component::*; +use crate::{ExportKind, Module, RawSection, ValType}; +use std::mem; + +/// Convenience type to build a component incrementally and automatically keep +/// track of index spaces. +/// +/// This type is intended to be a wrapper around the [`Component`] encoding type +/// which is useful for building it up incrementally over time. This type will +/// automatically collect definitions into sections and reports the index of all +/// items added by keeping track of indices internally. +#[derive(Debug, Default)] +pub struct ComponentBuilder { + /// The binary component that's being built. + component: Component, + + /// The last section which was appended to during encoding. This type is + /// generated by the `section_accessors` macro below. + /// + /// When something is encoded this is used if it matches the kind of item + /// being encoded, otherwise it's "flushed" to the output component and a + /// new section is started. + last_section: LastSection, + + // Core index spaces + core_modules: u32, + core_funcs: u32, + core_types: u32, + core_memories: u32, + core_tables: u32, + core_instances: u32, + core_tags: u32, + core_globals: u32, + + // Component index spaces + funcs: u32, + instances: u32, + types: u32, + components: u32, + values: u32, +} + +impl ComponentBuilder { + /// Returns the current number of core modules. + pub fn core_module_count(&self) -> u32 { + self.core_modules + } + + /// Returns the current number of core funcs. + pub fn core_func_count(&self) -> u32 { + self.core_funcs + } + + /// Returns the current number of core types. + pub fn core_type_count(&self) -> u32 { + self.core_types + } + + /// Returns the current number of core memories. + pub fn core_memory_count(&self) -> u32 { + self.core_memories + } + + /// Returns the current number of core tables. + pub fn core_table_count(&self) -> u32 { + self.core_tables + } + + /// Returns the current number of core instances. + pub fn core_instance_count(&self) -> u32 { + self.core_instances + } + + /// Returns the current number of core tags. + pub fn core_tag_count(&self) -> u32 { + self.core_tags + } + + /// Returns the current number of core globals. + pub fn core_global_count(&self) -> u32 { + self.core_globals + } + + /// Returns the current number of component funcs. + pub fn func_count(&self) -> u32 { + self.funcs + } + + /// Returns the current number of component instances. + pub fn instance_count(&self) -> u32 { + self.instances + } + + /// Returns the current number of component values. + pub fn value_count(&self) -> u32 { + self.values + } + + /// Returns the current number of components. + pub fn component_count(&self) -> u32 { + self.components + } + + /// Returns the current number of component types. + pub fn type_count(&self) -> u32 { + self.types + } + + /// Completes this component and returns the binary encoding of the entire + /// component. + pub fn finish(mut self) -> Vec { + self.flush(); + self.component.finish() + } + + /// Encodes a core wasm `Module` into this component, returning its index. + pub fn core_module(&mut self, module: &Module) -> u32 { + self.flush(); + self.component.section(&ModuleSection(module)); + inc(&mut self.core_modules) + } + + /// Encodes a core wasm `module` into this component, returning its index. + pub fn core_module_raw(&mut self, module: &[u8]) -> u32 { + self.flush(); + self.component.section(&RawSection { + id: ComponentSectionId::CoreModule.into(), + data: module, + }); + inc(&mut self.core_modules) + } + + /// Instantiates a core wasm module at `module_index` with the `args` + /// provided. + /// + /// Returns the index of the core wasm instance crated. + pub fn core_instantiate<'a, A>(&mut self, module_index: u32, args: A) -> u32 + where + A: IntoIterator, + A::IntoIter: ExactSizeIterator, + { + self.instances().instantiate(module_index, args); + inc(&mut self.core_instances) + } + + /// Creates a new core wasm instance from the `exports` provided. + /// + /// Returns the index of the core wasm instance crated. + pub fn core_instantiate_exports<'a, E>(&mut self, exports: E) -> u32 + where + E: IntoIterator, + E::IntoIter: ExactSizeIterator, + { + self.instances().export_items(exports); + inc(&mut self.core_instances) + } + + /// Creates a new aliased item where the core `instance` specified has its + /// export `name` aliased out with the `kind` specified. + /// + /// Returns the index of the item crated. + pub fn core_alias_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 { + self.alias(Alias::CoreInstanceExport { + instance, + kind, + name, + }) + } + + /// Adds a new alias to this component + pub fn alias(&mut self, alias: Alias<'_>) -> u32 { + self.aliases().alias(alias); + match alias { + Alias::InstanceExport { kind, .. } => self.inc_kind(kind), + Alias::CoreInstanceExport { kind, .. } => self.inc_core_kind(kind), + Alias::Outer { + kind: ComponentOuterAliasKind::Type, + .. + } => inc(&mut self.types), + Alias::Outer { + kind: ComponentOuterAliasKind::CoreModule, + .. + } => inc(&mut self.core_modules), + Alias::Outer { + kind: ComponentOuterAliasKind::Component, + .. + } => inc(&mut self.components), + Alias::Outer { + kind: ComponentOuterAliasKind::CoreType, + .. + } => inc(&mut self.core_types), + } + } + + /// Creates an alias to a previous component instance's exported item. + /// + /// The `instance` provided is the instance to access and the `name` is the + /// item to access. + /// + /// Returns the index of the new item defined. + pub fn alias_export(&mut self, instance: u32, name: &str, kind: ComponentExportKind) -> u32 { + self.alias(Alias::InstanceExport { + instance, + kind, + name, + }) + } + + fn inc_kind(&mut self, kind: ComponentExportKind) -> u32 { + match kind { + ComponentExportKind::Func => inc(&mut self.funcs), + ComponentExportKind::Module => inc(&mut self.core_modules), + ComponentExportKind::Type => inc(&mut self.types), + ComponentExportKind::Component => inc(&mut self.components), + ComponentExportKind::Instance => inc(&mut self.instances), + ComponentExportKind::Value => inc(&mut self.values), + } + } + + fn inc_core_kind(&mut self, kind: ExportKind) -> u32 { + match kind { + ExportKind::Func => inc(&mut self.core_funcs), + ExportKind::Table => inc(&mut self.core_tables), + ExportKind::Memory => inc(&mut self.core_memories), + ExportKind::Global => inc(&mut self.core_globals), + ExportKind::Tag => inc(&mut self.core_tags), + } + } + + /// Lowers the `func_index` component function into a core wasm function + /// using the `options` provided. + /// + /// Returns the index of the core wasm function created. + pub fn lower_func(&mut self, func_index: u32, options: O) -> u32 + where + O: IntoIterator, + O::IntoIter: ExactSizeIterator, + { + self.canonical_functions().lower(func_index, options); + inc(&mut self.core_funcs) + } + + /// Lifts the core wasm `core_func_index` function with the component + /// function type `type_index` and `options`. + /// + /// Returns the index of the component function created. + pub fn lift_func(&mut self, core_func_index: u32, type_index: u32, options: O) -> u32 + where + O: IntoIterator, + O::IntoIter: ExactSizeIterator, + { + self.canonical_functions() + .lift(core_func_index, type_index, options); + inc(&mut self.funcs) + } + + /// Imports a new item into this component with the `name` and `ty` specified. + pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> u32 { + let ret = match &ty { + ComponentTypeRef::Instance(_) => inc(&mut self.instances), + ComponentTypeRef::Func(_) => inc(&mut self.funcs), + ComponentTypeRef::Type(..) => inc(&mut self.types), + ComponentTypeRef::Component(_) => inc(&mut self.components), + ComponentTypeRef::Module(_) => inc(&mut self.core_modules), + ComponentTypeRef::Value(_) => inc(&mut self.values), + }; + self.imports().import(name, ty); + ret + } + + /// Exports a new item from this component with the `name` and `kind` + /// specified. + /// + /// The `idx` is the item to export and the `ty` is an optional type to + /// ascribe to the export. + pub fn export( + &mut self, + name: &str, + kind: ComponentExportKind, + idx: u32, + ty: Option, + ) -> u32 { + self.exports().export(name, kind, idx, ty); + self.inc_kind(kind) + } + + /// Creates a new encoder for the next core type in this component. + pub fn core_type(&mut self) -> (u32, CoreTypeEncoder<'_>) { + (inc(&mut self.core_types), self.core_types().ty()) + } + + /// Creates a new encoder for the next type in this component. + pub fn ty(&mut self) -> (u32, ComponentTypeEncoder<'_>) { + (inc(&mut self.types), self.types().ty()) + } + + /// Creates a new instance type within this component. + pub fn type_instance(&mut self, ty: &InstanceType) -> u32 { + self.types().instance(ty); + inc(&mut self.types) + } + + /// Creates a new component type within this component. + pub fn type_component(&mut self, ty: &ComponentType) -> u32 { + self.types().component(ty); + inc(&mut self.types) + } + + /// Creates a new defined component type within this component. + pub fn type_defined(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { + (inc(&mut self.types), self.types().defined_type()) + } + + /// Creates a new component function type within this component. + pub fn type_function(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { + (inc(&mut self.types), self.types().function()) + } + + /// Declares a + pub fn type_resource(&mut self, rep: ValType, dtor: Option) -> u32 { + self.types().resource(rep, dtor); + inc(&mut self.types) + } + + /// Defines a new subcomponent of this component. + pub fn component(&mut self, mut builder: ComponentBuilder) -> u32 { + builder.flush(); + self.flush(); + self.component + .section(&NestedComponentSection(&builder.component)); + inc(&mut self.components) + } + + /// Defines a new subcomponent of this component. + pub fn component_raw(&mut self, data: &[u8]) -> u32 { + let raw_section = RawSection { + id: ComponentSectionId::Component.into(), + data, + }; + self.flush(); + self.component.section(&raw_section); + inc(&mut self.components) + } + + /// Instantiates the `component_index` specified with the `args` specified. + pub fn instantiate(&mut self, component_index: u32, args: A) -> u32 + where + A: IntoIterator, + A::IntoIter: ExactSizeIterator, + S: AsRef, + { + self.component_instances() + .instantiate(component_index, args); + inc(&mut self.instances) + } + + /// Declares a new `resource.drop` intrinsic. + pub fn resource_drop(&mut self, ty: u32) -> u32 { + self.canonical_functions().resource_drop(ty); + inc(&mut self.core_funcs) + } + + /// Declares a new `resource.new` intrinsic. + pub fn resource_new(&mut self, ty: u32) -> u32 { + self.canonical_functions().resource_new(ty); + inc(&mut self.core_funcs) + } + + /// Declares a new `resource.rep` intrinsic. + pub fn resource_rep(&mut self, ty: u32) -> u32 { + self.canonical_functions().resource_rep(ty); + inc(&mut self.core_funcs) + } + + /// Adds a new custom section to this component. + pub fn raw_custom_section(&mut self, section: &[u8]) { + self.flush(); + self.component.section(&RawCustomSection(section)); + } +} + +// Helper macro to generate methods on `ComponentBuilder` to get specific +// section encoders that automatically flush and write out prior sections as +// necessary. +macro_rules! section_accessors { + ($($method:ident => $section:ident)*) => ( + #[derive(Debug, Default)] + enum LastSection { + #[default] + None, + $($section($section),)* + } + + impl ComponentBuilder { + $( + fn $method(&mut self) -> &mut $section { + match &self.last_section { + // The last encoded section matches the section that's + // being requested, so no change is necessary. + LastSection::$section(_) => {} + + // Otherwise the last section didn't match this section, + // so flush any prior section if needed and start + // encoding the desired section of this method. + _ => { + self.flush(); + self.last_section = LastSection::$section($section::new()); + } + } + match &mut self.last_section { + LastSection::$section(ret) => ret, + _ => unreachable!() + } + } + )* + + /// Writes out the last section into the final component binary if + /// there is a section specified, otherwise does nothing. + fn flush(&mut self) { + match mem::take(&mut self.last_section) { + LastSection::None => {} + $( + LastSection::$section(section) => { + self.component.section(§ion); + } + )* + } + } + + } + ) +} + +section_accessors! { + component_instances => ComponentInstanceSection + instances => InstanceSection + canonical_functions => CanonicalFunctionSection + aliases => ComponentAliasSection + exports => ComponentExportSection + imports => ComponentImportSection + types => ComponentTypeSection + core_types => CoreTypeSection +} + +fn inc(idx: &mut u32) -> u32 { + let ret = *idx; + *idx += 1; + ret +} diff --git a/crates/wasm-encoder/src/component/canonicals.rs b/crates/wasm-encoder/src/component/canonicals.rs index e81819c44e..340d9ca621 100644 --- a/crates/wasm-encoder/src/component/canonicals.rs +++ b/crates/wasm-encoder/src/component/canonicals.rs @@ -118,6 +118,32 @@ impl CanonicalFunctionSection { self.num_added += 1; self } + + /// Defines a function which will create an owned handle to the resource + /// specified by `ty_index`. + pub fn resource_new(&mut self, ty_index: u32) -> &mut Self { + self.bytes.push(0x02); + ty_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Defines a function which will drop the specified type of handle. + pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self { + self.bytes.push(0x03); + ty_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Defines a function which will return the representation of the specified + /// resource type. + pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self { + self.bytes.push(0x04); + ty_index.encode(&mut self.bytes); + self.num_added += 1; + self + } } impl Encode for CanonicalFunctionSection { diff --git a/crates/wasm-encoder/src/component/exports.rs b/crates/wasm-encoder/src/component/exports.rs index eefd3ca0ec..09f9e2514a 100644 --- a/crates/wasm-encoder/src/component/exports.rs +++ b/crates/wasm-encoder/src/component/exports.rs @@ -2,7 +2,10 @@ use super::{ COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT, }; -use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; +use crate::{ + encode_section, AsComponentExternName, ComponentSection, ComponentSectionId, ComponentTypeRef, + Encode, +}; /// Represents the kind of an export from a WebAssembly component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -52,11 +55,12 @@ impl Encode for ComponentExportKind { /// # Example /// /// ```rust -/// use wasm_encoder::{Component, ComponentExportSection, ComponentExportKind}; +/// use wasm_encoder::{Component, ComponentExportSection, ComponentExportKind, ComponentExternName}; /// /// // This exports a function named "foo" /// let mut exports = ComponentExportSection::new(); -/// exports.export("foo", ComponentExportKind::Func, 0); +/// let name = ComponentExternName::Kebab("foo"); +/// exports.export(name, ComponentExportKind::Func, 0, None); /// /// let mut component = Component::new(); /// component.section(&exports); @@ -86,10 +90,25 @@ impl ComponentExportSection { } /// Define an export in the export section. - pub fn export(&mut self, name: &str, kind: ComponentExportKind, index: u32) -> &mut Self { - name.encode(&mut self.bytes); + pub fn export( + &mut self, + name: impl AsComponentExternName, + kind: ComponentExportKind, + index: u32, + ty: Option, + ) -> &mut Self { + name.as_component_extern_name().encode(&mut self.bytes); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); + match ty { + Some(ty) => { + self.bytes.push(0x01); + ty.encode(&mut self.bytes); + } + None => { + self.bytes.push(0x00); + } + } self.num_added += 1; self } diff --git a/crates/wasm-encoder/src/component/imports.rs b/crates/wasm-encoder/src/component/imports.rs index 641163f3f5..fe611a015d 100644 --- a/crates/wasm-encoder/src/component/imports.rs +++ b/crates/wasm-encoder/src/component/imports.rs @@ -6,14 +6,20 @@ use crate::{ /// Represents the possible type bounds for type references. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum TypeBounds { - /// The type is bounded by equality. - Eq, + /// The type is bounded by equality to the type index specified. + Eq(u32), + /// This type is a fresh resource type, + SubResource, } impl Encode for TypeBounds { fn encode(&self, sink: &mut Vec) { match self { - Self::Eq => sink.push(0x00), + Self::Eq(i) => { + sink.push(0x00); + i.encode(sink); + } + Self::SubResource => sink.push(0x01), } } } @@ -32,9 +38,7 @@ pub enum ComponentTypeRef { /// The reference is to a value type. Value(ComponentValType), /// The reference is to a bounded type. - /// - /// The index is expected to be a type index. - Type(TypeBounds, u32), + Type(TypeBounds), /// The reference is to an instance type. /// /// The index is expected to be a type index to an instance type. @@ -68,10 +72,7 @@ impl Encode for ComponentTypeRef { idx.encode(sink); } Self::Value(ty) => ty.encode(sink), - Self::Type(bounds, idx) => { - bounds.encode(sink); - idx.encode(sink); - } + Self::Type(bounds) => bounds.encode(sink), } } } @@ -81,7 +82,7 @@ impl Encode for ComponentTypeRef { /// # Example /// /// ```rust -/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef}; +/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef, ComponentExternName}; /// /// let mut types = ComponentTypeSection::new(); /// @@ -98,7 +99,8 @@ impl Encode for ComponentTypeRef { /// /// // This imports a function named `f` with the type defined above /// let mut imports = ComponentImportSection::new(); -/// imports.import("f", ComponentTypeRef::Func(0)); +/// let name = ComponentExternName::Kebab("f"); +/// imports.import(name, ComponentTypeRef::Func(0)); /// /// let mut component = Component::new(); /// component.section(&types); @@ -129,8 +131,8 @@ impl ComponentImportSection { } /// Define an import in the component import section. - pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { - name.encode(&mut self.bytes); + pub fn import(&mut self, name: impl AsComponentExternName, ty: ComponentTypeRef) -> &mut Self { + name.as_component_extern_name().encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; self @@ -148,3 +150,51 @@ impl ComponentSection for ComponentImportSection { ComponentSectionId::Import.into() } } + +/// The different names that can be assigned to component imports +#[derive(Debug, Copy, Clone)] +pub enum ComponentExternName<'a> { + /// This is a "kebab name" along the lines of "a-foo-bar" + Kebab(&'a str), + /// This is an ID along the lines of "wasi:http/types@2.0" + Interface(&'a str), +} + +impl Encode for ComponentExternName<'_> { + fn encode(&self, sink: &mut Vec) { + match self { + ComponentExternName::Kebab(name) => { + sink.push(0x00); + name.encode(sink); + } + ComponentExternName::Interface(name) => { + sink.push(0x01); + name.encode(sink); + } + } + } +} + +/// Helper trait to convert into a `ComponentExternName` either from that type +/// or from a string. +pub trait AsComponentExternName { + /// Converts this receiver into a `ComponentExternName`. + fn as_component_extern_name(&self) -> ComponentExternName<'_>; +} + +impl AsComponentExternName for ComponentExternName<'_> { + fn as_component_extern_name(&self) -> ComponentExternName<'_> { + *self + } +} + +impl> AsComponentExternName for S { + fn as_component_extern_name(&self) -> ComponentExternName<'_> { + let s = self.as_ref(); + if s.contains("/") { + ComponentExternName::Interface(s) + } else { + ComponentExternName::Kebab(s) + } + } +} diff --git a/crates/wasm-encoder/src/component/instances.rs b/crates/wasm-encoder/src/component/instances.rs index 000a872d6b..d2a8e4e777 100644 --- a/crates/wasm-encoder/src/component/instances.rs +++ b/crates/wasm-encoder/src/component/instances.rs @@ -1,6 +1,7 @@ use super::CORE_INSTANCE_SORT; use crate::{ - encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, + encode_section, ComponentExportKind, ComponentExternName, ComponentSection, ComponentSectionId, + Encode, ExportKind, }; /// Represents an argument to a module instantiation. @@ -59,17 +60,18 @@ impl InstanceSection { } /// Define an instance by instantiating a core module. - pub fn instantiate<'a, A>(&mut self, module_index: u32, args: A) -> &mut Self + pub fn instantiate(&mut self, module_index: u32, args: A) -> &mut Self where - A: IntoIterator, + A: IntoIterator, A::IntoIter: ExactSizeIterator, + S: AsRef, { let args = args.into_iter(); self.bytes.push(0x00); module_index.encode(&mut self.bytes); args.len().encode(&mut self.bytes); for (name, arg) in args { - name.encode(&mut self.bytes); + name.as_ref().encode(&mut self.bytes); arg.encode(&mut self.bytes); } self.num_added += 1; @@ -77,16 +79,17 @@ impl InstanceSection { } /// Define an instance by exporting core WebAssembly items. - pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self + pub fn export_items(&mut self, exports: E) -> &mut Self where - E: IntoIterator, + E: IntoIterator, E::IntoIter: ExactSizeIterator, + S: AsRef, { let exports = exports.into_iter(); self.bytes.push(0x01); exports.len().encode(&mut self.bytes); for (name, kind, index) in exports { - name.encode(&mut self.bytes); + name.as_ref().encode(&mut self.bytes); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); } @@ -112,10 +115,10 @@ impl ComponentSection for InstanceSection { /// # Example /// /// ```rust -/// use wasm_encoder::{Component, ComponentInstanceSection, ComponentExportKind}; +/// use wasm_encoder::{Component, ComponentInstanceSection, ComponentExportKind, ComponentExternName}; /// /// let mut instances = ComponentInstanceSection::new(); -/// instances.export_items([("foo", ComponentExportKind::Func, 0)]); +/// instances.export_items([(ComponentExternName::Kebab("foo"), ComponentExportKind::Func, 0)]); /// instances.instantiate(1, [("foo", ComponentExportKind::Instance, 0)]); /// /// let mut component = Component::new(); @@ -146,17 +149,18 @@ impl ComponentInstanceSection { } /// Define an instance by instantiating a component. - pub fn instantiate<'a, A>(&mut self, component_index: u32, args: A) -> &mut Self + pub fn instantiate(&mut self, component_index: u32, args: A) -> &mut Self where - A: IntoIterator, + A: IntoIterator, A::IntoIter: ExactSizeIterator, + S: AsRef, { let args = args.into_iter(); self.bytes.push(0x00); component_index.encode(&mut self.bytes); args.len().encode(&mut self.bytes); for (name, kind, index) in args { - name.encode(&mut self.bytes); + name.as_ref().encode(&mut self.bytes); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); } @@ -167,7 +171,7 @@ impl ComponentInstanceSection { /// Define an instance by exporting items. pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self where - E: IntoIterator, + E: IntoIterator, ComponentExportKind, u32)>, E::IntoIter: ExactSizeIterator, { let exports = exports.into_iter(); diff --git a/crates/wasm-encoder/src/component/names.rs b/crates/wasm-encoder/src/component/names.rs new file mode 100644 index 0000000000..99db10bda0 --- /dev/null +++ b/crates/wasm-encoder/src/component/names.rs @@ -0,0 +1,149 @@ +use std::borrow::Cow; + +use super::*; +use crate::{encoding_size, CustomSection, Encode, ExportKind, NameMap, SectionId}; + +/// Encoding for the `component-name` custom section which assigns +/// human-readable names to items within a component. +#[derive(Clone, Debug, Default)] +pub struct ComponentNameSection { + bytes: Vec, +} + +enum Subsection { + Component, + Decls, +} + +impl ComponentNameSection { + /// Creates a new blank `name` custom section. + pub fn new() -> Self { + Self::default() + } + + /// Appends a component name subsection to this section. + /// + /// This will indicate that the name of the entire component should be the + /// `name` specified. Note that this should be encoded first before other + /// subsections. + pub fn component(&mut self, name: &str) { + let len = encoding_size(u32::try_from(name.len()).unwrap()); + self.subsection_header(Subsection::Component, len + name.len()); + name.encode(&mut self.bytes); + } + + /// Appends a decls name subsection to name core functions within the + /// component. + pub fn core_funcs(&mut self, names: &NameMap) { + self.core_decls(ExportKind::Func as u8, names) + } + + /// Appends a decls name subsection to name core tables within the + /// component. + pub fn core_tables(&mut self, names: &NameMap) { + self.core_decls(ExportKind::Table as u8, names) + } + + /// Appends a decls name subsection to name core memories within the + /// component. + pub fn core_memories(&mut self, names: &NameMap) { + self.core_decls(ExportKind::Memory as u8, names) + } + + /// Appends a decls name subsection to name core globals within the + /// component. + pub fn core_globals(&mut self, names: &NameMap) { + self.core_decls(ExportKind::Global as u8, names) + } + + /// Appends a decls name subsection to name core types within the + /// component. + pub fn core_types(&mut self, names: &NameMap) { + self.core_decls(CORE_TYPE_SORT, names) + } + + /// Appends a decls name subsection to name core modules within the + /// component. + pub fn core_modules(&mut self, names: &NameMap) { + self.core_decls(CORE_MODULE_SORT, names) + } + + /// Appends a decls name subsection to name core instances within the + /// component. + pub fn core_instances(&mut self, names: &NameMap) { + self.core_decls(CORE_INSTANCE_SORT, names) + } + + /// Appends a decls name subsection to name component functions within the + /// component. + pub fn funcs(&mut self, names: &NameMap) { + self.component_decls(FUNCTION_SORT, names) + } + + /// Appends a decls name subsection to name component values within the + /// component. + pub fn values(&mut self, names: &NameMap) { + self.component_decls(VALUE_SORT, names) + } + + /// Appends a decls name subsection to name component type within the + /// component. + pub fn types(&mut self, names: &NameMap) { + self.component_decls(TYPE_SORT, names) + } + + /// Appends a decls name subsection to name components within the + /// component. + pub fn components(&mut self, names: &NameMap) { + self.component_decls(COMPONENT_SORT, names) + } + + /// Appends a decls name subsection to name component instances within the + /// component. + pub fn instances(&mut self, names: &NameMap) { + self.component_decls(INSTANCE_SORT, names) + } + + fn component_decls(&mut self, kind: u8, names: &NameMap) { + self.subsection_header(Subsection::Decls, 1 + names.size()); + self.bytes.push(kind); + names.encode(&mut self.bytes); + } + + fn core_decls(&mut self, kind: u8, names: &NameMap) { + self.subsection_header(Subsection::Decls, 2 + names.size()); + self.bytes.push(CORE_SORT); + self.bytes.push(kind); + names.encode(&mut self.bytes); + } + + fn subsection_header(&mut self, id: Subsection, len: usize) { + self.bytes.push(id as u8); + len.encode(&mut self.bytes); + } + + /// Returns whether this section is empty, or nothing has been encoded. + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + + /// View the encoded section as a CustomSection. + pub fn as_custom<'a>(&'a self) -> CustomSection<'a> { + CustomSection { + name: "component-name".into(), + data: Cow::Borrowed(&self.bytes), + } + } +} + +impl Encode for ComponentNameSection { + fn encode(&self, sink: &mut Vec) { + self.as_custom().encode(sink); + } +} + +impl ComponentSection for ComponentNameSection { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index d87c2ec63d..ff3aacc2b1 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -1,7 +1,7 @@ use super::CORE_TYPE_SORT; use crate::{ - encode_section, ComponentOuterAliasKind, ComponentSection, ComponentSectionId, - ComponentTypeRef, Encode, EntityType, ValType, + encode_section, Alias, AsComponentExternName, ComponentExportKind, ComponentOuterAliasKind, + ComponentSection, ComponentSectionId, ComponentTypeRef, Encode, EntityType, ValType, }; /// Represents the type of a core module. @@ -92,9 +92,9 @@ impl<'a> CoreTypeEncoder<'a> { self.0.push(0x60); params.len().encode(self.0); - self.0.extend(params.map(u8::from)); + params.for_each(|p| p.encode(self.0)); results.len().encode(self.0); - self.0.extend(results.map(u8::from)); + results.for_each(|p| p.encode(self.0)); } /// Define a module type. @@ -190,6 +190,7 @@ pub struct ComponentType { num_added: u32, core_types_added: u32, types_added: u32, + instances_added: u32, } impl ComponentType { @@ -220,45 +221,59 @@ impl ComponentType { ComponentTypeEncoder(&mut self.bytes) } - /// Defines an outer core type alias in this component type. - pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { + /// Defines an alias for an exported item of a prior instance or an + /// outer type. + pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self { self.bytes.push(0x02); - ComponentOuterAliasKind::CoreType.encode(&mut self.bytes); - self.bytes.push(0x02); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); + alias.encode(&mut self.bytes); self.num_added += 1; - self.core_types_added += 1; - self - } - - /// Defines an outer type alias in this component type. - pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { - self.bytes.push(0x02); - ComponentOuterAliasKind::Type.encode(&mut self.bytes); - self.bytes.push(0x02); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); - self.num_added += 1; - self.types_added += 1; + match &alias { + Alias::InstanceExport { + kind: ComponentExportKind::Type, + .. + } + | Alias::Outer { + kind: ComponentOuterAliasKind::Type, + .. + } => self.types_added += 1, + Alias::Outer { + kind: ComponentOuterAliasKind::CoreType, + .. + } => self.core_types_added += 1, + Alias::InstanceExport { + kind: ComponentExportKind::Instance, + .. + } => self.instances_added += 1, + _ => {} + } self } /// Defines an import in this component type. - pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + pub fn import(&mut self, name: impl AsComponentExternName, ty: ComponentTypeRef) -> &mut Self { self.bytes.push(0x03); - name.encode(&mut self.bytes); + name.as_component_extern_name().encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; + match ty { + ComponentTypeRef::Type(..) => self.types_added += 1, + ComponentTypeRef::Instance(..) => self.instances_added += 1, + _ => {} + } self } /// Defines an export in this component type. - pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + pub fn export(&mut self, name: impl AsComponentExternName, ty: ComponentTypeRef) -> &mut Self { self.bytes.push(0x04); - name.encode(&mut self.bytes); + name.as_component_extern_name().encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; + match ty { + ComponentTypeRef::Type(..) => self.types_added += 1, + ComponentTypeRef::Instance(..) => self.instances_added += 1, + _ => {} + } self } @@ -271,6 +286,12 @@ impl ComponentType { pub fn type_count(&self) -> u32 { self.types_added } + + /// Gets the number of instances that have been defined in this component + /// type through imports, exports, or aliases. + pub fn instance_count(&self) -> u32 { + self.instances_added + } } impl Encode for ComponentType { @@ -283,12 +304,7 @@ impl Encode for ComponentType { /// Represents an instance type. #[derive(Debug, Clone, Default)] -pub struct InstanceType { - bytes: Vec, - num_added: u32, - core_types_added: u32, - types_added: u32, -} +pub struct InstanceType(ComponentType); impl InstanceType { /// Creates a new instance type. @@ -301,10 +317,7 @@ impl InstanceType { /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] pub fn core_type(&mut self) -> CoreTypeEncoder { - self.bytes.push(0x00); - self.num_added += 1; - self.core_types_added += 1; - CoreTypeEncoder(&mut self.bytes) + self.0.core_type() } /// Define a type in this instance type. @@ -312,61 +325,53 @@ impl InstanceType { /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] pub fn ty(&mut self) -> ComponentTypeEncoder { - self.bytes.push(0x01); - self.num_added += 1; - self.types_added += 1; - ComponentTypeEncoder(&mut self.bytes) + self.0.ty() } /// Defines an outer core type alias in this component type. - pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { - self.bytes.push(0x02); - ComponentOuterAliasKind::CoreType.encode(&mut self.bytes); - self.bytes.push(0x02); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); - self.num_added += 1; - self.core_types_added += 1; - self - } - - /// Defines an alias in this instance type. - pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { - self.bytes.push(0x02); - ComponentOuterAliasKind::Type.encode(&mut self.bytes); - self.bytes.push(0x02); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); - self.num_added += 1; - self.types_added += 1; + pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self { + self.0.alias(alias); self } /// Defines an export in this instance type. - pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { - self.bytes.push(0x04); - name.encode(&mut self.bytes); - ty.encode(&mut self.bytes); - self.num_added += 1; + pub fn export(&mut self, name: impl AsComponentExternName, ty: ComponentTypeRef) -> &mut Self { + self.0.export(name, ty); self } /// Gets the number of core types that have been added to this instance type. pub fn core_type_count(&self) -> u32 { - self.core_types_added + self.0.core_types_added } /// Gets the number of types that have been added or aliased in this instance type. pub fn type_count(&self) -> u32 { - self.types_added + self.0.types_added + } + + /// Gets the number of instances that have been imported or exported or + /// aliased in this instance type. + pub fn instance_count(&self) -> u32 { + self.0.instances_added + } + + /// Returns whether or not this instance type is empty. + pub fn is_empty(&self) -> bool { + self.0.num_added == 0 + } + + /// Returns the number of entries added to this instance types. + pub fn len(&self) -> u32 { + self.0.num_added } } impl Encode for InstanceType { fn encode(&self, sink: &mut Vec) { sink.push(0x42); - self.num_added.encode(sink); - sink.extend(&self.bytes); + self.0.num_added.encode(sink); + sink.extend(&self.0.bytes); } } @@ -380,21 +385,8 @@ impl<'a> ComponentFuncTypeEncoder<'a> { Self(sink) } - /// Defines a single unnamed parameter. - /// - /// This method cannot be used with `params`. - /// - /// Parameters must be defined before defining results. - pub fn param(&mut self, ty: impl Into) -> &mut Self { - self.0.push(0x00); - ty.into().encode(self.0); - self - } - /// Defines named parameters. /// - /// This method cannot be used with `param`. - /// /// Parameters must be defined before defining results. pub fn params<'b, P, T>(&mut self, params: P) -> &mut Self where @@ -402,7 +394,6 @@ impl<'a> ComponentFuncTypeEncoder<'a> { P::IntoIter: ExactSizeIterator, T: Into, { - self.0.push(0x01); let params = params.into_iter(); params.len().encode(self.0); for (name, ty) in params { @@ -468,6 +459,19 @@ impl<'a> ComponentTypeEncoder<'a> { pub fn defined_type(self) -> ComponentDefinedTypeEncoder<'a> { ComponentDefinedTypeEncoder(self.0) } + + /// Define a resource type. + pub fn resource(self, rep: ValType, dtor: Option) { + self.0.push(0x3f); + rep.encode(self.0); + match dtor { + Some(i) => { + self.0.push(0x01); + i.encode(self.0); + } + None => self.0.push(0x00), + } + } } /// Represents a primitive component value type. @@ -638,21 +642,6 @@ impl ComponentDefinedTypeEncoder<'_> { } } - /// Define a union type. - pub fn union(self, types: I) - where - I: IntoIterator, - I::IntoIter: ExactSizeIterator, - T: Into, - { - let types = types.into_iter(); - self.0.push(0x6C); - types.len().encode(self.0); - for ty in types { - ty.into().encode(self.0); - } - } - /// Define an option type. pub fn option(self, ty: impl Into) { self.0.push(0x6B); @@ -665,6 +654,18 @@ impl ComponentDefinedTypeEncoder<'_> { ok.encode(self.0); err.encode(self.0); } + + /// Define a `own` handle type + pub fn own(self, idx: u32) { + self.0.push(0x69); + idx.encode(self.0); + } + + /// Define a `borrow` handle type + pub fn borrow(self, idx: u32) { + self.0.push(0x68); + idx.encode(self.0); + } } /// An encoder for the type section of WebAssembly components. @@ -747,6 +748,12 @@ impl ComponentTypeSection { pub fn defined_type(&mut self) -> ComponentDefinedTypeEncoder<'_> { self.ty().defined_type() } + + /// Defines a new resource type. + pub fn resource(&mut self, rep: ValType, dtor: Option) -> &mut Self { + self.ty().resource(rep, dtor); + self + } } impl Encode for ComponentTypeSection { diff --git a/crates/wasm-encoder/src/core.rs b/crates/wasm-encoder/src/core.rs index e03bd9363e..feccfdefc1 100644 --- a/crates/wasm-encoder/src/core.rs +++ b/crates/wasm-encoder/src/core.rs @@ -1,6 +1,7 @@ mod code; mod custom; mod data; +mod dump; mod elements; mod exports; mod functions; @@ -9,6 +10,7 @@ mod imports; mod linking; mod memories; mod names; +mod producers; mod start; mod tables; mod tags; @@ -17,6 +19,7 @@ mod types; pub use code::*; pub use custom::*; pub use data::*; +pub use dump::*; pub use elements::*; pub use exports::*; pub use functions::*; @@ -25,6 +28,7 @@ pub use imports::*; pub use linking::*; pub use memories::*; pub use names::*; +pub use producers::*; pub use start::*; pub use tables::*; pub use tags::*; @@ -46,6 +50,12 @@ pub(crate) const CORE_TAG_SORT: u8 = 0x04; pub trait Section: Encode { /// Gets the section identifier for this section. fn id(&self) -> u8; + + /// Appends this section to the specified destination list of bytes. + fn append_to(&self, dst: &mut Vec) { + dst.push(self.id()); + self.encode(dst); + } } /// Known section identifiers of WebAssembly modules. @@ -108,16 +118,20 @@ pub struct Module { } impl Module { + /// The 8-byte header at the beginning of all core wasm modules. + #[rustfmt::skip] + pub const HEADER: [u8; 8] = [ + // Magic + 0x00, 0x61, 0x73, 0x6D, + // Version + 0x01, 0x00, 0x00, 0x00, + ]; + /// Begin writing a new `Module`. #[rustfmt::skip] pub fn new() -> Self { Module { - bytes: vec![ - // Magic - 0x00, 0x61, 0x73, 0x6D, - // Version - 0x01, 0x00, 0x00, 0x00, - ], + bytes: Self::HEADER.to_vec(), } } diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs index ca37b7270c..3cb9ea4ccb 100644 --- a/crates/wasm-encoder/src/core/code.rs +++ b/crates/wasm-encoder/src/core/code.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, Encode, Section, SectionId, ValType}; +use crate::{encode_section, Encode, HeapType, Section, SectionId, ValType}; use std::borrow::Cow; /// An encoder for the code section. @@ -87,8 +87,8 @@ impl CodeSection { /// let code_section = [10, 6, 1, 4, 0, 65, 0, 11]; /// /// // Parse the code section. - /// let mut reader = wasmparser::CodeSectionReader::new(&code_section, 0).unwrap(); - /// let body = reader.read().unwrap(); + /// let reader = wasmparser::CodeSectionReader::new(&code_section, 0).unwrap(); + /// let body = reader.into_iter().next().unwrap().unwrap(); /// let body_range = body.range(); /// /// // Add the body to a new code section encoder by copying bytes rather @@ -318,9 +318,15 @@ pub enum Instruction<'a> { Br(u32), BrIf(u32), BrTable(Cow<'a, [u32]>, u32), + BrOnNull(u32), + BrOnNonNull(u32), Return, Call(u32), + CallRef(u32), CallIndirect { ty: u32, table: u32 }, + ReturnCallRef(u32), + ReturnCall(u32), + ReturnCallIndirect { ty: u32, table: u32 }, Throw(u32), Rethrow(u32), @@ -340,16 +346,16 @@ pub enum Instruction<'a> { I64Load(MemArg), F32Load(MemArg), F64Load(MemArg), - I32Load8_S(MemArg), - I32Load8_U(MemArg), - I32Load16_S(MemArg), - I32Load16_U(MemArg), - I64Load8_S(MemArg), - I64Load8_U(MemArg), - I64Load16_S(MemArg), - I64Load16_U(MemArg), - I64Load32_S(MemArg), - I64Load32_U(MemArg), + I32Load8S(MemArg), + I32Load8U(MemArg), + I32Load16S(MemArg), + I32Load16U(MemArg), + I64Load8S(MemArg), + I64Load8U(MemArg), + I64Load16S(MemArg), + I64Load16U(MemArg), + I64Load32S(MemArg), + I64Load32U(MemArg), I32Store(MemArg), I64Store(MemArg), F32Store(MemArg), @@ -361,10 +367,11 @@ pub enum Instruction<'a> { I64Store32(MemArg), MemorySize(u32), MemoryGrow(u32), - MemoryInit { mem: u32, data: u32 }, + MemoryInit { mem: u32, data_index: u32 }, DataDrop(u32), - MemoryCopy { src: u32, dst: u32 }, + MemoryCopy { src_mem: u32, dst_mem: u32 }, MemoryFill(u32), + MemoryDiscard(u32), // Numeric instructions. I32Const(i32), @@ -510,35 +517,41 @@ pub enum Instruction<'a> { // Reference types instructions. TypedSelect(ValType), - RefNull(ValType), + RefNull(HeapType), RefIsNull, RefFunc(u32), + RefAsNonNull, + + // GC types instructions. + RefI31, + I31GetS, + I31GetU, // Bulk memory instructions. - TableInit { segment: u32, table: u32 }, - ElemDrop { segment: u32 }, - TableFill { table: u32 }, - TableSet { table: u32 }, - TableGet { table: u32 }, - TableGrow { table: u32 }, - TableSize { table: u32 }, - TableCopy { src: u32, dst: u32 }, + TableInit { elem_index: u32, table: u32 }, + ElemDrop(u32), + TableFill(u32), + TableSet(u32), + TableGet(u32), + TableGrow(u32), + TableSize(u32), + TableCopy { src_table: u32, dst_table: u32 }, // SIMD instructions. - V128Load { memarg: MemArg }, - V128Load8x8S { memarg: MemArg }, - V128Load8x8U { memarg: MemArg }, - V128Load16x4S { memarg: MemArg }, - V128Load16x4U { memarg: MemArg }, - V128Load32x2S { memarg: MemArg }, - V128Load32x2U { memarg: MemArg }, - V128Load8Splat { memarg: MemArg }, - V128Load16Splat { memarg: MemArg }, - V128Load32Splat { memarg: MemArg }, - V128Load64Splat { memarg: MemArg }, - V128Load32Zero { memarg: MemArg }, - V128Load64Zero { memarg: MemArg }, - V128Store { memarg: MemArg }, + V128Load(MemArg), + V128Load8x8S(MemArg), + V128Load8x8U(MemArg), + V128Load16x4S(MemArg), + V128Load16x4U(MemArg), + V128Load32x2S(MemArg), + V128Load32x2U(MemArg), + V128Load8Splat(MemArg), + V128Load16Splat(MemArg), + V128Load32Splat(MemArg), + V128Load64Splat(MemArg), + V128Load32Zero(MemArg), + V128Load64Zero(MemArg), + V128Store(MemArg), V128Load8Lane { memarg: MemArg, lane: Lane }, V128Load16Lane { memarg: MemArg, lane: Lane }, V128Load32Lane { memarg: MemArg, lane: Lane }, @@ -548,21 +561,21 @@ pub enum Instruction<'a> { V128Store32Lane { memarg: MemArg, lane: Lane }, V128Store64Lane { memarg: MemArg, lane: Lane }, V128Const(i128), - I8x16Shuffle { lanes: [Lane; 16] }, - I8x16ExtractLaneS { lane: Lane }, - I8x16ExtractLaneU { lane: Lane }, - I8x16ReplaceLane { lane: Lane }, - I16x8ExtractLaneS { lane: Lane }, - I16x8ExtractLaneU { lane: Lane }, - I16x8ReplaceLane { lane: Lane }, - I32x4ExtractLane { lane: Lane }, - I32x4ReplaceLane { lane: Lane }, - I64x2ExtractLane { lane: Lane }, - I64x2ReplaceLane { lane: Lane }, - F32x4ExtractLane { lane: Lane }, - F32x4ReplaceLane { lane: Lane }, - F64x2ExtractLane { lane: Lane }, - F64x2ReplaceLane { lane: Lane }, + I8x16Shuffle([Lane; 16]), + I8x16ExtractLaneS(Lane), + I8x16ExtractLaneU(Lane), + I8x16ReplaceLane(Lane), + I16x8ExtractLaneS(Lane), + I16x8ExtractLaneU(Lane), + I16x8ReplaceLane(Lane), + I32x4ExtractLane(Lane), + I32x4ReplaceLane(Lane), + I64x2ExtractLane(Lane), + I64x2ReplaceLane(Lane), + F32x4ExtractLane(Lane), + F32x4ReplaceLane(Lane), + F64x2ExtractLane(Lane), + F64x2ReplaceLane(Lane), I8x16Swizzle, I8x16Splat, I16x8Splat, @@ -645,7 +658,7 @@ pub enum Instruction<'a> { I8x16MinU, I8x16MaxS, I8x16MaxU, - I8x16RoundingAverageU, + I8x16AvgrU, I16x8ExtAddPairwiseI8x16S, I16x8ExtAddPairwiseI8x16U, I16x8Abs, @@ -673,7 +686,7 @@ pub enum Instruction<'a> { I16x8MinU, I16x8MaxS, I16x8MaxU, - I16x8RoundingAverageU, + I16x8AvgrU, I16x8ExtMulLowI8x16S, I16x8ExtMulHighI8x16S, I16x8ExtMulLowI8x16U, @@ -761,92 +774,97 @@ pub enum Instruction<'a> { F64x2ConvertLowI32x4U, F32x4DemoteF64x2Zero, F64x2PromoteLowF32x4, + + // Relaxed simd proposal I8x16RelaxedSwizzle, - I32x4RelaxedTruncSatF32x4S, - I32x4RelaxedTruncSatF32x4U, - I32x4RelaxedTruncSatF64x2SZero, - I32x4RelaxedTruncSatF64x2UZero, - F32x4Fma, - F32x4Fms, - F64x2Fma, - F64x2Fms, - I8x16LaneSelect, - I16x8LaneSelect, - I32x4LaneSelect, - I64x2LaneSelect, + I32x4RelaxedTruncF32x4S, + I32x4RelaxedTruncF32x4U, + I32x4RelaxedTruncF64x2SZero, + I32x4RelaxedTruncF64x2UZero, + F32x4RelaxedMadd, + F32x4RelaxedNmadd, + F64x2RelaxedMadd, + F64x2RelaxedNmadd, + I8x16RelaxedLaneselect, + I16x8RelaxedLaneselect, + I32x4RelaxedLaneselect, + I64x2RelaxedLaneselect, F32x4RelaxedMin, F32x4RelaxedMax, F64x2RelaxedMin, F64x2RelaxedMax, + I16x8RelaxedQ15mulrS, + I16x8RelaxedDotI8x16I7x16S, + I32x4RelaxedDotI8x16I7x16AddS, // Atomic instructions (the threads proposal) - MemoryAtomicNotify { memarg: MemArg }, - MemoryAtomicWait32 { memarg: MemArg }, - MemoryAtomicWait64 { memarg: MemArg }, + MemoryAtomicNotify(MemArg), + MemoryAtomicWait32(MemArg), + MemoryAtomicWait64(MemArg), AtomicFence, - I32AtomicLoad { memarg: MemArg }, - I64AtomicLoad { memarg: MemArg }, - I32AtomicLoad8U { memarg: MemArg }, - I32AtomicLoad16U { memarg: MemArg }, - I64AtomicLoad8U { memarg: MemArg }, - I64AtomicLoad16U { memarg: MemArg }, - I64AtomicLoad32U { memarg: MemArg }, - I32AtomicStore { memarg: MemArg }, - I64AtomicStore { memarg: MemArg }, - I32AtomicStore8 { memarg: MemArg }, - I32AtomicStore16 { memarg: MemArg }, - I64AtomicStore8 { memarg: MemArg }, - I64AtomicStore16 { memarg: MemArg }, - I64AtomicStore32 { memarg: MemArg }, - I32AtomicRmwAdd { memarg: MemArg }, - I64AtomicRmwAdd { memarg: MemArg }, - I32AtomicRmw8AddU { memarg: MemArg }, - I32AtomicRmw16AddU { memarg: MemArg }, - I64AtomicRmw8AddU { memarg: MemArg }, - I64AtomicRmw16AddU { memarg: MemArg }, - I64AtomicRmw32AddU { memarg: MemArg }, - I32AtomicRmwSub { memarg: MemArg }, - I64AtomicRmwSub { memarg: MemArg }, - I32AtomicRmw8SubU { memarg: MemArg }, - I32AtomicRmw16SubU { memarg: MemArg }, - I64AtomicRmw8SubU { memarg: MemArg }, - I64AtomicRmw16SubU { memarg: MemArg }, - I64AtomicRmw32SubU { memarg: MemArg }, - I32AtomicRmwAnd { memarg: MemArg }, - I64AtomicRmwAnd { memarg: MemArg }, - I32AtomicRmw8AndU { memarg: MemArg }, - I32AtomicRmw16AndU { memarg: MemArg }, - I64AtomicRmw8AndU { memarg: MemArg }, - I64AtomicRmw16AndU { memarg: MemArg }, - I64AtomicRmw32AndU { memarg: MemArg }, - I32AtomicRmwOr { memarg: MemArg }, - I64AtomicRmwOr { memarg: MemArg }, - I32AtomicRmw8OrU { memarg: MemArg }, - I32AtomicRmw16OrU { memarg: MemArg }, - I64AtomicRmw8OrU { memarg: MemArg }, - I64AtomicRmw16OrU { memarg: MemArg }, - I64AtomicRmw32OrU { memarg: MemArg }, - I32AtomicRmwXor { memarg: MemArg }, - I64AtomicRmwXor { memarg: MemArg }, - I32AtomicRmw8XorU { memarg: MemArg }, - I32AtomicRmw16XorU { memarg: MemArg }, - I64AtomicRmw8XorU { memarg: MemArg }, - I64AtomicRmw16XorU { memarg: MemArg }, - I64AtomicRmw32XorU { memarg: MemArg }, - I32AtomicRmwXchg { memarg: MemArg }, - I64AtomicRmwXchg { memarg: MemArg }, - I32AtomicRmw8XchgU { memarg: MemArg }, - I32AtomicRmw16XchgU { memarg: MemArg }, - I64AtomicRmw8XchgU { memarg: MemArg }, - I64AtomicRmw16XchgU { memarg: MemArg }, - I64AtomicRmw32XchgU { memarg: MemArg }, - I32AtomicRmwCmpxchg { memarg: MemArg }, - I64AtomicRmwCmpxchg { memarg: MemArg }, - I32AtomicRmw8CmpxchgU { memarg: MemArg }, - I32AtomicRmw16CmpxchgU { memarg: MemArg }, - I64AtomicRmw8CmpxchgU { memarg: MemArg }, - I64AtomicRmw16CmpxchgU { memarg: MemArg }, - I64AtomicRmw32CmpxchgU { memarg: MemArg }, + I32AtomicLoad(MemArg), + I64AtomicLoad(MemArg), + I32AtomicLoad8U(MemArg), + I32AtomicLoad16U(MemArg), + I64AtomicLoad8U(MemArg), + I64AtomicLoad16U(MemArg), + I64AtomicLoad32U(MemArg), + I32AtomicStore(MemArg), + I64AtomicStore(MemArg), + I32AtomicStore8(MemArg), + I32AtomicStore16(MemArg), + I64AtomicStore8(MemArg), + I64AtomicStore16(MemArg), + I64AtomicStore32(MemArg), + I32AtomicRmwAdd(MemArg), + I64AtomicRmwAdd(MemArg), + I32AtomicRmw8AddU(MemArg), + I32AtomicRmw16AddU(MemArg), + I64AtomicRmw8AddU(MemArg), + I64AtomicRmw16AddU(MemArg), + I64AtomicRmw32AddU(MemArg), + I32AtomicRmwSub(MemArg), + I64AtomicRmwSub(MemArg), + I32AtomicRmw8SubU(MemArg), + I32AtomicRmw16SubU(MemArg), + I64AtomicRmw8SubU(MemArg), + I64AtomicRmw16SubU(MemArg), + I64AtomicRmw32SubU(MemArg), + I32AtomicRmwAnd(MemArg), + I64AtomicRmwAnd(MemArg), + I32AtomicRmw8AndU(MemArg), + I32AtomicRmw16AndU(MemArg), + I64AtomicRmw8AndU(MemArg), + I64AtomicRmw16AndU(MemArg), + I64AtomicRmw32AndU(MemArg), + I32AtomicRmwOr(MemArg), + I64AtomicRmwOr(MemArg), + I32AtomicRmw8OrU(MemArg), + I32AtomicRmw16OrU(MemArg), + I64AtomicRmw8OrU(MemArg), + I64AtomicRmw16OrU(MemArg), + I64AtomicRmw32OrU(MemArg), + I32AtomicRmwXor(MemArg), + I64AtomicRmwXor(MemArg), + I32AtomicRmw8XorU(MemArg), + I32AtomicRmw16XorU(MemArg), + I64AtomicRmw8XorU(MemArg), + I64AtomicRmw16XorU(MemArg), + I64AtomicRmw32XorU(MemArg), + I32AtomicRmwXchg(MemArg), + I64AtomicRmwXchg(MemArg), + I32AtomicRmw8XchgU(MemArg), + I32AtomicRmw16XchgU(MemArg), + I64AtomicRmw8XchgU(MemArg), + I64AtomicRmw16XchgU(MemArg), + I64AtomicRmw32XchgU(MemArg), + I32AtomicRmwCmpxchg(MemArg), + I64AtomicRmwCmpxchg(MemArg), + I32AtomicRmw8CmpxchgU(MemArg), + I32AtomicRmw16CmpxchgU(MemArg), + I64AtomicRmw8CmpxchgU(MemArg), + I64AtomicRmw16CmpxchgU(MemArg), + I64AtomicRmw32CmpxchgU(MemArg), } impl Encode for Instruction<'_> { @@ -898,16 +916,42 @@ impl Encode for Instruction<'_> { ls.encode(sink); l.encode(sink); } + Instruction::BrOnNull(l) => { + sink.push(0xD5); + l.encode(sink); + } + Instruction::BrOnNonNull(l) => { + sink.push(0xD6); + l.encode(sink); + } Instruction::Return => sink.push(0x0F), Instruction::Call(f) => { sink.push(0x10); f.encode(sink); } + Instruction::CallRef(ty) => { + sink.push(0x14); + ty.encode(sink); + } Instruction::CallIndirect { ty, table } => { sink.push(0x11); ty.encode(sink); table.encode(sink); } + Instruction::ReturnCallRef(ty) => { + sink.push(0x15); + ty.encode(sink); + } + + Instruction::ReturnCall(f) => { + sink.push(0x12); + f.encode(sink); + } + Instruction::ReturnCallIndirect { ty, table } => { + sink.push(0x13); + ty.encode(sink); + table.encode(sink); + } Instruction::Delegate(l) => { sink.push(0x18); l.encode(sink); @@ -945,11 +989,11 @@ impl Encode for Instruction<'_> { sink.push(0x24); g.encode(sink); } - Instruction::TableGet { table } => { + Instruction::TableGet(table) => { sink.push(0x25); table.encode(sink); } - Instruction::TableSet { table } => { + Instruction::TableSet(table) => { sink.push(0x26); table.encode(sink); } @@ -971,43 +1015,43 @@ impl Encode for Instruction<'_> { sink.push(0x2B); m.encode(sink); } - Instruction::I32Load8_S(m) => { + Instruction::I32Load8S(m) => { sink.push(0x2C); m.encode(sink); } - Instruction::I32Load8_U(m) => { + Instruction::I32Load8U(m) => { sink.push(0x2D); m.encode(sink); } - Instruction::I32Load16_S(m) => { + Instruction::I32Load16S(m) => { sink.push(0x2E); m.encode(sink); } - Instruction::I32Load16_U(m) => { + Instruction::I32Load16U(m) => { sink.push(0x2F); m.encode(sink); } - Instruction::I64Load8_S(m) => { + Instruction::I64Load8S(m) => { sink.push(0x30); m.encode(sink); } - Instruction::I64Load8_U(m) => { + Instruction::I64Load8U(m) => { sink.push(0x31); m.encode(sink); } - Instruction::I64Load16_S(m) => { + Instruction::I64Load16S(m) => { sink.push(0x32); m.encode(sink); } - Instruction::I64Load16_U(m) => { + Instruction::I64Load16U(m) => { sink.push(0x33); m.encode(sink); } - Instruction::I64Load32_S(m) => { + Instruction::I64Load32S(m) => { sink.push(0x34); m.encode(sink); } - Instruction::I64Load32_U(m) => { + Instruction::I64Load32U(m) => { sink.push(0x35); m.encode(sink); } @@ -1055,10 +1099,10 @@ impl Encode for Instruction<'_> { sink.push(0x40); i.encode(sink); } - Instruction::MemoryInit { mem, data } => { + Instruction::MemoryInit { mem, data_index } => { sink.push(0xfc); sink.push(0x08); - data.encode(sink); + data_index.encode(sink); mem.encode(sink); } Instruction::DataDrop(data) => { @@ -1066,17 +1110,22 @@ impl Encode for Instruction<'_> { sink.push(0x09); data.encode(sink); } - Instruction::MemoryCopy { src, dst } => { + Instruction::MemoryCopy { src_mem, dst_mem } => { sink.push(0xfc); sink.push(0x0a); - dst.encode(sink); - src.encode(sink); + dst_mem.encode(sink); + src_mem.encode(sink); } Instruction::MemoryFill(mem) => { sink.push(0xfc); sink.push(0x0b); mem.encode(sink); } + Instruction::MemoryDiscard(mem) => { + sink.push(0xfc); + sink.push(0x12); + mem.encode(sink); + } // Numeric instructions. Instruction::I32Const(x) => { @@ -1269,98 +1318,116 @@ impl Encode for Instruction<'_> { sink.push(0xd2); f.encode(sink); } + Instruction::RefAsNonNull => sink.push(0xd4), + + // GC instructions. + Instruction::RefI31 => { + sink.push(0xfb); + sink.push(0x1c) + } + Instruction::I31GetS => { + sink.push(0xfb); + sink.push(0x1d) + } + Instruction::I31GetU => { + sink.push(0xfb); + sink.push(0x1e) + } // Bulk memory instructions. - Instruction::TableInit { segment, table } => { + Instruction::TableInit { elem_index, table } => { sink.push(0xfc); sink.push(0x0c); - segment.encode(sink); + elem_index.encode(sink); table.encode(sink); } - Instruction::ElemDrop { segment } => { + Instruction::ElemDrop(segment) => { sink.push(0xfc); sink.push(0x0d); segment.encode(sink); } - Instruction::TableCopy { src, dst } => { + Instruction::TableCopy { + src_table, + dst_table, + } => { sink.push(0xfc); sink.push(0x0e); - dst.encode(sink); - src.encode(sink); + dst_table.encode(sink); + src_table.encode(sink); } - Instruction::TableGrow { table } => { + Instruction::TableGrow(table) => { sink.push(0xfc); sink.push(0x0f); table.encode(sink); } - Instruction::TableSize { table } => { + Instruction::TableSize(table) => { sink.push(0xfc); sink.push(0x10); table.encode(sink); } - Instruction::TableFill { table } => { + Instruction::TableFill(table) => { sink.push(0xfc); sink.push(0x11); table.encode(sink); } // SIMD instructions. - Instruction::V128Load { memarg } => { + Instruction::V128Load(memarg) => { sink.push(0xFD); 0x00u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load8x8S { memarg } => { + Instruction::V128Load8x8S(memarg) => { sink.push(0xFD); 0x01u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load8x8U { memarg } => { + Instruction::V128Load8x8U(memarg) => { sink.push(0xFD); 0x02u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load16x4S { memarg } => { + Instruction::V128Load16x4S(memarg) => { sink.push(0xFD); 0x03u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load16x4U { memarg } => { + Instruction::V128Load16x4U(memarg) => { sink.push(0xFD); 0x04u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load32x2S { memarg } => { + Instruction::V128Load32x2S(memarg) => { sink.push(0xFD); 0x05u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load32x2U { memarg } => { + Instruction::V128Load32x2U(memarg) => { sink.push(0xFD); 0x06u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load8Splat { memarg } => { + Instruction::V128Load8Splat(memarg) => { sink.push(0xFD); 0x07u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load16Splat { memarg } => { + Instruction::V128Load16Splat(memarg) => { sink.push(0xFD); 0x08u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load32Splat { memarg } => { + Instruction::V128Load32Splat(memarg) => { sink.push(0xFD); 0x09u32.encode(sink); memarg.encode(sink); } - Instruction::V128Load64Splat { memarg } => { + Instruction::V128Load64Splat(memarg) => { sink.push(0xFD); 0x0Au32.encode(sink); memarg.encode(sink); } - Instruction::V128Store { memarg } => { + Instruction::V128Store(memarg) => { sink.push(0xFD); 0x0Bu32.encode(sink); memarg.encode(sink); @@ -1370,7 +1437,7 @@ impl Encode for Instruction<'_> { 0x0Cu32.encode(sink); sink.extend(x.to_le_bytes().iter().copied()); } - Instruction::I8x16Shuffle { lanes } => { + Instruction::I8x16Shuffle(lanes) => { sink.push(0xFD); 0x0Du32.encode(sink); assert!(lanes.iter().all(|l: &u8| *l < 32)); @@ -1404,85 +1471,85 @@ impl Encode for Instruction<'_> { sink.push(0xFD); 0x14u32.encode(sink); } - Instruction::I8x16ExtractLaneS { lane } => { + Instruction::I8x16ExtractLaneS(lane) => { sink.push(0xFD); 0x15u32.encode(sink); assert!(lane < 16); sink.push(lane); } - Instruction::I8x16ExtractLaneU { lane } => { + Instruction::I8x16ExtractLaneU(lane) => { sink.push(0xFD); 0x16u32.encode(sink); assert!(lane < 16); sink.push(lane); } - Instruction::I8x16ReplaceLane { lane } => { + Instruction::I8x16ReplaceLane(lane) => { sink.push(0xFD); 0x17u32.encode(sink); assert!(lane < 16); sink.push(lane); } - Instruction::I16x8ExtractLaneS { lane } => { + Instruction::I16x8ExtractLaneS(lane) => { sink.push(0xFD); 0x18u32.encode(sink); assert!(lane < 8); sink.push(lane); } - Instruction::I16x8ExtractLaneU { lane } => { + Instruction::I16x8ExtractLaneU(lane) => { sink.push(0xFD); 0x19u32.encode(sink); assert!(lane < 8); sink.push(lane); } - Instruction::I16x8ReplaceLane { lane } => { + Instruction::I16x8ReplaceLane(lane) => { sink.push(0xFD); 0x1Au32.encode(sink); assert!(lane < 8); sink.push(lane); } - Instruction::I32x4ExtractLane { lane } => { + Instruction::I32x4ExtractLane(lane) => { sink.push(0xFD); 0x1Bu32.encode(sink); assert!(lane < 4); sink.push(lane); } - Instruction::I32x4ReplaceLane { lane } => { + Instruction::I32x4ReplaceLane(lane) => { sink.push(0xFD); 0x1Cu32.encode(sink); assert!(lane < 4); sink.push(lane); } - Instruction::I64x2ExtractLane { lane } => { + Instruction::I64x2ExtractLane(lane) => { sink.push(0xFD); 0x1Du32.encode(sink); assert!(lane < 2); sink.push(lane); } - Instruction::I64x2ReplaceLane { lane } => { + Instruction::I64x2ReplaceLane(lane) => { sink.push(0xFD); 0x1Eu32.encode(sink); assert!(lane < 2); sink.push(lane); } - Instruction::F32x4ExtractLane { lane } => { + Instruction::F32x4ExtractLane(lane) => { sink.push(0xFD); 0x1Fu32.encode(sink); assert!(lane < 4); sink.push(lane); } - Instruction::F32x4ReplaceLane { lane } => { + Instruction::F32x4ReplaceLane(lane) => { sink.push(0xFD); 0x20u32.encode(sink); assert!(lane < 4); sink.push(lane); } - Instruction::F64x2ExtractLane { lane } => { + Instruction::F64x2ExtractLane(lane) => { sink.push(0xFD); 0x21u32.encode(sink); assert!(lane < 2); sink.push(lane); } - Instruction::F64x2ReplaceLane { lane } => { + Instruction::F64x2ReplaceLane(lane) => { sink.push(0xFD); 0x22u32.encode(sink); assert!(lane < 2); @@ -1765,7 +1832,7 @@ impl Encode for Instruction<'_> { sink.push(0xFD); 0x79u32.encode(sink); } - Instruction::I8x16RoundingAverageU => { + Instruction::I8x16AvgrU => { sink.push(0xFD); 0x7Bu32.encode(sink); } @@ -1885,7 +1952,7 @@ impl Encode for Instruction<'_> { sink.push(0xFD); 0x99u32.encode(sink); } - Instruction::I16x8RoundingAverageU => { + Instruction::I16x8AvgrU => { sink.push(0xFD); 0x9Bu32.encode(sink); } @@ -2229,12 +2296,12 @@ impl Encode for Instruction<'_> { sink.push(0xFD); 0x5Fu32.encode(sink); } - Instruction::V128Load32Zero { memarg } => { + Instruction::V128Load32Zero(memarg) => { sink.push(0xFD); 0x5Cu32.encode(sink); memarg.encode(sink); } - Instruction::V128Load64Zero { memarg } => { + Instruction::V128Load64Zero(memarg) => { sink.push(0xFD); 0x5Du32.encode(sink); memarg.encode(sink); @@ -2313,7 +2380,7 @@ impl Encode for Instruction<'_> { } Instruction::I64x2LeS => { sink.push(0xFD); - 0xDDu32.encode(sink); + 0xDAu32.encode(sink); } Instruction::I64x2GeS => { sink.push(0xFD); @@ -2321,85 +2388,97 @@ impl Encode for Instruction<'_> { } Instruction::I8x16RelaxedSwizzle => { sink.push(0xFD); - 0xA2u32.encode(sink); + 0x100u32.encode(sink); } - Instruction::I32x4RelaxedTruncSatF32x4S => { + Instruction::I32x4RelaxedTruncF32x4S => { sink.push(0xFD); - 0xA5u32.encode(sink); + 0x101u32.encode(sink); } - Instruction::I32x4RelaxedTruncSatF32x4U => { + Instruction::I32x4RelaxedTruncF32x4U => { sink.push(0xFD); - 0xA6u32.encode(sink); + 0x102u32.encode(sink); } - Instruction::I32x4RelaxedTruncSatF64x2SZero => { + Instruction::I32x4RelaxedTruncF64x2SZero => { sink.push(0xFD); - 0xC5u32.encode(sink); + 0x103u32.encode(sink); } - Instruction::I32x4RelaxedTruncSatF64x2UZero => { + Instruction::I32x4RelaxedTruncF64x2UZero => { sink.push(0xFD); - 0xC6u32.encode(sink); + 0x104u32.encode(sink); } - Instruction::F32x4Fma => { + Instruction::F32x4RelaxedMadd => { sink.push(0xFD); - 0xAFu32.encode(sink); + 0x105u32.encode(sink); } - Instruction::F32x4Fms => { + Instruction::F32x4RelaxedNmadd => { sink.push(0xFD); - 0xB0u32.encode(sink); + 0x106u32.encode(sink); } - Instruction::F64x2Fma => { + Instruction::F64x2RelaxedMadd => { sink.push(0xFD); - 0xCFu32.encode(sink); + 0x107u32.encode(sink); } - Instruction::F64x2Fms => { + Instruction::F64x2RelaxedNmadd => { sink.push(0xFD); - 0xD0u32.encode(sink); + 0x108u32.encode(sink); } - Instruction::I8x16LaneSelect => { + Instruction::I8x16RelaxedLaneselect => { sink.push(0xFD); - 0xB2u32.encode(sink); + 0x109u32.encode(sink); } - Instruction::I16x8LaneSelect => { + Instruction::I16x8RelaxedLaneselect => { sink.push(0xFD); - 0xB3u32.encode(sink); + 0x10Au32.encode(sink); } - Instruction::I32x4LaneSelect => { + Instruction::I32x4RelaxedLaneselect => { sink.push(0xFD); - 0xD2u32.encode(sink); + 0x10Bu32.encode(sink); } - Instruction::I64x2LaneSelect => { + Instruction::I64x2RelaxedLaneselect => { sink.push(0xFD); - 0xD3u32.encode(sink); + 0x10Cu32.encode(sink); } Instruction::F32x4RelaxedMin => { sink.push(0xFD); - 0xB4u32.encode(sink); + 0x10Du32.encode(sink); } Instruction::F32x4RelaxedMax => { sink.push(0xFD); - 0xE2u32.encode(sink); + 0x10Eu32.encode(sink); } Instruction::F64x2RelaxedMin => { sink.push(0xFD); - 0xD4u32.encode(sink); + 0x10Fu32.encode(sink); } Instruction::F64x2RelaxedMax => { sink.push(0xFD); - 0xEEu32.encode(sink); + 0x110u32.encode(sink); + } + Instruction::I16x8RelaxedQ15mulrS => { + sink.push(0xFD); + 0x111u32.encode(sink); + } + Instruction::I16x8RelaxedDotI8x16I7x16S => { + sink.push(0xFD); + 0x112u32.encode(sink); + } + Instruction::I32x4RelaxedDotI8x16I7x16AddS => { + sink.push(0xFD); + 0x113u32.encode(sink); } // Atmoic instructions from the thread proposal - Instruction::MemoryAtomicNotify { memarg } => { + Instruction::MemoryAtomicNotify(memarg) => { sink.push(0xFE); sink.push(0x00); memarg.encode(sink); } - Instruction::MemoryAtomicWait32 { memarg } => { + Instruction::MemoryAtomicWait32(memarg) => { sink.push(0xFE); sink.push(0x01); memarg.encode(sink); } - Instruction::MemoryAtomicWait64 { memarg } => { + Instruction::MemoryAtomicWait64(memarg) => { sink.push(0xFE); sink.push(0x02); memarg.encode(sink); @@ -2409,317 +2488,317 @@ impl Encode for Instruction<'_> { sink.push(0x03); sink.push(0x00); } - Instruction::I32AtomicLoad { memarg } => { + Instruction::I32AtomicLoad(memarg) => { sink.push(0xFE); sink.push(0x10); memarg.encode(sink); } - Instruction::I64AtomicLoad { memarg } => { + Instruction::I64AtomicLoad(memarg) => { sink.push(0xFE); sink.push(0x11); memarg.encode(sink); } - Instruction::I32AtomicLoad8U { memarg } => { + Instruction::I32AtomicLoad8U(memarg) => { sink.push(0xFE); sink.push(0x12); memarg.encode(sink); } - Instruction::I32AtomicLoad16U { memarg } => { + Instruction::I32AtomicLoad16U(memarg) => { sink.push(0xFE); sink.push(0x13); memarg.encode(sink); } - Instruction::I64AtomicLoad8U { memarg } => { + Instruction::I64AtomicLoad8U(memarg) => { sink.push(0xFE); sink.push(0x14); memarg.encode(sink); } - Instruction::I64AtomicLoad16U { memarg } => { + Instruction::I64AtomicLoad16U(memarg) => { sink.push(0xFE); sink.push(0x15); memarg.encode(sink); } - Instruction::I64AtomicLoad32U { memarg } => { + Instruction::I64AtomicLoad32U(memarg) => { sink.push(0xFE); sink.push(0x16); memarg.encode(sink); } - Instruction::I32AtomicStore { memarg } => { + Instruction::I32AtomicStore(memarg) => { sink.push(0xFE); sink.push(0x17); memarg.encode(sink); } - Instruction::I64AtomicStore { memarg } => { + Instruction::I64AtomicStore(memarg) => { sink.push(0xFE); sink.push(0x18); memarg.encode(sink); } - Instruction::I32AtomicStore8 { memarg } => { + Instruction::I32AtomicStore8(memarg) => { sink.push(0xFE); sink.push(0x19); memarg.encode(sink); } - Instruction::I32AtomicStore16 { memarg } => { + Instruction::I32AtomicStore16(memarg) => { sink.push(0xFE); sink.push(0x1A); memarg.encode(sink); } - Instruction::I64AtomicStore8 { memarg } => { + Instruction::I64AtomicStore8(memarg) => { sink.push(0xFE); sink.push(0x1B); memarg.encode(sink); } - Instruction::I64AtomicStore16 { memarg } => { + Instruction::I64AtomicStore16(memarg) => { sink.push(0xFE); sink.push(0x1C); memarg.encode(sink); } - Instruction::I64AtomicStore32 { memarg } => { + Instruction::I64AtomicStore32(memarg) => { sink.push(0xFE); sink.push(0x1D); memarg.encode(sink); } - Instruction::I32AtomicRmwAdd { memarg } => { + Instruction::I32AtomicRmwAdd(memarg) => { sink.push(0xFE); sink.push(0x1E); memarg.encode(sink); } - Instruction::I64AtomicRmwAdd { memarg } => { + Instruction::I64AtomicRmwAdd(memarg) => { sink.push(0xFE); sink.push(0x1F); memarg.encode(sink); } - Instruction::I32AtomicRmw8AddU { memarg } => { + Instruction::I32AtomicRmw8AddU(memarg) => { sink.push(0xFE); sink.push(0x20); memarg.encode(sink); } - Instruction::I32AtomicRmw16AddU { memarg } => { + Instruction::I32AtomicRmw16AddU(memarg) => { sink.push(0xFE); sink.push(0x21); memarg.encode(sink); } - Instruction::I64AtomicRmw8AddU { memarg } => { + Instruction::I64AtomicRmw8AddU(memarg) => { sink.push(0xFE); sink.push(0x22); memarg.encode(sink); } - Instruction::I64AtomicRmw16AddU { memarg } => { + Instruction::I64AtomicRmw16AddU(memarg) => { sink.push(0xFE); sink.push(0x23); memarg.encode(sink); } - Instruction::I64AtomicRmw32AddU { memarg } => { + Instruction::I64AtomicRmw32AddU(memarg) => { sink.push(0xFE); sink.push(0x24); memarg.encode(sink); } - Instruction::I32AtomicRmwSub { memarg } => { + Instruction::I32AtomicRmwSub(memarg) => { sink.push(0xFE); sink.push(0x25); memarg.encode(sink); } - Instruction::I64AtomicRmwSub { memarg } => { + Instruction::I64AtomicRmwSub(memarg) => { sink.push(0xFE); sink.push(0x26); memarg.encode(sink); } - Instruction::I32AtomicRmw8SubU { memarg } => { + Instruction::I32AtomicRmw8SubU(memarg) => { sink.push(0xFE); sink.push(0x27); memarg.encode(sink); } - Instruction::I32AtomicRmw16SubU { memarg } => { + Instruction::I32AtomicRmw16SubU(memarg) => { sink.push(0xFE); sink.push(0x28); memarg.encode(sink); } - Instruction::I64AtomicRmw8SubU { memarg } => { + Instruction::I64AtomicRmw8SubU(memarg) => { sink.push(0xFE); sink.push(0x29); memarg.encode(sink); } - Instruction::I64AtomicRmw16SubU { memarg } => { + Instruction::I64AtomicRmw16SubU(memarg) => { sink.push(0xFE); sink.push(0x2A); memarg.encode(sink); } - Instruction::I64AtomicRmw32SubU { memarg } => { + Instruction::I64AtomicRmw32SubU(memarg) => { sink.push(0xFE); sink.push(0x2B); memarg.encode(sink); } - Instruction::I32AtomicRmwAnd { memarg } => { + Instruction::I32AtomicRmwAnd(memarg) => { sink.push(0xFE); sink.push(0x2C); memarg.encode(sink); } - Instruction::I64AtomicRmwAnd { memarg } => { + Instruction::I64AtomicRmwAnd(memarg) => { sink.push(0xFE); sink.push(0x2D); memarg.encode(sink); } - Instruction::I32AtomicRmw8AndU { memarg } => { + Instruction::I32AtomicRmw8AndU(memarg) => { sink.push(0xFE); sink.push(0x2E); memarg.encode(sink); } - Instruction::I32AtomicRmw16AndU { memarg } => { + Instruction::I32AtomicRmw16AndU(memarg) => { sink.push(0xFE); sink.push(0x2F); memarg.encode(sink); } - Instruction::I64AtomicRmw8AndU { memarg } => { + Instruction::I64AtomicRmw8AndU(memarg) => { sink.push(0xFE); sink.push(0x30); memarg.encode(sink); } - Instruction::I64AtomicRmw16AndU { memarg } => { + Instruction::I64AtomicRmw16AndU(memarg) => { sink.push(0xFE); sink.push(0x31); memarg.encode(sink); } - Instruction::I64AtomicRmw32AndU { memarg } => { + Instruction::I64AtomicRmw32AndU(memarg) => { sink.push(0xFE); sink.push(0x32); memarg.encode(sink); } - Instruction::I32AtomicRmwOr { memarg } => { + Instruction::I32AtomicRmwOr(memarg) => { sink.push(0xFE); sink.push(0x33); memarg.encode(sink); } - Instruction::I64AtomicRmwOr { memarg } => { + Instruction::I64AtomicRmwOr(memarg) => { sink.push(0xFE); sink.push(0x34); memarg.encode(sink); } - Instruction::I32AtomicRmw8OrU { memarg } => { + Instruction::I32AtomicRmw8OrU(memarg) => { sink.push(0xFE); sink.push(0x35); memarg.encode(sink); } - Instruction::I32AtomicRmw16OrU { memarg } => { + Instruction::I32AtomicRmw16OrU(memarg) => { sink.push(0xFE); sink.push(0x36); memarg.encode(sink); } - Instruction::I64AtomicRmw8OrU { memarg } => { + Instruction::I64AtomicRmw8OrU(memarg) => { sink.push(0xFE); sink.push(0x37); memarg.encode(sink); } - Instruction::I64AtomicRmw16OrU { memarg } => { + Instruction::I64AtomicRmw16OrU(memarg) => { sink.push(0xFE); sink.push(0x38); memarg.encode(sink); } - Instruction::I64AtomicRmw32OrU { memarg } => { + Instruction::I64AtomicRmw32OrU(memarg) => { sink.push(0xFE); sink.push(0x39); memarg.encode(sink); } - Instruction::I32AtomicRmwXor { memarg } => { + Instruction::I32AtomicRmwXor(memarg) => { sink.push(0xFE); sink.push(0x3A); memarg.encode(sink); } - Instruction::I64AtomicRmwXor { memarg } => { + Instruction::I64AtomicRmwXor(memarg) => { sink.push(0xFE); sink.push(0x3B); memarg.encode(sink); } - Instruction::I32AtomicRmw8XorU { memarg } => { + Instruction::I32AtomicRmw8XorU(memarg) => { sink.push(0xFE); sink.push(0x3C); memarg.encode(sink); } - Instruction::I32AtomicRmw16XorU { memarg } => { + Instruction::I32AtomicRmw16XorU(memarg) => { sink.push(0xFE); sink.push(0x3D); memarg.encode(sink); } - Instruction::I64AtomicRmw8XorU { memarg } => { + Instruction::I64AtomicRmw8XorU(memarg) => { sink.push(0xFE); sink.push(0x3E); memarg.encode(sink); } - Instruction::I64AtomicRmw16XorU { memarg } => { + Instruction::I64AtomicRmw16XorU(memarg) => { sink.push(0xFE); sink.push(0x3F); memarg.encode(sink); } - Instruction::I64AtomicRmw32XorU { memarg } => { + Instruction::I64AtomicRmw32XorU(memarg) => { sink.push(0xFE); sink.push(0x40); memarg.encode(sink); } - Instruction::I32AtomicRmwXchg { memarg } => { + Instruction::I32AtomicRmwXchg(memarg) => { sink.push(0xFE); sink.push(0x41); memarg.encode(sink); } - Instruction::I64AtomicRmwXchg { memarg } => { + Instruction::I64AtomicRmwXchg(memarg) => { sink.push(0xFE); sink.push(0x42); memarg.encode(sink); } - Instruction::I32AtomicRmw8XchgU { memarg } => { + Instruction::I32AtomicRmw8XchgU(memarg) => { sink.push(0xFE); sink.push(0x43); memarg.encode(sink); } - Instruction::I32AtomicRmw16XchgU { memarg } => { + Instruction::I32AtomicRmw16XchgU(memarg) => { sink.push(0xFE); sink.push(0x44); memarg.encode(sink); } - Instruction::I64AtomicRmw8XchgU { memarg } => { + Instruction::I64AtomicRmw8XchgU(memarg) => { sink.push(0xFE); sink.push(0x45); memarg.encode(sink); } - Instruction::I64AtomicRmw16XchgU { memarg } => { + Instruction::I64AtomicRmw16XchgU(memarg) => { sink.push(0xFE); sink.push(0x46); memarg.encode(sink); } - Instruction::I64AtomicRmw32XchgU { memarg } => { + Instruction::I64AtomicRmw32XchgU(memarg) => { sink.push(0xFE); sink.push(0x47); memarg.encode(sink); } - Instruction::I32AtomicRmwCmpxchg { memarg } => { + Instruction::I32AtomicRmwCmpxchg(memarg) => { sink.push(0xFE); sink.push(0x48); memarg.encode(sink); } - Instruction::I64AtomicRmwCmpxchg { memarg } => { + Instruction::I64AtomicRmwCmpxchg(memarg) => { sink.push(0xFE); sink.push(0x49); memarg.encode(sink); } - Instruction::I32AtomicRmw8CmpxchgU { memarg } => { + Instruction::I32AtomicRmw8CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4A); memarg.encode(sink); } - Instruction::I32AtomicRmw16CmpxchgU { memarg } => { + Instruction::I32AtomicRmw16CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4B); memarg.encode(sink); } - Instruction::I64AtomicRmw8CmpxchgU { memarg } => { + Instruction::I64AtomicRmw8CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4C); memarg.encode(sink); } - Instruction::I64AtomicRmw16CmpxchgU { memarg } => { + Instruction::I64AtomicRmw16CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4D); memarg.encode(sink); } - Instruction::I64AtomicRmw32CmpxchgU { memarg } => { + Instruction::I64AtomicRmw32CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4E); memarg.encode(sink); @@ -2761,7 +2840,7 @@ impl ConstExpr { } /// Create a constant expression containing a single `ref.null` instruction. - pub fn ref_null(ty: ValType) -> Self { + pub fn ref_null(ty: HeapType) -> Self { Self::new_insn(Instruction::RefNull(ty)) } @@ -2803,6 +2882,82 @@ impl Encode for ConstExpr { } } +/// An error when converting a `wasmparser::ConstExpr` into a +/// `wasm_encoder::ConstExpr`. +#[cfg(feature = "wasmparser")] +#[derive(Debug)] +pub enum ConstExprConversionError { + /// There was an error when parsing the const expression. + ParseError(wasmparser::BinaryReaderError), + + /// The const expression is invalid: not actually constant or something like + /// that. + Invalid, +} + +#[cfg(feature = "wasmparser")] +impl std::fmt::Display for ConstExprConversionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ParseError(_e) => { + write!(f, "There was an error when parsing the const expression") + } + Self::Invalid => write!(f, "The const expression was invalid"), + } + } +} + +#[cfg(feature = "wasmparser")] +impl std::error::Error for ConstExprConversionError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::ParseError(e) => Some(e), + Self::Invalid => None, + } + } +} + +#[cfg(feature = "wasmparser")] +impl<'a> TryFrom> for ConstExpr { + type Error = ConstExprConversionError; + + fn try_from(const_expr: wasmparser::ConstExpr) -> Result { + let mut ops = const_expr.get_operators_reader().into_iter(); + + let result = match ops.next() { + Some(Ok(wasmparser::Operator::I32Const { value })) => ConstExpr::i32_const(value), + Some(Ok(wasmparser::Operator::I64Const { value })) => ConstExpr::i64_const(value), + Some(Ok(wasmparser::Operator::F32Const { value })) => { + ConstExpr::f32_const(value.bits() as _) + } + Some(Ok(wasmparser::Operator::F64Const { value })) => { + ConstExpr::f64_const(value.bits() as _) + } + Some(Ok(wasmparser::Operator::V128Const { value })) => { + ConstExpr::v128_const(i128::from_le_bytes(*value.bytes())) + } + Some(Ok(wasmparser::Operator::RefNull { hty })) => ConstExpr::ref_null(hty.into()), + Some(Ok(wasmparser::Operator::RefFunc { function_index })) => { + ConstExpr::ref_func(function_index) + } + Some(Ok(wasmparser::Operator::GlobalGet { global_index })) => { + ConstExpr::global_get(global_index) + } + + // TODO: support the extended-const proposal. + Some(Ok(_op)) => return Err(ConstExprConversionError::Invalid), + + Some(Err(e)) => return Err(ConstExprConversionError::ParseError(e)), + None => return Err(ConstExprConversionError::Invalid), + }; + + match (ops.next(), ops.next()) { + (Some(Ok(wasmparser::Operator::End)), None) => Ok(result), + _ => Err(ConstExprConversionError::Invalid), + } + } +} + #[cfg(test)] mod tests { #[test] diff --git a/crates/wasm-encoder/src/core/custom.rs b/crates/wasm-encoder/src/core/custom.rs index 47d78d458c..870ee62617 100644 --- a/crates/wasm-encoder/src/core/custom.rs +++ b/crates/wasm-encoder/src/core/custom.rs @@ -1,12 +1,14 @@ +use std::borrow::Cow; + use crate::{encoding_size, Encode, Section, SectionId}; /// A custom section holding arbitrary data. #[derive(Clone, Debug)] pub struct CustomSection<'a> { /// The name of this custom section. - pub name: &'a str, + pub name: Cow<'a, str>, /// This custom section's data. - pub data: &'a [u8], + pub data: Cow<'a, [u8]>, } impl Encode for CustomSection<'_> { @@ -14,7 +16,7 @@ impl Encode for CustomSection<'_> { let encoded_name_len = encoding_size(u32::try_from(self.name.len()).unwrap()); (encoded_name_len + self.name.len() + self.data.len()).encode(sink); self.name.encode(sink); - sink.extend(self.data); + sink.extend(&*self.data); } } @@ -24,6 +26,24 @@ impl Section for CustomSection<'_> { } } +/// A raw custom section where the bytes specified contain the leb-encoded +/// length of the custom section, the custom section's name, and the custom +/// section's data. +#[derive(Clone, Debug)] +pub struct RawCustomSection<'a>(pub &'a [u8]); + +impl Encode for RawCustomSection<'_> { + fn encode(&self, sink: &mut Vec) { + sink.extend(self.0); + } +} + +impl Section for RawCustomSection<'_> { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} + #[cfg(test)] mod tests { use super::*; @@ -31,8 +51,8 @@ mod tests { #[test] fn test_custom_section() { let custom = CustomSection { - name: "test", - data: &[11, 22, 33, 44], + name: "test".into(), + data: Cow::Borrowed(&[11, 22, 33, 44]), }; let mut encoded = vec![]; diff --git a/crates/wasm-encoder/src/core/dump.rs b/crates/wasm-encoder/src/core/dump.rs new file mode 100644 index 0000000000..ee3d229909 --- /dev/null +++ b/crates/wasm-encoder/src/core/dump.rs @@ -0,0 +1,627 @@ +use std::borrow::Cow; + +use crate::{CustomSection, Encode, Section}; + +/// The "core" custom section for coredumps, as described in the +/// [tool-conventions +/// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md). +/// +/// There are four sections that comprise a core dump: +/// - "core", which contains the name of the core dump +/// - "coremodules", a listing of modules +/// - "coreinstances", a listing of module instances +/// - "corestack", a listing of frames for a specific thread +/// +/// # Example of how these could be constructed and encoded into a module: +/// +/// ``` +/// use wasm_encoder::{ +/// CoreDumpInstancesSection, CoreDumpModulesSection, CoreDumpSection, CoreDumpStackSection, +/// CoreDumpValue, Module, +/// }; +/// let core = CoreDumpSection::new("MyModule.wasm"); +/// +/// let mut modules = CoreDumpModulesSection::new(); +/// modules.module("my_module"); +/// +/// let mut instances = CoreDumpInstancesSection::new(); +/// let module_idx = 0; +/// let memories = vec![1]; +/// let globals = vec![2]; +/// instances.instance(module_idx, memories, globals); +/// +/// let mut thread = CoreDumpStackSection::new("main"); +/// let instance_index = 0; +/// let func_index = 42; +/// let code_offset = 0x1234; +/// let locals = vec![CoreDumpValue::I32(1)]; +/// let stack = vec![CoreDumpValue::I32(2)]; +/// thread.frame(instance_index, func_index, code_offset, locals, stack); +/// +/// let mut module = Module::new(); +/// module.section(&core); +/// module.section(&modules); +/// module.section(&instances); +/// module.section(&thread); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct CoreDumpSection { + name: String, +} + +impl CoreDumpSection { + /// Create a new core dump section encoder + pub fn new(name: impl Into) -> Self { + let name = name.into(); + CoreDumpSection { name } + } + + /// View the encoded section as a CustomSection. + fn as_custom<'a>(&'a self) -> CustomSection<'a> { + let mut data = vec![0]; + self.name.encode(&mut data); + CustomSection { + name: "core".into(), + data: Cow::Owned(data), + } + } +} + +impl Encode for CoreDumpSection { + fn encode(&self, sink: &mut Vec) { + self.as_custom().encode(sink); + } +} + +impl Section for CoreDumpSection { + fn id(&self) -> u8 { + crate::core::SectionId::Custom as u8 + } +} + +/// The "coremodules" custom section for coredumps which lists the names of the +/// modules +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{CoreDumpModulesSection, Module}; +/// let mut modules_section = CoreDumpModulesSection::new(); +/// modules_section.module("my_module"); +/// let mut module = Module::new(); +/// module.section(&modules_section); +/// ``` +#[derive(Debug)] +pub struct CoreDumpModulesSection { + num_added: u32, + bytes: Vec, +} + +impl CoreDumpModulesSection { + /// Create a new core dump modules section encoder. + pub fn new() -> Self { + CoreDumpModulesSection { + bytes: vec![], + num_added: 0, + } + } + + /// View the encoded section as a CustomSection. + pub fn as_custom(&self) -> CustomSection<'_> { + let mut data = vec![]; + self.num_added.encode(&mut data); + data.extend(self.bytes.iter().copied()); + CustomSection { + name: "coremodules".into(), + data: Cow::Owned(data), + } + } + + /// Encode a module name into the section's bytes. + pub fn module(&mut self, module_name: impl AsRef) -> &mut Self { + self.bytes.push(0x0); + module_name.as_ref().encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// The number of modules that are encoded in the section. + pub fn len(&self) -> u32 { + self.num_added + } +} + +impl Encode for CoreDumpModulesSection { + fn encode(&self, sink: &mut Vec) { + self.as_custom().encode(sink); + } +} + +impl Section for CoreDumpModulesSection { + fn id(&self) -> u8 { + crate::core::SectionId::Custom as u8 + } +} + +/// The "coreinstances" section for the core dump +#[derive(Debug)] +pub struct CoreDumpInstancesSection { + num_added: u32, + bytes: Vec, +} + +impl CoreDumpInstancesSection { + /// Create a new core dump instances section encoder. + pub fn new() -> Self { + CoreDumpInstancesSection { + bytes: vec![], + num_added: 0, + } + } + + /// View the encoded section as a CustomSection. + pub fn as_custom(&self) -> CustomSection<'_> { + let mut data = vec![]; + self.num_added.encode(&mut data); + data.extend(self.bytes.iter().copied()); + CustomSection { + name: "coreinstances".into(), + data: Cow::Owned(data), + } + } + + /// Encode an instance into the section's bytes. + pub fn instance(&mut self, module_index: u32, memories: M, globals: G) -> &mut Self + where + M: IntoIterator, + ::IntoIter: ExactSizeIterator, + G: IntoIterator, + ::IntoIter: ExactSizeIterator, + { + self.bytes.push(0x0); + module_index.encode(&mut self.bytes); + crate::encode_vec(memories, &mut self.bytes); + crate::encode_vec(globals, &mut self.bytes); + self.num_added += 1; + self + } + + /// The number of modules that are encoded in the section. + pub fn len(&self) -> u32 { + self.num_added + } +} + +impl Encode for CoreDumpInstancesSection { + fn encode(&self, sink: &mut Vec) { + self.as_custom().encode(sink); + } +} + +impl Section for CoreDumpInstancesSection { + fn id(&self) -> u8 { + crate::core::SectionId::Custom as u8 + } +} + +/// A "corestack" custom section as described in the [tool-conventions +/// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md) +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{CoreDumpStackSection, Module, CoreDumpValue}; +/// let mut thread = CoreDumpStackSection::new("main"); +/// +/// let instance_index = 0; +/// let func_index = 42; +/// let code_offset = 0x1234; +/// let locals = vec![CoreDumpValue::I32(1)]; +/// let stack = vec![CoreDumpValue::I32(2)]; +/// thread.frame(instance_index, func_index, code_offset, locals, stack); +/// +/// let mut module = Module::new(); +/// module.section(&thread); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct CoreDumpStackSection { + frame_bytes: Vec, + count: u32, + name: String, +} + +impl CoreDumpStackSection { + /// Create a new core dump stack section encoder. + pub fn new(name: impl Into) -> Self { + let name = name.into(); + CoreDumpStackSection { + frame_bytes: Vec::new(), + count: 0, + name, + } + } + + /// Add a stack frame to this coredump stack section. + pub fn frame( + &mut self, + instanceidx: u32, + funcidx: u32, + codeoffset: u32, + locals: L, + stack: S, + ) -> &mut Self + where + L: IntoIterator, + ::IntoIter: ExactSizeIterator, + S: IntoIterator, + ::IntoIter: ExactSizeIterator, + { + self.count += 1; + self.frame_bytes.push(0); + instanceidx.encode(&mut self.frame_bytes); + funcidx.encode(&mut self.frame_bytes); + codeoffset.encode(&mut self.frame_bytes); + crate::encode_vec(locals, &mut self.frame_bytes); + crate::encode_vec(stack, &mut self.frame_bytes); + self + } + + /// View the encoded section as a CustomSection. + pub fn as_custom<'a>(&'a self) -> CustomSection<'a> { + let mut data = vec![0]; + self.name.encode(&mut data); + self.count.encode(&mut data); + data.extend(&self.frame_bytes); + CustomSection { + name: "corestack".into(), + data: Cow::Owned(data), + } + } +} + +impl Encode for CoreDumpStackSection { + fn encode(&self, sink: &mut Vec) { + self.as_custom().encode(sink); + } +} + +impl Section for CoreDumpStackSection { + fn id(&self) -> u8 { + crate::core::SectionId::Custom as u8 + } +} + +/// Local and stack values are encoded using one byte for the type (similar to +/// Wasm's Number Types) followed by bytes representing the actual value +/// See the tool-conventions repo for more details. +#[derive(Clone, Debug)] +pub enum CoreDumpValue { + /// a missing value (usually missing because it was optimized out) + Missing, + /// An i32 value + I32(i32), + /// An i64 value + I64(i64), + /// An f32 value + F32(f32), + /// An f64 value + F64(f64), +} + +impl Encode for CoreDumpValue { + fn encode(&self, sink: &mut Vec) { + match self { + CoreDumpValue::Missing => sink.push(0x01), + CoreDumpValue::I32(x) => { + sink.push(0x7F); + x.encode(sink); + } + CoreDumpValue::I64(x) => { + sink.push(0x7E); + x.encode(sink); + } + CoreDumpValue::F32(x) => { + sink.push(0x7D); + x.encode(sink); + } + CoreDumpValue::F64(x) => { + sink.push(0x7C); + x.encode(sink); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::Module; + use wasmparser::{BinaryReader, FromReader, Parser, Payload}; + + // Create new core dump section and test whether it is properly encoded and + // parsed back out by wasmparser + #[test] + fn test_roundtrip_core() { + let core = CoreDumpSection::new("test.wasm"); + let mut module = Module::new(); + module.section(&core); + + let wasm_bytes = module.finish(); + + let mut parser = Parser::new(0).parse_all(&wasm_bytes); + match parser.next() { + Some(Ok(Payload::Version { .. })) => {} + _ => panic!(""), + } + + let payload = parser + .next() + .expect("parser is not empty") + .expect("element is a payload"); + match payload { + Payload::CustomSection(section) => { + assert_eq!(section.name(), "core"); + let core = wasmparser::CoreDumpSection::from_reader(&mut BinaryReader::new( + section.data(), + )) + .expect("data is readable into a core dump section"); + assert_eq!(core.name, "test.wasm"); + } + _ => panic!("unexpected payload"), + } + } + + #[test] + fn test_roundtrip_coremodules() { + let mut coremodules = CoreDumpModulesSection::new(); + coremodules.module("test_module"); + + let mut module = crate::Module::new(); + module.section(&coremodules); + + let wasm_bytes = module.finish(); + + let mut parser = Parser::new(0).parse_all(&wasm_bytes); + match parser.next() { + Some(Ok(Payload::Version { .. })) => {} + _ => panic!(""), + } + + let payload = parser + .next() + .expect("parser is not empty") + .expect("element is a payload"); + match payload { + Payload::CustomSection(section) => { + assert_eq!(section.name(), "coremodules"); + let modules = wasmparser::CoreDumpModulesSection::from_reader( + &mut BinaryReader::new(section.data()), + ) + .expect("data is readable into a core dump modules section"); + assert_eq!(modules.modules[0], "test_module"); + } + _ => panic!("unexpected payload"), + } + } + + #[test] + fn test_roundtrip_coreinstances() { + let mut coreinstances = CoreDumpInstancesSection::new(); + let module_index = 0; + let memories = vec![42]; + let globals = vec![17]; + coreinstances.instance(module_index, memories, globals); + + let mut module = Module::new(); + module.section(&coreinstances); + let wasm_bytes = module.finish(); + + let mut parser = Parser::new(0).parse_all(&wasm_bytes); + match parser.next() { + Some(Ok(Payload::Version { .. })) => {} + _ => panic!(""), + } + + let payload = parser + .next() + .expect("parser is not empty") + .expect("element is a payload"); + match payload { + Payload::CustomSection(section) => { + assert_eq!(section.name(), "coreinstances"); + let coreinstances = wasmparser::CoreDumpInstancesSection::from_reader( + &mut BinaryReader::new(section.data()), + ) + .expect("data is readable into a core dump instances section"); + assert_eq!(coreinstances.instances.len(), 1); + let instance = coreinstances + .instances + .first() + .expect("instance is encoded"); + assert_eq!(instance.module_index, 0); + assert_eq!(instance.memories.len(), 1); + assert_eq!(instance.globals.len(), 1); + } + _ => panic!("unexpected payload"), + } + } + + // Create new corestack section and test whether it is properly encoded and + // parsed back out by wasmparser + #[test] + fn test_roundtrip_corestack() { + let mut corestack = CoreDumpStackSection::new("main"); + corestack.frame( + 0, + 12, + 0, + vec![CoreDumpValue::I32(10)], + vec![CoreDumpValue::I32(42)], + ); + let mut module = Module::new(); + module.section(&corestack); + let wasm_bytes = module.finish(); + + let mut parser = Parser::new(0).parse_all(&wasm_bytes); + match parser.next() { + Some(Ok(Payload::Version { .. })) => {} + _ => panic!(""), + } + + let payload = parser + .next() + .expect("parser is not empty") + .expect("element is a payload"); + match payload { + Payload::CustomSection(section) => { + assert_eq!(section.name(), "corestack"); + let corestack = wasmparser::CoreDumpStackSection::from_reader( + &mut BinaryReader::new(section.data()), + ) + .expect("data is readable into a core dump stack section"); + assert_eq!(corestack.name, "main"); + assert_eq!(corestack.frames.len(), 1); + let frame = corestack + .frames + .first() + .expect("frame is encoded in corestack"); + assert_eq!(frame.instanceidx, 0); + assert_eq!(frame.funcidx, 12); + assert_eq!(frame.codeoffset, 0); + assert_eq!(frame.locals.len(), 1); + match frame.locals.first().expect("frame contains a local") { + &wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 10), + _ => panic!("unexpected local value"), + } + assert_eq!(frame.stack.len(), 1); + match frame.stack.first().expect("stack contains a value") { + &wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 42), + _ => panic!("unexpected stack value"), + } + } + _ => panic!("unexpected payload"), + } + } + + #[test] + fn test_encode_coredump_section() { + let core = CoreDumpSection::new("test"); + + let mut encoded = vec![]; + core.encode(&mut encoded); + + #[rustfmt::skip] + assert_eq!(encoded, vec![ + // section length + 11, + // name length + 4, + // section name (core) + b'c',b'o',b'r',b'e', + // process-info (0, data length, data) + 0, 4, b't', b'e', b's', b't', + ]); + } + + #[test] + fn test_encode_coremodules_section() { + let mut modules = CoreDumpModulesSection::new(); + modules.module("mod1"); + modules.module("mod2"); + + let mut encoded = vec![]; + modules.encode(&mut encoded); + + #[rustfmt::skip] + assert_eq!(encoded, vec![ + // section length + 25, + // name length + 11, + // section name (coremodules) + b'c',b'o',b'r',b'e',b'm',b'o',b'd',b'u',b'l',b'e',b's', + // module count + 2, + // 0x0, name-length, module name (mod1) + 0x0, 4, b'm',b'o',b'd',b'1', + // 0x0, name-length, module name (mod2) + 0x0, 4, b'm',b'o',b'd',b'2' + ]); + } + + #[test] + fn test_encode_coreinstances_section() { + let mut instances = CoreDumpInstancesSection::new(); + instances.instance(0, vec![42], vec![17]); + + let mut encoded = vec![]; + instances.encode(&mut encoded); + + #[rustfmt::skip] + assert_eq!(encoded, vec![ + // section length + 21, + // name length + 13, + // section name (coreinstances) + b'c',b'o',b'r',b'e',b'i',b'n',b's',b't',b'a',b'n',b'c',b'e',b's', + // instance count + 1, + // 0x0, module_idx + 0x0, 0, + // memories count, memories + 1, 42, + // globals count, globals + 1, 17 + ]); + } + + #[test] + fn test_encode_corestack_section() { + let mut thread = CoreDumpStackSection::new("main"); + thread.frame( + 0, + 42, + 51, + vec![CoreDumpValue::I32(1)], + vec![CoreDumpValue::I32(2)], + ); + + let mut encoded = vec![]; + thread.encode(&mut encoded); + + #[rustfmt::skip] + assert_eq!( + encoded, + vec![ + // section length + 27, + // length of name. + 9, + // section name (corestack) + b'c',b'o',b'r',b'e',b's',b't',b'a',b'c',b'k', + // 0x0, thread name length + 0, 4, + // thread name (main) + b'm',b'a',b'i',b'n', + // frame count + 1, + // 0x0, instanceidx, funcidx, codeoffset + 0, 0, 42, 51, + // local count + 1, + // local value type + 0x7F, + // local value + 1, + // stack count + 1, + // stack value type + 0x7F, + // stack value + 2 + + ] + ); + } +} diff --git a/crates/wasm-encoder/src/core/elements.rs b/crates/wasm-encoder/src/core/elements.rs index 5eb641247b..31b772186a 100644 --- a/crates/wasm-encoder/src/core/elements.rs +++ b/crates/wasm-encoder/src/core/elements.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType}; +use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId}; /// An encoder for the element section. /// @@ -9,12 +9,12 @@ use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType}; /// ``` /// use wasm_encoder::{ /// Elements, ElementSection, Module, TableSection, TableType, -/// ValType, ConstExpr +/// RefType, ConstExpr /// }; /// /// let mut tables = TableSection::new(); /// tables.table(TableType { -/// element_type: ValType::FuncRef, +/// element_type: RefType::FUNCREF, /// minimum: 128, /// maximum: None, /// }); @@ -22,11 +22,10 @@ use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType}; /// let mut elements = ElementSection::new(); /// let table_index = 0; /// let offset = ConstExpr::i32_const(42); -/// let element_type = ValType::FuncRef; /// let functions = Elements::Functions(&[ /// // Function indices... /// ]); -/// elements.active(Some(table_index), &offset, element_type, functions); +/// elements.active(Some(table_index), &offset, functions); /// /// let mut module = Module::new(); /// module @@ -47,7 +46,7 @@ pub enum Elements<'a> { /// A sequences of references to functions by their indices. Functions(&'a [u32]), /// A sequence of reference expressions. - Expressions(&'a [ConstExpr]), + Expressions(RefType, &'a [ConstExpr]), } /// An element segment's mode. @@ -79,8 +78,6 @@ pub enum ElementMode<'a> { pub struct ElementSegment<'a> { /// The element segment's mode. pub mode: ElementMode<'a>, - /// The element segment's type. - pub element_type: ValType, /// This segment's elements. pub elements: Elements<'a>, } @@ -104,53 +101,53 @@ impl ElementSection { /// Define an element segment. pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self { let expr_bit = match segment.elements { - Elements::Expressions(_) => 0b100u32, + Elements::Expressions(..) => 0b100u32, Elements::Functions(_) => 0b000u32, }; + let mut encode_type = false; match &segment.mode { - ElementMode::Active { - table: None, - offset, - } => { - (/* 0x00 | */expr_bit).encode(&mut self.bytes); - offset.encode(&mut self.bytes); - } ElementMode::Passive => { (0x01 | expr_bit).encode(&mut self.bytes); - if expr_bit == 0 { - self.bytes.push(0x00); // elemkind == funcref - } else { - segment.element_type.encode(&mut self.bytes); - } + encode_type = true; } - ElementMode::Active { - table: Some(i), - offset, - } => { - (0x02 | expr_bit).encode(&mut self.bytes); - i.encode(&mut self.bytes); - offset.encode(&mut self.bytes); - if expr_bit == 0 { - self.bytes.push(0x00); // elemkind == funcref - } else { - segment.element_type.encode(&mut self.bytes); + ElementMode::Active { table, offset } => { + match (table, &segment.elements) { + // If the `table` is not specified then the 0x00 encoding + // can be used with either function indices or expressions + // that have a `funcref` type. + (None, Elements::Functions(_) | Elements::Expressions(RefType::FUNCREF, _)) => { + (/* 0x00 | */expr_bit).encode(&mut self.bytes); + } + + // ... otherwise fall through for all other expressions here + // with table 0 or an explicitly specified table to the 0x02 + // encoding. + (None, Elements::Expressions(..)) | (Some(_), _) => { + (0x02 | expr_bit).encode(&mut self.bytes); + table.unwrap_or(0).encode(&mut self.bytes); + encode_type = true; + } } + offset.encode(&mut self.bytes); } ElementMode::Declared => { (0x03 | expr_bit).encode(&mut self.bytes); - if expr_bit == 0 { - self.bytes.push(0x00); // elemkind == funcref - } else { - segment.element_type.encode(&mut self.bytes); - } + encode_type = true; } } match segment.elements { Elements::Functions(fs) => { + if encode_type { + // elemkind == funcref + self.bytes.push(0x00); + } fs.encode(&mut self.bytes); } - Elements::Expressions(e) => { + Elements::Expressions(ty, e) => { + if encode_type { + ty.encode(&mut self.bytes); + } e.len().encode(&mut self.bytes); for expr in e { expr.encode(&mut self.bytes); @@ -171,7 +168,6 @@ impl ElementSection { &mut self, table_index: Option, offset: &ConstExpr, - element_type: ValType, elements: Elements<'_>, ) -> &mut Self { self.segment(ElementSegment { @@ -179,7 +175,6 @@ impl ElementSection { table: table_index, offset, }, - element_type, elements, }) } @@ -187,10 +182,9 @@ impl ElementSection { /// Encode a passive element segment. /// /// Passive segments are part of the bulk memory proposal. - pub fn passive<'a>(&mut self, element_type: ValType, elements: Elements<'a>) -> &mut Self { + pub fn passive<'a>(&mut self, elements: Elements<'a>) -> &mut Self { self.segment(ElementSegment { mode: ElementMode::Passive, - element_type, elements, }) } @@ -198,10 +192,9 @@ impl ElementSection { /// Encode a declared element segment. /// /// Declared segments are part of the bulk memory proposal. - pub fn declared<'a>(&mut self, element_type: ValType, elements: Elements<'a>) -> &mut Self { + pub fn declared<'a>(&mut self, elements: Elements<'a>) -> &mut Self { self.segment(ElementSegment { mode: ElementMode::Declared, - element_type, elements, }) } diff --git a/crates/wasm-encoder/src/core/exports.rs b/crates/wasm-encoder/src/core/exports.rs index 0b8006655f..fc2dc9c392 100644 --- a/crates/wasm-encoder/src/core/exports.rs +++ b/crates/wasm-encoder/src/core/exports.rs @@ -5,28 +5,36 @@ use crate::{encode_section, Encode, Section, SectionId}; /// Represents the kind of an export from a WebAssembly module. #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] pub enum ExportKind { /// The export is a function. - Func, + Func = CORE_FUNCTION_SORT, /// The export is a table. - Table, + Table = CORE_TABLE_SORT, /// The export is a memory. - Memory, + Memory = CORE_MEMORY_SORT, /// The export is a global. - Global, + Global = CORE_GLOBAL_SORT, /// The export is a tag. - Tag, + Tag = CORE_TAG_SORT, } impl Encode for ExportKind { fn encode(&self, sink: &mut Vec) { - sink.push(match self { - Self::Func => CORE_FUNCTION_SORT, - Self::Table => CORE_TABLE_SORT, - Self::Memory => CORE_MEMORY_SORT, - Self::Global => CORE_GLOBAL_SORT, - Self::Tag => CORE_TAG_SORT, - }); + sink.push(*self as u8); + } +} + +#[cfg(feature = "wasmparser")] +impl From for ExportKind { + fn from(external_kind: wasmparser::ExternalKind) -> Self { + match external_kind { + wasmparser::ExternalKind::Func => ExportKind::Func, + wasmparser::ExternalKind::Table => ExportKind::Table, + wasmparser::ExternalKind::Memory => ExportKind::Memory, + wasmparser::ExternalKind::Global => ExportKind::Global, + wasmparser::ExternalKind::Tag => ExportKind::Tag, + } } } diff --git a/crates/wasm-encoder/src/core/globals.rs b/crates/wasm-encoder/src/core/globals.rs index 16f23c2891..f31b1475cb 100644 --- a/crates/wasm-encoder/src/core/globals.rs +++ b/crates/wasm-encoder/src/core/globals.rs @@ -88,3 +88,13 @@ impl Encode for GlobalType { sink.push(self.mutable as u8); } } + +#[cfg(feature = "wasmparser")] +impl From for GlobalType { + fn from(global_ty: wasmparser::GlobalType) -> Self { + GlobalType { + val_type: global_ty.content_type.into(), + mutable: global_ty.mutable, + } + } +} diff --git a/crates/wasm-encoder/src/core/imports.rs b/crates/wasm-encoder/src/core/imports.rs index 455170f227..7d60ef6ae2 100644 --- a/crates/wasm-encoder/src/core/imports.rs +++ b/crates/wasm-encoder/src/core/imports.rs @@ -73,6 +73,19 @@ impl From for EntityType { } } +#[cfg(feature = "wasmparser")] +impl From for EntityType { + fn from(type_ref: wasmparser::TypeRef) -> Self { + match type_ref { + wasmparser::TypeRef::Func(i) => EntityType::Function(i), + wasmparser::TypeRef::Table(t) => EntityType::Table(t.into()), + wasmparser::TypeRef::Memory(m) => EntityType::Memory(m.into()), + wasmparser::TypeRef::Global(g) => EntityType::Global(g.into()), + wasmparser::TypeRef::Tag(t) => EntityType::Tag(t.into()), + } + } +} + /// An encoder for the import section of WebAssembly modules. /// /// # Example diff --git a/crates/wasm-encoder/src/core/linking.rs b/crates/wasm-encoder/src/core/linking.rs index 3309277be3..9a2995721f 100644 --- a/crates/wasm-encoder/src/core/linking.rs +++ b/crates/wasm-encoder/src/core/linking.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use crate::{encode_section, CustomSection, Encode, Section, SectionId}; const VERSION: u32 = 2; @@ -72,8 +74,8 @@ impl Default for LinkingSection { impl Encode for LinkingSection { fn encode(&self, sink: &mut Vec) { CustomSection { - name: "linking", - data: &self.bytes, + name: "linking".into(), + data: Cow::Borrowed(&self.bytes), } .encode(sink); } diff --git a/crates/wasm-encoder/src/core/memories.rs b/crates/wasm-encoder/src/core/memories.rs index c651768bdc..892545eb98 100644 --- a/crates/wasm-encoder/src/core/memories.rs +++ b/crates/wasm-encoder/src/core/memories.rs @@ -97,3 +97,15 @@ impl Encode for MemoryType { } } } + +#[cfg(feature = "wasmparser")] +impl From for MemoryType { + fn from(memory_ty: wasmparser::MemoryType) -> Self { + MemoryType { + minimum: memory_ty.initial, + maximum: memory_ty.maximum, + memory64: memory_ty.memory64, + shared: memory_ty.shared, + } + } +} diff --git a/crates/wasm-encoder/src/core/names.rs b/crates/wasm-encoder/src/core/names.rs index 880925918e..7cb01cfa62 100644 --- a/crates/wasm-encoder/src/core/names.rs +++ b/crates/wasm-encoder/src/core/names.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use crate::{encoding_size, CustomSection, Encode, Section, SectionId}; /// An encoder for the custom `name` section. @@ -149,15 +151,19 @@ impl NameSection { self.bytes.push(id as u8); len.encode(&mut self.bytes); } + + /// View the encoded section as a CustomSection. + pub fn as_custom<'a>(&'a self) -> CustomSection<'a> { + CustomSection { + name: "name".into(), + data: Cow::Borrowed(&self.bytes), + } + } } impl Encode for NameSection { fn encode(&self, sink: &mut Vec) { - CustomSection { - name: "name", - data: &self.bytes, - } - .encode(sink); + self.as_custom().encode(sink); } } @@ -199,9 +205,14 @@ impl NameMap { self.count += 1; } - fn size(&self) -> usize { + pub(crate) fn size(&self) -> usize { encoding_size(self.count) + self.bytes.len() } + + /// Returns whether no names have been added to this map. + pub fn is_empty(&self) -> bool { + self.count == 0 + } } impl Encode for NameMap { diff --git a/crates/wasm-encoder/src/core/producers.rs b/crates/wasm-encoder/src/core/producers.rs new file mode 100644 index 0000000000..af03ecbb8e --- /dev/null +++ b/crates/wasm-encoder/src/core/producers.rs @@ -0,0 +1,180 @@ +use std::borrow::Cow; + +use crate::{CustomSection, Encode, Section, SectionId}; + +/// An encoder for the [producers custom +/// section](https://github.com/WebAssembly/tool-conventions/blob/main/ProducersSection.md). +/// +/// This section is a non-standard convention that is supported by many toolchains. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{ProducersSection, ProducersField, Module}; +/// +/// // Create a new producers section. +/// let mut field = ProducersField::new(); +/// field.value("clang", "14.0.4"); +/// field.value("rustc", "1.66.1 (90743e729 2023-01-10)"); +/// let mut producers = ProducersSection::new(); +/// producers.field("processed-by", &field); +/// +/// // Add the producers section to a new Wasm module and get the encoded bytes. +/// let mut module = Module::new(); +/// module.section(&producers); +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Debug)] +pub struct ProducersSection { + bytes: Vec, + num_fields: u32, +} + +impl ProducersSection { + /// Construct an empty encoder for the producers custom section. + pub fn new() -> Self { + Self::default() + } + + /// Add a field to the section. The spec recommends names for this section + /// are "language", "processed-by", and "sdk". Each field in section must + /// have a unique name. + pub fn field(&mut self, name: &str, values: &ProducersField) -> &mut Self { + name.encode(&mut self.bytes); + values.encode(&mut self.bytes); + self.num_fields += 1; + self + } +} + +impl Default for ProducersSection { + fn default() -> Self { + Self { + bytes: Vec::new(), + num_fields: 0, + } + } +} + +impl Encode for ProducersSection { + fn encode(&self, sink: &mut Vec) { + let mut data = Vec::new(); + self.num_fields.encode(&mut data); + data.extend(&self.bytes); + + CustomSection { + name: "producers".into(), + data: Cow::Borrowed(&data), + } + .encode(sink); + } +} + +impl Section for ProducersSection { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} + +/// The value of a field in the producers custom section +#[derive(Clone, Debug)] +pub struct ProducersField { + bytes: Vec, + num_values: u32, +} + +impl ProducersField { + /// Construct an empty encoder for a producers field value + pub fn new() -> Self { + ProducersField::default() + } + + /// Add a value to the field encoder. Each value in a field must have a + /// unique name. If there is no sensible value for `version`, use the + /// empty string. + pub fn value(&mut self, name: &str, version: &str) -> &mut Self { + name.encode(&mut self.bytes); + version.encode(&mut self.bytes); + self.num_values += 1; + self + } +} + +impl Default for ProducersField { + fn default() -> Self { + Self { + bytes: Vec::new(), + num_values: 0, + } + } +} + +impl Encode for ProducersField { + fn encode(&self, sink: &mut Vec) { + self.num_values.encode(sink); + sink.extend(&self.bytes); + } +} + +#[cfg(test)] +mod test { + #[test] + fn roundtrip_example() { + use crate::{Module, ProducersField, ProducersSection}; + use wasmparser::{Parser, Payload, ProducersSectionReader}; + + // Create a new producers section. + let mut field = ProducersField::new(); + field.value("clang", "14.0.4"); + field.value("rustc", "1.66.1"); + let mut producers = ProducersSection::new(); + producers.field("processed-by", &field); + + // Add the producers section to a new Wasm module and get the encoded bytes. + let mut module = Module::new(); + module.section(&producers); + let wasm_bytes = module.finish(); + + let mut parser = Parser::new(0).parse_all(&wasm_bytes); + let payload = parser + .next() + .expect("parser is not empty") + .expect("element is a payload"); + match payload { + Payload::Version { .. } => {} + _ => panic!(""), + } + let payload = parser + .next() + .expect("parser is not empty") + .expect("element is a payload"); + match payload { + Payload::CustomSection(c) => { + assert_eq!(c.name(), "producers"); + let mut section = ProducersSectionReader::new(c.data(), c.data_offset()) + .expect("readable as a producers section") + .into_iter(); + let field = section + .next() + .expect("section has an element") + .expect("element is a producers field"); + assert_eq!(field.name, "processed-by"); + let mut values = field.values.into_iter(); + let value = values + .next() + .expect("values has an element") + .expect("element is a producers field value"); + assert_eq!(value.name, "clang"); + assert_eq!(value.version, "14.0.4"); + + let value = values + .next() + .expect("values has another element") + .expect("element is a producers field value"); + assert_eq!(value.name, "rustc"); + assert_eq!(value.version, "1.66.1"); + } + _ => panic!("unexpected payload"), + } + } +} diff --git a/crates/wasm-encoder/src/core/tables.rs b/crates/wasm-encoder/src/core/tables.rs index 57a7628a5d..a41bd1988f 100644 --- a/crates/wasm-encoder/src/core/tables.rs +++ b/crates/wasm-encoder/src/core/tables.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, Encode, Section, SectionId, ValType}; +use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId}; /// An encoder for the table section. /// @@ -7,11 +7,11 @@ use crate::{encode_section, Encode, Section, SectionId, ValType}; /// # Example /// /// ``` -/// use wasm_encoder::{Module, TableSection, TableType, ValType}; +/// use wasm_encoder::{Module, TableSection, TableType, RefType}; /// /// let mut tables = TableSection::new(); /// tables.table(TableType { -/// element_type: ValType::FuncRef, +/// element_type: RefType::FUNCREF, /// minimum: 128, /// maximum: None, /// }); @@ -49,6 +49,18 @@ impl TableSection { self.num_added += 1; self } + + /// Define a table with an explicit initialization expression. + /// + /// Note that this is part of the function-references proposal. + pub fn table_with_init(&mut self, table_type: TableType, init: &ConstExpr) -> &mut Self { + self.bytes.push(0x40); + self.bytes.push(0x00); + table_type.encode(&mut self.bytes); + init.encode(&mut self.bytes); + self.num_added += 1; + self + } } impl Encode for TableSection { @@ -67,7 +79,7 @@ impl Section for TableSection { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct TableType { /// The table's element type. - pub element_type: ValType, + pub element_type: RefType, /// Minimum size, in elements, of this table pub minimum: u32, /// Maximum size, in elements, of this table @@ -90,3 +102,14 @@ impl Encode for TableType { } } } + +#[cfg(feature = "wasmparser")] +impl From for TableType { + fn from(table_ty: wasmparser::TableType) -> Self { + TableType { + element_type: table_ty.element_type.into(), + minimum: table_ty.initial, + maximum: table_ty.maximum, + } + } +} diff --git a/crates/wasm-encoder/src/core/tags.rs b/crates/wasm-encoder/src/core/tags.rs index 413055f2af..9b4c728a8c 100644 --- a/crates/wasm-encoder/src/core/tags.rs +++ b/crates/wasm-encoder/src/core/tags.rs @@ -68,6 +68,15 @@ pub enum TagKind { Exception = 0x0, } +#[cfg(feature = "wasmparser")] +impl From for TagKind { + fn from(kind: wasmparser::TagKind) -> Self { + match kind { + wasmparser::TagKind::Exception => TagKind::Exception, + } + } +} + /// A tag's type. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct TagType { @@ -83,3 +92,13 @@ impl Encode for TagType { self.func_type_idx.encode(sink); } } + +#[cfg(feature = "wasmparser")] +impl From for TagType { + fn from(tag_ty: wasmparser::TagType) -> Self { + TagType { + kind: tag_ty.kind.into(), + func_type_idx: tag_ty.func_type_idx, + } + } +} diff --git a/crates/wasm-encoder/src/core/types.rs b/crates/wasm-encoder/src/core/types.rs index d99e22ea94..a36a913a58 100644 --- a/crates/wasm-encoder/src/core/types.rs +++ b/crates/wasm-encoder/src/core/types.rs @@ -1,42 +1,377 @@ use crate::{encode_section, Encode, Section, SectionId}; +/// Represents a subtype of possible other types in a WebAssembly module. +#[derive(Debug, Clone)] +pub struct SubType { + /// Is the subtype final. + pub is_final: bool, + /// The list of supertype indexes. As of GC MVP, there can be at most one supertype. + pub supertype_idx: Option, + /// The structural type of the subtype. + pub structural_type: StructuralType, +} + +#[cfg(feature = "wasmparser")] +impl From for SubType { + fn from(sub_ty: wasmparser::SubType) -> Self { + SubType { + is_final: sub_ty.is_final, + supertype_idx: sub_ty.supertype_idx, + structural_type: sub_ty.structural_type.into(), + } + } +} + +/// Represents a structural type in a WebAssembly module. +#[derive(Debug, Clone)] +pub enum StructuralType { + /// The type is for a function. + Func(FuncType), + /// The type is for an array. + Array(ArrayType), + /// The type is for a struct. + Struct(StructType), +} + +impl Encode for StructuralType { + fn encode(&self, sink: &mut Vec) { + match self { + StructuralType::Func(ty) => TypeSection::encode_function( + sink, + ty.params().iter().copied(), + ty.results().iter().copied(), + ), + StructuralType::Array(ArrayType(ty)) => { + TypeSection::encode_array(sink, &ty.element_type, ty.mutable) + } + StructuralType::Struct(ty) => { + TypeSection::encode_struct(sink, ty.fields.iter().cloned()) + } + } + } +} + +#[cfg(feature = "wasmparser")] +impl From for StructuralType { + fn from(structural_ty: wasmparser::StructuralType) -> Self { + match structural_ty { + wasmparser::StructuralType::Func(f) => StructuralType::Func(f.into()), + wasmparser::StructuralType::Array(a) => StructuralType::Array(a.into()), + wasmparser::StructuralType::Struct(s) => StructuralType::Struct(s.into()), + } + } +} + +/// Represents a type of a function in a WebAssembly module. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct FuncType { + /// The combined parameters and result types. + params_results: Box<[ValType]>, + /// The number of parameter types. + len_params: usize, +} + +#[cfg(feature = "wasmparser")] +impl From for FuncType { + fn from(func_ty: wasmparser::FuncType) -> Self { + FuncType::new( + func_ty.params().iter().cloned().map(Into::into), + func_ty.results().iter().cloned().map(Into::into), + ) + } +} + +/// Represents a type of an array in a WebAssembly module. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct ArrayType(pub FieldType); + +#[cfg(feature = "wasmparser")] +impl From for ArrayType { + fn from(array_ty: wasmparser::ArrayType) -> Self { + ArrayType(array_ty.0.into()) + } +} + +/// Represents a type of a struct in a WebAssembly module. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct StructType { + /// Struct fields. + pub fields: Box<[FieldType]>, +} + +#[cfg(feature = "wasmparser")] +impl From for StructType { + fn from(struct_ty: wasmparser::StructType) -> Self { + StructType { + fields: struct_ty.fields.iter().cloned().map(Into::into).collect(), + } + } +} + +/// Field type in structural types (structs, arrays). +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub struct FieldType { + /// Storage type of the field. + pub element_type: StorageType, + /// Is the field mutable. + pub mutable: bool, +} + +#[cfg(feature = "wasmparser")] +impl From for FieldType { + fn from(field_ty: wasmparser::FieldType) -> Self { + FieldType { + element_type: field_ty.element_type.into(), + mutable: field_ty.mutable, + } + } +} + +/// Storage type for structural type fields. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum StorageType { + /// The `i8` type. + I8, + /// The `i16` type. + I16, + /// A value type. + Val(ValType), +} + +#[cfg(feature = "wasmparser")] +impl From for StorageType { + fn from(storage_ty: wasmparser::StorageType) -> Self { + match storage_ty { + wasmparser::StorageType::I8 => StorageType::I8, + wasmparser::StorageType::I16 => StorageType::I16, + wasmparser::StorageType::Val(v) => StorageType::Val(v.into()), + } + } +} + /// The type of a core WebAssembly value. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[repr(u8)] pub enum ValType { /// The `i32` type. - I32 = 0x7F, + I32, /// The `i64` type. - I64 = 0x7E, + I64, /// The `f32` type. - F32 = 0x7D, + F32, /// The `f64` type. - F64 = 0x7C, + F64, /// The `v128` type. /// /// Part of the SIMD proposal. - V128 = 0x7B, - /// The `funcref` type. + V128, + /// A reference type. /// - /// Part of the reference types proposal when used anywhere other than a - /// table's element type. - FuncRef = 0x70, - /// The `externref` type. - /// - /// Part of the reference types proposal. - ExternRef = 0x6F, + /// The `funcref` and `externref` type fall into this category and the full + /// generalization here is due to the implementation of the + /// function-references proposal. + Ref(RefType), +} + +#[cfg(feature = "wasmparser")] +impl From for ValType { + fn from(val_ty: wasmparser::ValType) -> Self { + match val_ty { + wasmparser::ValType::I32 => ValType::I32, + wasmparser::ValType::I64 => ValType::I64, + wasmparser::ValType::F32 => ValType::F32, + wasmparser::ValType::F64 => ValType::F64, + wasmparser::ValType::V128 => ValType::V128, + wasmparser::ValType::Ref(r) => ValType::Ref(r.into()), + } + } } -impl From for u8 { +impl FuncType { + /// Creates a new [`FuncType`] from the given `params` and `results`. + pub fn new(params: P, results: R) -> Self + where + P: IntoIterator, + R: IntoIterator, + { + let mut buffer = params.into_iter().collect::>(); + let len_params = buffer.len(); + buffer.extend(results); + Self { + params_results: buffer.into(), + len_params, + } + } + + /// Returns a shared slice to the parameter types of the [`FuncType`]. + #[inline] + pub fn params(&self) -> &[ValType] { + &self.params_results[..self.len_params] + } + + /// Returns a shared slice to the result types of the [`FuncType`]. #[inline] - fn from(t: ValType) -> u8 { - t as u8 + pub fn results(&self) -> &[ValType] { + &self.params_results[self.len_params..] + } +} + +impl ValType { + /// Alias for the `funcref` type in WebAssembly + pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF); + /// Alias for the `externref` type in WebAssembly + pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF); +} + +impl Encode for StorageType { + fn encode(&self, sink: &mut Vec) { + match self { + StorageType::I8 => sink.push(0x78), + StorageType::I16 => sink.push(0x77), + StorageType::Val(vt) => vt.encode(sink), + } } } impl Encode for ValType { fn encode(&self, sink: &mut Vec) { - sink.push(*self as u8); + match self { + ValType::I32 => sink.push(0x7F), + ValType::I64 => sink.push(0x7E), + ValType::F32 => sink.push(0x7D), + ValType::F64 => sink.push(0x7C), + ValType::V128 => sink.push(0x7B), + ValType::Ref(rt) => rt.encode(sink), + } + } +} + +/// A reference type. +/// +/// This is largely part of the function references proposal for WebAssembly but +/// additionally is used by the `funcref` and `externref` types. The full +/// generality of this type is only exercised with function-references. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[allow(missing_docs)] +pub struct RefType { + pub nullable: bool, + pub heap_type: HeapType, +} + +impl RefType { + /// Alias for the `funcref` type in WebAssembly + pub const FUNCREF: RefType = RefType { + nullable: true, + heap_type: HeapType::Func, + }; + + /// Alias for the `externref` type in WebAssembly + pub const EXTERNREF: RefType = RefType { + nullable: true, + heap_type: HeapType::Extern, + }; +} + +impl Encode for RefType { + fn encode(&self, sink: &mut Vec) { + if self.nullable { + // Favor the original encodings of `funcref` and `externref` where + // possible + match self.heap_type { + HeapType::Func => return sink.push(0x70), + HeapType::Extern => return sink.push(0x6f), + _ => {} + } + } + + if self.nullable { + sink.push(0x63); + } else { + sink.push(0x64); + } + self.heap_type.encode(sink); + } +} + +#[cfg(feature = "wasmparser")] +impl From for RefType { + fn from(ref_type: wasmparser::RefType) -> Self { + RefType { + nullable: ref_type.is_nullable(), + heap_type: ref_type.heap_type().into(), + } + } +} + +impl From for ValType { + fn from(ty: RefType) -> ValType { + ValType::Ref(ty) + } +} + +/// Part of the function references proposal. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum HeapType { + /// Untyped (any) function. + Func, + /// External heap type. + Extern, + /// The `any` heap type. The common supertype (a.k.a. top) of all internal types. + Any, + /// The `none` heap type. The common subtype (a.k.a. bottom) of all internal types. + None, + /// The `noextern` heap type. The common subtype (a.k.a. bottom) of all external types. + NoExtern, + /// The `nofunc` heap type. The common subtype (a.k.a. bottom) of all function types. + NoFunc, + /// The `eq` heap type. The common supertype of all referenceable types on which comparison + /// (ref.eq) is allowed. + Eq, + /// The `struct` heap type. The common supertype of all struct types. + Struct, + /// The `array` heap type. The common supertype of all array types. + Array, + /// The i31 heap type. + I31, + /// User defined type at the given index. + Indexed(u32), +} + +impl Encode for HeapType { + fn encode(&self, sink: &mut Vec) { + match self { + HeapType::Func => sink.push(0x70), + HeapType::Extern => sink.push(0x6F), + HeapType::Any => sink.push(0x6E), + HeapType::None => sink.push(0x71), + HeapType::NoExtern => sink.push(0x72), + HeapType::NoFunc => sink.push(0x73), + HeapType::Eq => sink.push(0x6D), + HeapType::Struct => sink.push(0x6B), + HeapType::Array => sink.push(0x6A), + HeapType::I31 => sink.push(0x6C), + // Note that this is encoded as a signed type rather than unsigned + // as it's decoded as an s33 + HeapType::Indexed(i) => i64::from(*i).encode(sink), + } + } +} + +#[cfg(feature = "wasmparser")] +impl From for HeapType { + fn from(heap_type: wasmparser::HeapType) -> Self { + match heap_type { + wasmparser::HeapType::Indexed(i) => HeapType::Indexed(i), + wasmparser::HeapType::Func => HeapType::Func, + wasmparser::HeapType::Extern => HeapType::Extern, + wasmparser::HeapType::Any => HeapType::Any, + wasmparser::HeapType::None => HeapType::None, + wasmparser::HeapType::NoExtern => HeapType::NoExtern, + wasmparser::HeapType::NoFunc => HeapType::NoFunc, + wasmparser::HeapType::Eq => HeapType::Eq, + wasmparser::HeapType::Struct => HeapType::Struct, + wasmparser::HeapType::Array => HeapType::Array, + wasmparser::HeapType::I31 => HeapType::I31, + } } } @@ -80,6 +415,18 @@ impl TypeSection { /// Define a function type in this type section. pub fn function(&mut self, params: P, results: R) -> &mut Self + where + P: IntoIterator, + P::IntoIter: ExactSizeIterator, + R: IntoIterator, + R::IntoIter: ExactSizeIterator, + { + Self::encode_function(&mut self.bytes, params, results); + self.num_added += 1; + self + } + + fn encode_function(sink: &mut Vec, params: P, results: R) where P: IntoIterator, P::IntoIter: ExactSizeIterator, @@ -89,11 +436,64 @@ impl TypeSection { let params = params.into_iter(); let results = results.into_iter(); - self.bytes.push(0x60); - params.len().encode(&mut self.bytes); - self.bytes.extend(params.map(u8::from)); - results.len().encode(&mut self.bytes); - self.bytes.extend(results.map(u8::from)); + sink.push(0x60); + params.len().encode(sink); + params.for_each(|p| p.encode(sink)); + results.len().encode(sink); + results.for_each(|p| p.encode(sink)); + } + + /// Define an array type in this type section. + pub fn array(&mut self, ty: &StorageType, mutable: bool) -> &mut Self { + Self::encode_array(&mut self.bytes, ty, mutable); + self.num_added += 1; + self + } + + fn encode_array(sink: &mut Vec, ty: &StorageType, mutable: bool) { + sink.push(0x5e); + Self::encode_field(sink, ty, mutable); + } + + fn encode_field(sink: &mut Vec, ty: &StorageType, mutable: bool) { + ty.encode(sink); + sink.push(mutable as u8); + } + + /// Define a struct type in this type section. + pub fn struct_(&mut self, fields: F) -> &mut Self + where + F: IntoIterator, + F::IntoIter: ExactSizeIterator, + { + Self::encode_struct(&mut self.bytes, fields); + self.num_added += 1; + self + } + + fn encode_struct(sink: &mut Vec, fields: F) + where + F: IntoIterator, + F::IntoIter: ExactSizeIterator, + { + let fields = fields.into_iter(); + sink.push(0x5f); + fields.len().encode(sink); + for f in fields { + Self::encode_field(sink, &f.element_type, f.mutable); + } + } + + /// Define an explicit subtype in this type section. + pub fn subtype(&mut self, ty: &SubType) -> &mut Self { + // We only need to emit a prefix byte before the actual structural type + // when either the type is not final or it has a declared super type. + if ty.supertype_idx.is_some() || !ty.is_final { + self.bytes.push(if ty.is_final { 0x4f } else { 0x50 }); + ty.supertype_idx.encode(&mut self.bytes); + } + + ty.structural_type.encode(&mut self.bytes); self.num_added += 1; self } @@ -110,3 +510,32 @@ impl Section for TypeSection { SectionId::Type.into() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::Module; + + #[test] + fn func_types_dont_require_wasm_gc() { + let mut types = TypeSection::new(); + types.subtype(&SubType { + is_final: true, + supertype_idx: None, + structural_type: StructuralType::Func(FuncType::new([], [])), + }); + + let mut module = Module::new(); + module.section(&types); + let wasm_bytes = module.finish(); + + let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { + gc: false, + ..Default::default() + }); + + validator.validate_all(&wasm_bytes).expect( + "Encoding pre Wasm GC type should not accidentally use Wasm GC specific encoding", + ); + } +} diff --git a/crates/wasm-encoder/src/lib.rs b/crates/wasm-encoder/src/lib.rs index c84e20f81d..930c63ec9d 100644 --- a/crates/wasm-encoder/src/lib.rs +++ b/crates/wasm-encoder/src/lib.rs @@ -144,6 +144,33 @@ impl Encode for i64 { } } +impl Encode for f32 { + fn encode(&self, sink: &mut Vec) { + let bits = self.to_bits(); + sink.extend(bits.to_le_bytes()) + } +} + +impl Encode for f64 { + fn encode(&self, sink: &mut Vec) { + let bits = self.to_bits(); + sink.extend(bits.to_le_bytes()) + } +} + +fn encode_vec(elements: V, sink: &mut Vec) +where + T: Encode, + V: IntoIterator, + V::IntoIter: ExactSizeIterator, +{ + let elements = elements.into_iter(); + u32::try_from(elements.len()).unwrap().encode(sink); + for x in elements { + x.encode(sink); + } +} + impl Encode for Option where T: Encode, @@ -183,6 +210,6 @@ mod test { #[test] fn it_encodes_an_empty_component() { let bytes = Component::new().finish(); - assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0a, 0x00, 0x01, 0x00]); + assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0d, 0x00, 0x01, 0x00]); } } diff --git a/crates/wasm-metadata/Cargo.toml b/crates/wasm-metadata/Cargo.toml new file mode 100644 index 0000000000..9639334d38 --- /dev/null +++ b/crates/wasm-metadata/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "wasm-metadata" +version = "0.10.9" +edition.workspace = true +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-metadata" +description = "Read and manipulate WebAssembly metadata" + +[dependencies] +clap = { workspace = true, optional = true } +anyhow = { workspace = true } +wasmparser = { workspace = true } +wasm-encoder = { workspace = true } +indexmap = { workspace = true, features = ["serde"] } +serde = { workspace = true } +serde_derive = { workspace = true } +serde_json = { version = "1" } +spdx = "0.10.1" + +[dev-dependencies] +wat = { workspace = true } diff --git a/crates/wasm-metadata/src/lib.rs b/crates/wasm-metadata/src/lib.rs new file mode 100644 index 0000000000..53f8ec0801 --- /dev/null +++ b/crates/wasm-metadata/src/lib.rs @@ -0,0 +1,1496 @@ +use anyhow::Result; +use indexmap::{map::Entry, IndexMap}; +use serde_derive::{Deserialize, Serialize}; +use spdx::Expression; +use std::borrow::Cow; +use std::fmt; +use std::fmt::Display; +use std::mem; +use std::ops::Range; +use wasm_encoder::{ComponentSection as _, ComponentSectionId, Encode, Section}; +use wasmparser::{ + ComponentNameSectionReader, NameSectionReader, Parser, Payload::*, ProducersSectionReader, +}; + +/// A representation of a WebAssembly producers section. +/// +/// Spec: +#[derive(Debug, Serialize)] +pub struct Producers( + #[serde(serialize_with = "indexmap::map::serde_seq::serialize")] + IndexMap>, +); + +impl Default for Producers { + fn default() -> Self { + Self::empty() + } +} + +impl Producers { + /// Creates an empty producers section + pub fn empty() -> Self { + Producers(IndexMap::new()) + } + + /// Indicates if section is empty + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Read the producers section from a Wasm binary. Supports both core + /// Modules and Components. In the component case, only returns the + /// producers section in the outer component, ignoring all interior + /// components and modules. + pub fn from_wasm(bytes: &[u8]) -> Result> { + let mut depth = 0; + for payload in Parser::new(0).parse_all(bytes) { + let payload = payload?; + use wasmparser::Payload::*; + match payload { + ModuleSection { .. } | ComponentSection { .. } => depth += 1, + End { .. } => depth -= 1, + CustomSection(c) if c.name() == "producers" && depth == 0 => { + let producers = Self::from_bytes(c.data(), c.data_offset())?; + return Ok(Some(producers)); + } + _ => {} + } + } + Ok(None) + } + /// Read the producers section from a Wasm binary. + pub fn from_bytes(bytes: &[u8], offset: usize) -> Result { + let section = ProducersSectionReader::new(bytes, offset)?; + let mut fields = IndexMap::new(); + for field in section.into_iter() { + let field = field?; + let mut values = IndexMap::new(); + for value in field.values.into_iter() { + let value = value?; + values.insert(value.name.to_owned(), value.version.to_owned()); + } + fields.insert(field.name.to_owned(), values); + } + Ok(Producers(fields)) + } + /// Add a name & version value to a field. + /// + /// The spec says expected field names are "language", "processed-by", and "sdk". + /// The version value should be left blank for languages. + pub fn add(&mut self, field: &str, name: &str, version: &str) { + match self.0.entry(field.to_string()) { + Entry::Occupied(e) => { + e.into_mut().insert(name.to_owned(), version.to_owned()); + } + Entry::Vacant(e) => { + let mut m = IndexMap::new(); + m.insert(name.to_owned(), version.to_owned()); + e.insert(m); + } + } + } + + /// Add all values found in another `Producers` section. Values in `other` take + /// precedence. + pub fn merge(&mut self, other: &Self) { + for (field, values) in other.iter() { + for (name, version) in values.iter() { + self.add(field, name, version); + } + } + } + + /// Get the contents of a field + pub fn get<'a>(&'a self, field: &str) -> Option> { + self.0.get(&field.to_owned()).map(ProducersField) + } + + /// Iterate through all fields + pub fn iter<'a>(&'a self) -> impl Iterator)> + 'a { + self.0 + .iter() + .map(|(name, field)| (name, ProducersField(field))) + } + + /// Construct the fields specified by [`AddMetadata`] + fn from_meta(add: &AddMetadata) -> Self { + let mut s = Self::empty(); + for lang in add.language.iter() { + s.add("language", &lang, ""); + } + for (name, version) in add.processed_by.iter() { + s.add("processed-by", &name, &version); + } + for (name, version) in add.sdk.iter() { + s.add("sdk", &name, &version); + } + s + } + + /// Serialize into [`wasm_encoder::ProducersSection`]. + fn section(&self) -> wasm_encoder::ProducersSection { + let mut section = wasm_encoder::ProducersSection::new(); + for (fieldname, fieldvalues) in self.0.iter() { + let mut field = wasm_encoder::ProducersField::new(); + for (name, version) in fieldvalues { + field.value(&name, &version); + } + section.field(&fieldname, &field); + } + section + } + + /// Serialize into the raw bytes of a wasm custom section. + pub fn raw_custom_section(&self) -> Vec { + let mut ret = Vec::new(); + self.section().encode(&mut ret); + ret + } + + /// Merge into an existing wasm module. Rewrites the module with this producers section + /// merged into its existing one, or adds this producers section if none is present. + pub fn add_to_wasm(&self, input: &[u8]) -> Result> { + rewrite_wasm(&None, self, None, input) + } + + fn display(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { + let indent = std::iter::repeat(" ").take(indent).collect::(); + for (fieldname, fieldvalues) in self.0.iter() { + writeln!(f, "{indent}{fieldname}:")?; + for (name, version) in fieldvalues { + if version.is_empty() { + writeln!(f, "{indent} {name}")?; + } else { + writeln!(f, "{indent} {name}: {version}")?; + } + } + } + Ok(()) + } +} + +impl fmt::Display for Producers { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.display(f, 0) + } +} + +/// Contents of a producers field +pub struct ProducersField<'a>(&'a IndexMap); + +impl<'a> ProducersField<'a> { + /// Get the version associated with a name in the field + pub fn get(&self, name: &str) -> Option<&'a String> { + self.0.get(&name.to_owned()) + } + /// Iterate through all name-version pairs in the field + pub fn iter(&self) -> impl Iterator + 'a { + self.0.iter() + } +} + +/// Add metadata (module name, producers) to a WebAssembly file. +/// +/// Supports both core WebAssembly modules and components. In components, +/// metadata will be added to the outermost component. +#[cfg_attr(feature = "clap", derive(clap::Parser))] +#[derive(Debug, Clone, Default)] +pub struct AddMetadata { + /// Add a module or component name to the names section + #[cfg_attr(feature = "clap", clap(long, value_name = "NAME"))] + pub name: Option, + + /// Add a programming language to the producers section + #[cfg_attr(feature = "clap", clap(long, value_name = "NAME"))] + pub language: Vec, + + /// Add a tool and its version to the producers section + #[cfg_attr(feature = "clap", clap(long = "processed-by", value_parser = parse_key_value, value_name="NAME=VERSION"))] + pub processed_by: Vec<(String, String)>, + + /// Add an SDK and its version to the producers section + #[cfg_attr(feature="clap", clap(long, value_parser = parse_key_value, value_name="NAME=VERSION"))] + pub sdk: Vec<(String, String)>, + + /// Add an registry metadata to the registry-metadata section + #[cfg_attr(feature="clap", clap(long, value_parser = parse_registry_metadata_value, value_name="PATH"))] + pub registry_metadata: Option, +} + +#[cfg(feature = "clap")] +fn parse_key_value(s: &str) -> Result<(String, String)> { + s.split_once('=') + .map(|(k, v)| (k.to_owned(), v.to_owned())) + .ok_or_else(|| anyhow::anyhow!("expected KEY=VALUE")) +} + +#[cfg(feature = "clap")] +fn parse_registry_metadata_value(s: &str) -> Result { + let contents = std::fs::read(s)?; + + let registry_metadata = RegistryMetadata::from_bytes(&contents, 0)?; + + Ok(registry_metadata) +} + +impl AddMetadata { + /// Process a WebAssembly binary. Supports both core WebAssembly modules, and WebAssembly + /// components. The module and component will have, at very least, an empty name and producers + /// section created. + pub fn to_wasm(&self, input: &[u8]) -> Result> { + rewrite_wasm( + &self.name, + &Producers::from_meta(self), + self.registry_metadata.as_ref(), + input, + ) + } +} + +fn rewrite_wasm( + add_name: &Option, + add_producers: &Producers, + add_registry_metadata: Option<&RegistryMetadata>, + input: &[u8], +) -> Result> { + let mut producers_found = false; + let mut names_found = false; + let mut stack = Vec::new(); + let mut output = Vec::new(); + for payload in Parser::new(0).parse_all(&input) { + let payload = payload?; + + // Track nesting depth, so that we don't mess with inner producer sections: + match payload { + Version { encoding, .. } => { + output.extend_from_slice(match encoding { + wasmparser::Encoding::Component => &wasm_encoder::Component::HEADER, + wasmparser::Encoding::Module => &wasm_encoder::Module::HEADER, + }); + } + ModuleSection { .. } | ComponentSection { .. } => { + stack.push(mem::take(&mut output)); + continue; + } + End { .. } => { + let mut parent = match stack.pop() { + Some(c) => c, + None => break, + }; + if output.starts_with(&wasm_encoder::Component::HEADER) { + parent.push(ComponentSectionId::Component as u8); + output.encode(&mut parent); + } else { + parent.push(ComponentSectionId::CoreModule as u8); + output.encode(&mut parent); + } + output = parent; + } + _ => {} + } + + // Process the wasm sections: + match payload { + // Only rewrite the outermost producers section: + CustomSection(c) if c.name() == "producers" && stack.len() == 0 => { + producers_found = true; + let mut producers = Producers::from_bytes(c.data(), c.data_offset())?; + // Add to the section according to the command line flags: + producers.merge(&add_producers); + // Encode into output: + producers.section().append_to(&mut output); + } + + CustomSection(c) if c.name() == "name" && stack.len() == 0 => { + names_found = true; + let mut names = ModuleNames::from_bytes(c.data(), c.data_offset())?; + names.merge(&ModuleNames::from_name(add_name)); + + names.section()?.as_custom().append_to(&mut output); + } + + CustomSection(c) if c.name() == "component-name" && stack.len() == 0 => { + names_found = true; + let mut names = ComponentNames::from_bytes(c.data(), c.data_offset())?; + names.merge(&ComponentNames::from_name(add_name)); + names.section()?.as_custom().append_to(&mut output); + } + + CustomSection(c) if c.name() == "registry-metadata" && stack.len() == 0 => { + // Pass section through if a new registry metadata isn't provided, otherwise ignore and overwrite with new + if add_registry_metadata.is_none() { + let registry: RegistryMetadata = RegistryMetadata::from_bytes(&c.data(), 0)?; + + let registry_metadata = wasm_encoder::CustomSection { + name: Cow::Borrowed("registry-metadata"), + data: Cow::Owned(serde_json::to_vec(®istry)?), + }; + registry_metadata.append_to(&mut output); + } + } + + // All other sections get passed through unmodified: + _ => { + if let Some((id, range)) = payload.as_section() { + wasm_encoder::RawSection { + id, + data: &input[range], + } + .append_to(&mut output); + } + } + } + } + if !names_found && add_name.is_some() { + if output.starts_with(&wasm_encoder::Component::HEADER) { + let names = ComponentNames::from_name(add_name); + names.section()?.append_to_component(&mut output); + } else { + let names = ModuleNames::from_name(add_name); + names.section()?.append_to(&mut output) + } + } + if !producers_found && !add_producers.is_empty() { + let mut producers = Producers::empty(); + // Add to the section according to the command line flags: + producers.merge(add_producers); + // Encode into output: + producers.section().append_to(&mut output); + } + if add_registry_metadata.is_some() { + let registry_metadata = wasm_encoder::CustomSection { + name: Cow::Borrowed("registry-metadata"), + data: Cow::Owned(serde_json::to_vec(&add_registry_metadata)?), + }; + registry_metadata.append_to(&mut output); + } + Ok(output) +} + +/// A tree of the metadata found in a WebAssembly binary. +#[derive(Debug, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum Metadata { + /// Metadata found inside a WebAssembly component. + Component { + /// The component name, if any. Found in the component-name section. + name: Option, + /// The component's producers section, if any. + producers: Option, + /// The component's registry metadata section, if any. + registry_metadata: Option, + /// All child modules and components inside the component. + children: Vec>, + /// Byte range of the module in the parent binary + range: Range, + }, + /// Metadata found inside a WebAssembly module. + Module { + /// The module name, if any. Found in the name section. + name: Option, + /// The module's producers section, if any. + producers: Option, + /// The module's registry metadata section, if any. + registry_metadata: Option, + /// Byte range of the module in the parent binary + range: Range, + }, +} + +impl Metadata { + /// Parse metadata from a WebAssembly binary. Supports both core WebAssembly modules, and + /// WebAssembly components. + pub fn from_binary(input: &[u8]) -> Result { + let mut metadata = Vec::new(); + + for payload in Parser::new(0).parse_all(&input) { + match payload? { + Version { encoding, .. } => { + if metadata.is_empty() { + match encoding { + wasmparser::Encoding::Module => { + metadata.push(Metadata::empty_module(0..input.len())) + } + wasmparser::Encoding::Component => { + metadata.push(Metadata::empty_component(0..input.len())) + } + } + } + } + ModuleSection { range, .. } => metadata.push(Metadata::empty_module(range)), + ComponentSection { range, .. } => metadata.push(Metadata::empty_component(range)), + End { .. } => { + let finished = metadata.pop().expect("non-empty metadata stack"); + if metadata.is_empty() { + return Ok(finished); + } else { + metadata.last_mut().unwrap().push_child(finished); + } + } + CustomSection(c) if c.name() == "name" => { + let names = ModuleNames::from_bytes(c.data(), c.data_offset())?; + if let Some(name) = names.get_name() { + metadata + .last_mut() + .expect("non-empty metadata stack") + .set_name(&name); + } + } + CustomSection(c) if c.name() == "component-name" => { + let names = ComponentNames::from_bytes(c.data(), c.data_offset())?; + if let Some(name) = names.get_name() { + metadata + .last_mut() + .expect("non-empty metadata stack") + .set_name(name); + } + } + CustomSection(c) if c.name() == "producers" => { + let producers = Producers::from_bytes(c.data(), c.data_offset())?; + metadata + .last_mut() + .expect("non-empty metadata stack") + .set_producers(producers); + } + CustomSection(c) if c.name() == "registry-metadata" => { + let registry: RegistryMetadata = RegistryMetadata::from_bytes(&c.data(), 0)?; + metadata + .last_mut() + .expect("non-empty metadata stack") + .set_registry_metadata(registry); + } + + _ => {} + } + } + Err(anyhow::anyhow!( + "malformed wasm binary, should have reached end" + )) + } + + fn empty_component(range: Range) -> Self { + Metadata::Component { + name: None, + producers: None, + registry_metadata: None, + children: Vec::new(), + range, + } + } + + fn empty_module(range: Range) -> Self { + Metadata::Module { + name: None, + producers: None, + registry_metadata: None, + range, + } + } + fn set_name(&mut self, n: &str) { + match self { + Metadata::Module { name, .. } => *name = Some(n.to_owned()), + Metadata::Component { name, .. } => *name = Some(n.to_owned()), + } + } + fn set_producers(&mut self, p: Producers) { + match self { + Metadata::Module { producers, .. } => *producers = Some(p), + Metadata::Component { producers, .. } => *producers = Some(p), + } + } + fn set_registry_metadata(&mut self, r: RegistryMetadata) { + match self { + Metadata::Module { + registry_metadata, .. + } => *registry_metadata = Some(r), + Metadata::Component { + registry_metadata, .. + } => *registry_metadata = Some(r), + } + } + fn push_child(&mut self, child: Self) { + match self { + Metadata::Module { .. } => panic!("module shouldnt have children"), + Metadata::Component { children, .. } => children.push(Box::new(child)), + } + } + + fn display(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { + let spaces = std::iter::repeat(" ").take(indent).collect::(); + match self { + Metadata::Module { + name, + producers, + registry_metadata, + .. + } => { + if let Some(name) = name { + writeln!(f, "{spaces}module {name}:")?; + } else { + writeln!(f, "{spaces}module:")?; + } + if let Some(producers) = producers { + producers.display(f, indent + 4)?; + } + if let Some(registry_metadata) = registry_metadata { + registry_metadata.display(f, indent + 4)?; + } + Ok(()) + } + Metadata::Component { + name, + producers, + registry_metadata, + children, + .. + } => { + if let Some(name) = name { + writeln!(f, "{spaces}component {name}:")?; + } else { + writeln!(f, "{spaces}component:")?; + } + if let Some(producers) = producers { + producers.display(f, indent + 4)?; + } + if let Some(registry_metadata) = registry_metadata { + registry_metadata.display(f, indent + 4)?; + } + for c in children { + c.display(f, indent + 4)?; + } + Ok(()) + } + } + } +} + +impl fmt::Display for Metadata { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.display(f, 0) + } +} + +/// Helper for rewriting a module's name section with a new module name. +pub struct ModuleNames<'a> { + module_name: Option, + names: Vec>, +} + +impl<'a> ModuleNames<'a> { + /// Create an empty name section. + pub fn empty() -> Self { + ModuleNames { + module_name: None, + names: Vec::new(), + } + } + /// Read a name section from a WebAssembly binary. Records the module name, and all other + /// contents of name section, for later serialization. + pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result> { + let section = NameSectionReader::new(bytes, offset); + let mut s = Self::empty(); + for name in section.into_iter() { + let name = name?; + match name { + wasmparser::Name::Module { name, .. } => s.module_name = Some(name.to_owned()), + _ => s.names.push(name), + } + } + Ok(s) + } + /// Update module section according to [`AddMetadata`] + fn from_name(name: &Option) -> Self { + let mut s = Self::empty(); + s.module_name = name.clone(); + s + } + + /// Merge with another section + fn merge(&mut self, other: &Self) { + if other.module_name.is_some() { + self.module_name = other.module_name.clone(); + } + self.names.extend_from_slice(&other.names); + } + + /// Set module name + pub fn set_name(&mut self, name: &str) { + self.module_name = Some(name.to_owned()) + } + /// Get module name + pub fn get_name(&self) -> Option<&String> { + self.module_name.as_ref() + } + /// Serialize into [`wasm_encoder::NameSection`]. + fn section(&self) -> Result { + let mut section = wasm_encoder::NameSection::new(); + if let Some(module_name) = &self.module_name { + section.module(&module_name); + } + for n in self.names.iter() { + match n { + wasmparser::Name::Module { .. } => unreachable!(), + wasmparser::Name::Function(m) => section.functions(&name_map(&m)?), + wasmparser::Name::Local(m) => section.locals(&indirect_name_map(&m)?), + wasmparser::Name::Label(m) => section.labels(&indirect_name_map(&m)?), + wasmparser::Name::Type(m) => section.types(&name_map(&m)?), + wasmparser::Name::Table(m) => section.tables(&name_map(&m)?), + wasmparser::Name::Memory(m) => section.memories(&name_map(&m)?), + wasmparser::Name::Global(m) => section.globals(&name_map(&m)?), + wasmparser::Name::Element(m) => section.elements(&name_map(&m)?), + wasmparser::Name::Data(m) => section.types(&name_map(&m)?), + wasmparser::Name::Unknown { .. } => {} // wasm-encoder doesn't support it + } + } + Ok(section) + } + + /// Serialize into the raw bytes of a wasm custom section. + pub fn raw_custom_section(&self) -> Result> { + let mut ret = Vec::new(); + self.section()?.encode(&mut ret); + Ok(ret) + } +} + +/// Helper for rewriting a component's component-name section with a new component name. +pub struct ComponentNames<'a> { + component_name: Option, + names: Vec>, +} + +impl<'a> ComponentNames<'a> { + /// Create an empty component-name section. + pub fn empty() -> Self { + ComponentNames { + component_name: None, + names: Vec::new(), + } + } + /// Read a component-name section from a WebAssembly binary. Records the component name, as + /// well as all other component name fields for later serialization. + pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result> { + let section = ComponentNameSectionReader::new(bytes, offset); + let mut s = Self::empty(); + for name in section.into_iter() { + let name = name?; + match name { + wasmparser::ComponentName::Component { name, .. } => { + s.component_name = Some(name.to_owned()) + } + _ => s.names.push(name), + } + } + Ok(s) + } + /// Set component name according to [`AddMetadata`] + fn from_name(name: &Option) -> Self { + let mut s = Self::empty(); + s.component_name = name.clone(); + s + } + + /// Merge with another section + fn merge(&mut self, other: &Self) { + if other.component_name.is_some() { + self.component_name = other.component_name.clone(); + } + self.names.extend_from_slice(&other.names); + } + + /// Set component name + pub fn set_name(&mut self, name: &str) { + self.component_name = Some(name.to_owned()) + } + /// Get component name + pub fn get_name(&self) -> Option<&String> { + self.component_name.as_ref() + } + /// Serialize into [`wasm_encoder::ComponentNameSection`] + fn section(&self) -> Result { + let mut section = wasm_encoder::ComponentNameSection::new(); + if let Some(component_name) = &self.component_name { + section.component(&component_name); + } + for n in self.names.iter() { + match n { + wasmparser::ComponentName::Component { .. } => unreachable!(), + wasmparser::ComponentName::CoreFuncs(m) => section.core_funcs(&name_map(&m)?), + wasmparser::ComponentName::CoreGlobals(m) => section.core_globals(&name_map(&m)?), + wasmparser::ComponentName::CoreMemories(m) => section.core_memories(&name_map(&m)?), + wasmparser::ComponentName::CoreTables(m) => section.core_tables(&name_map(&m)?), + wasmparser::ComponentName::CoreModules(m) => section.core_modules(&name_map(&m)?), + wasmparser::ComponentName::CoreInstances(m) => { + section.core_instances(&name_map(&m)?) + } + wasmparser::ComponentName::CoreTypes(m) => section.core_types(&name_map(&m)?), + wasmparser::ComponentName::Types(m) => section.types(&name_map(&m)?), + wasmparser::ComponentName::Instances(m) => section.instances(&name_map(&m)?), + wasmparser::ComponentName::Components(m) => section.components(&name_map(&m)?), + wasmparser::ComponentName::Funcs(m) => section.funcs(&name_map(&m)?), + wasmparser::ComponentName::Values(m) => section.values(&name_map(&m)?), + wasmparser::ComponentName::Unknown { .. } => {} // wasm-encoder doesn't support it + } + } + Ok(section) + } + + /// Serialize into the raw bytes of a wasm custom section. + pub fn raw_custom_section(&self) -> Result> { + let mut ret = Vec::new(); + self.section()?.encode(&mut ret); + Ok(ret) + } +} + +fn name_map(map: &wasmparser::NameMap<'_>) -> Result { + let mut out = wasm_encoder::NameMap::new(); + for m in map.clone().into_iter() { + let m = m?; + out.append(m.index, m.name); + } + Ok(out) +} + +fn indirect_name_map( + map: &wasmparser::IndirectNameMap<'_>, +) -> Result { + let mut out = wasm_encoder::IndirectNameMap::new(); + for m in map.clone().into_iter() { + let m = m?; + out.append(m.index, &name_map(&m.names)?); + } + Ok(out) +} + +#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)] +pub struct RegistryMetadata { + /// List of authors who has created this package. + #[serde(skip_serializing_if = "Option::is_none")] + authors: Option>, + + /// Package description in markdown format. + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + + /// SPDX License Expression + /// + /// SPDX License List: + #[serde(skip_serializing_if = "Option::is_none")] + license: Option, + + /// A list of custom licenses that should be referenced to from the license expression. + /// + #[serde(skip_serializing_if = "Option::is_none")] + custom_licenses: Option>, + + /// A list of links that can contain predefined link types or custom links for use with tooling or registries. + #[serde(skip_serializing_if = "Option::is_none")] + links: Option>, + + /// A list of categories that a package should be listed under when uploaded to a registry. + #[serde(skip_serializing_if = "Option::is_none")] + categories: Option>, +} + +const LICENSE_REF: &str = "LicenseRef-"; + +impl RegistryMetadata { + /// Merge into an existing wasm module. Rewrites the module with this registry-metadata section + /// overwriting its existing one, or adds this registry-metadata section if none is present. + pub fn add_to_wasm(&self, input: &[u8]) -> Result> { + rewrite_wasm(&None, &Producers::empty(), Some(&self), input) + } + + pub fn from_wasm(bytes: &[u8]) -> Result> { + let mut depth = 0; + for payload in Parser::new(0).parse_all(bytes) { + let payload = payload?; + use wasmparser::Payload::*; + match payload { + ModuleSection { .. } | ComponentSection { .. } => depth += 1, + End { .. } => depth -= 1, + CustomSection(c) if c.name() == "registry-metadata" && depth == 0 => { + let registry = RegistryMetadata::from_bytes(&c.data(), 0)?; + return Ok(Some(registry)); + } + _ => {} + } + } + Ok(None) + } + + /// Gets the registry-matadata from a slice of bytes + pub fn from_bytes(bytes: &[u8], offset: usize) -> Result { + let registry: RegistryMetadata = serde_json::from_slice(&bytes[offset..])?; + return Ok(registry); + } + + pub fn validate(&self) -> Result<()> { + fn validate_expression(expression: &str) -> Result> { + let expression = Expression::parse(expression)?; + + let mut licenses = Vec::new(); + + for license in expression.iter() { + match license { + spdx::expression::ExprNode::Op(_) => continue, + spdx::expression::ExprNode::Req(req) => { + if let spdx::LicenseItem::Spdx { .. } = req.req.license { + // Continue if it's a license that exists on the Spdx license list + continue; + } + + let license_id = req.req.to_string(); + + if license_id.starts_with(LICENSE_REF) { + // Strip "LicenseRef-", convert to lowercase and then append + licenses.push(license_id[LICENSE_REF.len()..].to_lowercase()); + } + } + } + } + + Ok(licenses) + } + + match (&self.license, &self.custom_licenses) { + (None, Some(custom_licenses)) => { + let ids = custom_licenses + .iter() + .map(|license| license.id.clone()) + .collect::>() + .join(", "); + + return Err(anyhow::anyhow!( + "{ids} are defined but nevered referenced in license expression" + )); + } + (Some(license), Some(custom_licenses)) => { + let licenses = validate_expression(license.as_str())?; + + if !licenses.is_empty() { + for license in &licenses { + let mut match_found = false; + for custom_license in custom_licenses { + // Ignore license id casing + if custom_license.id.to_lowercase() == *license { + match_found = true; + } + } + + if !match_found { + return Err(anyhow::anyhow!( + "No matching reference for license '{license}' was defined" + )); + } + } + } + } + (Some(license), None) => { + let licenses = validate_expression(license.as_str())?; + + if !licenses.is_empty() { + return Err(anyhow::anyhow!( + "Reference to custom license exists but no custom license was given" + )); + } + } + (None, None) => {} + } + + Ok(()) + } + + /// Get authors + pub fn get_authors(&self) -> Option<&Vec> { + self.authors.as_ref() + } + + /// Set authors + pub fn set_authors(&mut self, authors: Option>) { + self.authors = authors; + } + + /// Get description + pub fn get_description(&self) -> Option<&String> { + self.description.as_ref() + } + + /// Set description + pub fn set_description(&mut self, description: Option) { + self.description = description; + } + + /// Get license + pub fn get_license(&self) -> Option<&String> { + self.license.as_ref() + } + + /// Set license + pub fn set_license(&mut self, license: Option) { + self.license = license; + } + + /// Get custom_licenses + pub fn get_custom_licenses(&self) -> Option<&Vec> { + self.custom_licenses.as_ref() + } + + /// Set custom_licenses + pub fn set_custom_licenses(&mut self, custom_licenses: Option>) { + self.custom_licenses = custom_licenses; + } + + /// Get links + pub fn get_links(&self) -> Option<&Vec> { + self.links.as_ref() + } + + /// Set links + pub fn set_links(&mut self, links: Option>) { + self.links = links; + } + + /// Get categories + pub fn get_categories(&self) -> Option<&Vec> { + self.categories.as_ref() + } + + /// Set categories + pub fn set_categories(&mut self, categories: Option>) { + self.categories = categories; + } + + fn display(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { + let spaces = std::iter::repeat(" ").take(indent).collect::(); + + if let Some(authors) = &self.authors { + writeln!(f, "{spaces}authors:")?; + for author in authors { + writeln!(f, "{spaces} {author}")?; + } + } + + if let Some(license) = &self.license { + writeln!(f, "{spaces}license:")?; + writeln!(f, "{spaces} {license}")?; + } + + if let Some(links) = &self.links { + writeln!(f, "{spaces}links:")?; + for link in links { + writeln!(f, "{spaces} {link}")?; + } + } + + if let Some(categories) = &self.categories { + writeln!(f, "{spaces}categories:")?; + for category in categories { + writeln!(f, "{spaces} {category}")?; + } + } + + if let Some(description) = &self.description { + writeln!(f, "{spaces}description:")?; + writeln!(f, "{spaces} {description}")?; + } + + if let Some(custom_licenses) = &self.custom_licenses { + writeln!(f, "{spaces}custom_licenses:")?; + for license in custom_licenses { + license.display(f, indent + 4)?; + } + } + + Ok(()) + } +} + +impl Display for RegistryMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +pub struct Link { + pub ty: LinkType, + pub value: String, +} + +impl Display for Link { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}: {}", self.ty, self.value) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub enum LinkType { + Documentation, + Homepage, + Repository, + Funding, + #[serde(untagged)] + Custom(String), +} + +impl Display for LinkType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + LinkType::Documentation => "Documentation", + LinkType::Homepage => "Homepage", + LinkType::Repository => "Repository", + LinkType::Funding => "Funding", + LinkType::Custom(s) => s.as_str(), + }; + + write!(f, "{s}") + } +} + +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)] +pub struct CustomLicense { + /// License Identifier + /// Provides a locally unique identifier to refer to licenses that are not found on the SPDX License List. + /// + pub id: String, + + /// License Name + /// Provide a common name of the license that is not on the SPDX list. + /// + pub name: String, + + /// Extracted Text + /// Provides a copy of the actual text of the license reference extracted from the package or file that is associated with the License Identifier to aid in future analysis. + /// + pub text: String, + + /// License Cross Reference + /// Provides a pointer to the official source of a license that is not included in the SPDX License List, that is referenced by the License Identifier. + /// + #[serde(skip_serializing_if = "Option::is_none")] + pub reference: Option, +} + +impl CustomLicense { + fn display(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { + let spaces = std::iter::repeat(" ").take(indent).collect::(); + + writeln!(f, "{spaces}{}:", self.id)?; + writeln!(f, "{spaces} name: {}", self.name)?; + + if let Some(reference) = &self.reference { + writeln!(f, "{spaces} reference: {reference}")?; + } + + writeln!(f, "{spaces} text:")?; + writeln!(f, "{spaces} {}", self.text)?; + + Ok(()) + } +} + +impl Display for CustomLicense { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} + +#[cfg(test)] +mod test { + use std::vec; + + use super::*; + #[test] + fn add_to_empty_module() { + let wat = "(module)"; + let module = wat::parse_str(wat).unwrap(); + let add = AddMetadata { + name: Some("foo".to_owned()), + language: vec!["bar".to_owned()], + processed_by: vec![("baz".to_owned(), "1.0".to_owned())], + sdk: vec![], + registry_metadata: Some(RegistryMetadata { + authors: Some(vec!["foo".to_owned()]), + description: Some("foo bar baz".to_owned()), + license: Some("MIT OR LicenseRef-FOO".to_owned()), + custom_licenses: Some(vec![CustomLicense { + id: "FOO".to_owned(), + name: "Foo".to_owned(), + text: "Foo License".to_owned(), + reference: Some("https://exaple.com/license/foo".to_owned()), + }]), + links: Some(vec![ + Link { + ty: LinkType::Custom("CustomFoo".to_owned()), + value: "https://example.com/custom".to_owned(), + }, + Link { + ty: LinkType::Homepage, + value: "https://example.com".to_owned(), + }, + ]), + categories: Some(vec!["Tools".to_owned()]), + }), + }; + let module = add.to_wasm(&module).unwrap(); + + let metadata = Metadata::from_binary(&module).unwrap(); + match metadata { + Metadata::Module { + name, + producers, + registry_metadata, + range, + } => { + assert_eq!(name, Some("foo".to_owned())); + let producers = producers.expect("some producers"); + assert_eq!(producers.get("language").unwrap().get("bar").unwrap(), ""); + assert_eq!( + producers.get("processed-by").unwrap().get("baz").unwrap(), + "1.0" + ); + + let registry_metadata = registry_metadata.unwrap(); + + assert!(registry_metadata.validate().is_ok()); + + assert_eq!(registry_metadata.authors.unwrap(), vec!["foo".to_owned()]); + assert_eq!( + registry_metadata.description.unwrap(), + "foo bar baz".to_owned() + ); + + assert_eq!( + registry_metadata.license.unwrap(), + "MIT OR LicenseRef-FOO".to_owned() + ); + assert_eq!( + registry_metadata.custom_licenses.unwrap(), + vec![CustomLicense { + id: "FOO".to_owned(), + name: "Foo".to_owned(), + text: "Foo License".to_owned(), + reference: Some("https://exaple.com/license/foo".to_owned()), + }] + ); + assert_eq!( + registry_metadata.links.unwrap(), + vec![ + Link { + ty: LinkType::Custom("CustomFoo".to_owned()), + value: "https://example.com/custom".to_owned(), + }, + Link { + ty: LinkType::Homepage, + value: "https://example.com".to_owned(), + }, + ] + ); + assert_eq!( + registry_metadata.categories.unwrap(), + vec!["Tools".to_owned()] + ); + + assert_eq!(range.start, 0); + assert_eq!(range.end, 422); + } + _ => panic!("metadata should be module"), + } + } + + #[test] + fn add_to_empty_component() { + let wat = "(component)"; + let component = wat::parse_str(wat).unwrap(); + let add = AddMetadata { + name: Some("foo".to_owned()), + language: vec!["bar".to_owned()], + processed_by: vec![("baz".to_owned(), "1.0".to_owned())], + sdk: vec![], + registry_metadata: Some(RegistryMetadata { + authors: Some(vec!["foo".to_owned()]), + description: Some("foo bar baz".to_owned()), + license: Some("MIT OR LicenseRef-FOO".to_owned()), + custom_licenses: Some(vec![CustomLicense { + id: "FOO".to_owned(), + name: "Foo".to_owned(), + text: "Foo License".to_owned(), + reference: Some("https://exaple.com/license/foo".to_owned()), + }]), + links: Some(vec![ + Link { + ty: LinkType::Custom("CustomFoo".to_owned()), + value: "https://example.com/custom".to_owned(), + }, + Link { + ty: LinkType::Homepage, + value: "https://example.com".to_owned(), + }, + ]), + categories: Some(vec!["Tools".to_owned()]), + }), + }; + let component = add.to_wasm(&component).unwrap(); + + let metadata = Metadata::from_binary(&component).unwrap(); + match metadata { + Metadata::Component { + name, + producers, + registry_metadata, + children, + range, + } => { + assert!(children.is_empty()); + assert_eq!(name, Some("foo".to_owned())); + let producers = producers.expect("some producers"); + assert_eq!(producers.get("language").unwrap().get("bar").unwrap(), ""); + assert_eq!( + producers.get("processed-by").unwrap().get("baz").unwrap(), + "1.0" + ); + + let registry_metadata = registry_metadata.unwrap(); + + assert!(registry_metadata.validate().is_ok()); + + assert_eq!(registry_metadata.authors.unwrap(), vec!["foo".to_owned()]); + assert_eq!( + registry_metadata.description.unwrap(), + "foo bar baz".to_owned() + ); + + assert_eq!( + registry_metadata.license.unwrap(), + "MIT OR LicenseRef-FOO".to_owned() + ); + assert_eq!( + registry_metadata.custom_licenses.unwrap(), + vec![CustomLicense { + id: "FOO".to_owned(), + name: "Foo".to_owned(), + text: "Foo License".to_owned(), + reference: Some("https://exaple.com/license/foo".to_owned()), + }] + ); + assert_eq!( + registry_metadata.links.unwrap(), + vec![ + Link { + ty: LinkType::Custom("CustomFoo".to_owned()), + value: "https://example.com/custom".to_owned(), + }, + Link { + ty: LinkType::Homepage, + value: "https://example.com".to_owned(), + }, + ] + ); + assert_eq!( + registry_metadata.categories.unwrap(), + vec!["Tools".to_owned()] + ); + + assert_eq!(range.start, 0); + assert_eq!(range.end, 432); + } + _ => panic!("metadata should be component"), + } + } + + #[test] + fn add_to_nested_component() { + // Create the same old module, stick some metadata into it + let wat = "(module)"; + let module = wat::parse_str(wat).unwrap(); + let add = AddMetadata { + name: Some("foo".to_owned()), + language: vec!["bar".to_owned()], + processed_by: vec![("baz".to_owned(), "1.0".to_owned())], + sdk: vec![], + registry_metadata: Some(RegistryMetadata { + authors: Some(vec!["Foo".to_owned()]), + ..Default::default() + }), + }; + let module = add.to_wasm(&module).unwrap(); + + // Stick that module inside a component. + let mut component = wasm_encoder::Component::new(); + component.section(&wasm_encoder::RawSection { + id: wasm_encoder::ComponentSectionId::CoreModule.into(), + data: &module, + }); + let component = component.finish(); + + // Add some different metadata to the component. + let add = AddMetadata { + name: Some("gussie".to_owned()), + sdk: vec![("willa".to_owned(), "sparky".to_owned())], + ..Default::default() + }; + let component = add.to_wasm(&component).unwrap(); + + let metadata = Metadata::from_binary(&component).unwrap(); + match metadata { + Metadata::Component { + name, + producers, + children, + .. + } => { + // Check that the component metadata is in the component + assert_eq!(name, Some("gussie".to_owned())); + let producers = producers.as_ref().expect("some producers"); + assert_eq!( + producers.get("sdk").unwrap().get("willa").unwrap(), + &"sparky".to_owned() + ); + // Check that there is a single child with the metadata set for the module + assert_eq!(children.len(), 1); + let child = children.get(0).unwrap(); + match &**child { + Metadata::Module { + name, + producers, + registry_metadata, + range, + } => { + assert_eq!(name, &Some("foo".to_owned())); + let producers = producers.as_ref().expect("some producers"); + assert_eq!(producers.get("language").unwrap().get("bar").unwrap(), ""); + assert_eq!( + producers.get("processed-by").unwrap().get("baz").unwrap(), + "1.0" + ); + + let registry_metadata = registry_metadata.as_ref().unwrap(); + assert_eq!( + registry_metadata.authors.as_ref().unwrap(), + &["Foo".to_owned()] + ); + + assert_eq!(range.start, 10); + assert_eq!(range.end, 120); + } + _ => panic!("child is a module"), + } + } + _ => panic!("root should be component"), + } + } + + #[test] + fn producers_empty_module() { + let wat = "(module)"; + let module = wat::parse_str(wat).unwrap(); + let mut producers = Producers::empty(); + producers.add("language", "bar", ""); + producers.add("processed-by", "baz", "1.0"); + + let module = producers.add_to_wasm(&module).unwrap(); + + let metadata = Metadata::from_binary(&module).unwrap(); + match metadata { + Metadata::Module { + name, producers, .. + } => { + assert_eq!(name, None); + let producers = producers.expect("some producers"); + assert_eq!(producers.get("language").unwrap().get("bar").unwrap(), ""); + assert_eq!( + producers.get("processed-by").unwrap().get("baz").unwrap(), + "1.0" + ); + } + _ => panic!("metadata should be module"), + } + } + + #[test] + fn producers_add_another_field() { + let wat = "(module)"; + let module = wat::parse_str(wat).unwrap(); + let mut producers = Producers::empty(); + producers.add("language", "bar", ""); + producers.add("processed-by", "baz", "1.0"); + let module = producers.add_to_wasm(&module).unwrap(); + + let mut producers = Producers::empty(); + producers.add("language", "waaat", ""); + let module = producers.add_to_wasm(&module).unwrap(); + + let metadata = Metadata::from_binary(&module).unwrap(); + match metadata { + Metadata::Module { + name, producers, .. + } => { + assert_eq!(name, None); + let producers = producers.expect("some producers"); + assert_eq!(producers.get("language").unwrap().get("bar").unwrap(), ""); + assert_eq!(producers.get("language").unwrap().get("waaat").unwrap(), ""); + assert_eq!( + producers.get("processed-by").unwrap().get("baz").unwrap(), + "1.0" + ); + } + _ => panic!("metadata should be module"), + } + } + + #[test] + fn producers_overwrite_field() { + let wat = "(module)"; + let module = wat::parse_str(wat).unwrap(); + let mut producers = Producers::empty(); + producers.add("processed-by", "baz", "1.0"); + let module = producers.add_to_wasm(&module).unwrap(); + + let mut producers = Producers::empty(); + producers.add("processed-by", "baz", "420"); + let module = producers.add_to_wasm(&module).unwrap(); + + let metadata = Metadata::from_binary(&module).unwrap(); + match metadata { + Metadata::Module { producers, .. } => { + let producers = producers.expect("some producers"); + assert_eq!( + producers.get("processed-by").unwrap().get("baz").unwrap(), + "420" + ); + } + _ => panic!("metadata should be module"), + } + } + + #[test] + fn overwrite_registry_metadata() { + let wat = "(module)"; + let module = wat::parse_str(wat).unwrap(); + let registry_metadata = RegistryMetadata { + authors: Some(vec!["Foo".to_owned()]), + ..Default::default() + }; + let module = registry_metadata.add_to_wasm(&module).unwrap(); + + let registry_metadata = RegistryMetadata { + authors: Some(vec!["Bar".to_owned()]), + ..Default::default() + }; + let module = registry_metadata.add_to_wasm(&module).unwrap(); + + let metadata = Metadata::from_binary(&module).unwrap(); + match metadata { + Metadata::Module { + registry_metadata, .. + } => { + let registry_metadata = registry_metadata.expect("some registry_metadata"); + assert_eq!(registry_metadata.authors.unwrap(), vec!["Bar".to_owned()]); + } + _ => panic!("metadata should be module"), + } + } +} diff --git a/crates/wasm-mutate-stats/Cargo.toml b/crates/wasm-mutate-stats/Cargo.toml index f961ccc803..41e4e2731c 100644 --- a/crates/wasm-mutate-stats/Cargo.toml +++ b/crates/wasm-mutate-stats/Cargo.toml @@ -1,22 +1,22 @@ [package] name = "wasm-mutate-stats" version = "0.1.0" -edition = "2021" +edition.workspace = true publish = false [dependencies] -anyhow = "1.0" -arbitrary = "1.0" -num_cpus = "1.13" -rand = { version = "0.8.0", features = ["small_rng"] } -wasm-mutate = { path = '../wasm-mutate' } -wasmprinter = { path = '../wasmprinter' } -wasmparser = { path = "../wasmparser" } -wasmtime = "0.38.1" -env_logger = "0.9" +anyhow = { workspace = true } +arbitrary = { workspace = true } +num_cpus = { workspace = true } +rand = { workspace = true } +wasm-mutate = { workspace = true } +wasmprinter = { workspace = true } +wasmparser = { workspace = true } +wasmtime = { workspace = true } +env_logger = { workspace = true } itertools = "0.10.0" -clap = { version = "3.0", features = ['derive'] } -log = "0.4" +clap = { workspace = true } +log = { workspace = true } [lib] doctest = false diff --git a/crates/wasm-mutate-stats/src/bin/wasm-mutate-stats.rs b/crates/wasm-mutate-stats/src/bin/wasm-mutate-stats.rs index b5bceb4dba..800d213885 100644 --- a/crates/wasm-mutate-stats/src/bin/wasm-mutate-stats.rs +++ b/crates/wasm-mutate-stats/src/bin/wasm-mutate-stats.rs @@ -81,7 +81,7 @@ struct Options { /// List of engine configurations. /// Allowed values: [O0, O2, Os] /// If it is not set, the default configuration of wasmtime will be used - #[clap(short = 'c', long = "compilation-configs", parse(try_from_str=parse_optimization_types) )] + #[clap(short = 'c', long = "compilation-configs", value_parser = parse_optimization_types)] configs: Option>, /// Target triple during compilation, e.g. "x86_64-apple-darwin" #[clap(short = 'a', long = "triple")] diff --git a/crates/wasm-mutate/Cargo.toml b/crates/wasm-mutate/Cargo.toml index 33119537a2..87b9b46163 100644 --- a/crates/wasm-mutate/Cargo.toml +++ b/crates/wasm-mutate/Cargo.toml @@ -1,22 +1,22 @@ [package] name = "wasm-mutate" -version = "0.2.7" -edition = "2021" +version = "0.2.38" +edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-mutate" description = "A WebAssembly test case mutator" [dependencies] -clap = { optional = true, version = "3.0", features = ['derive'] } +clap = { workspace = true, optional = true } thiserror = "1.0.28" -wasmparser = { version = "0.90.0", path = "../wasmparser" } -wasm-encoder = { version = "0.16.0", path = "../wasm-encoder"} -rand = { version = "0.8.0", features = ["small_rng"] } -log = "0.4.14" +wasmparser = { workspace = true } +wasm-encoder = { workspace = true } +rand = { workspace = true } +log = { workspace = true } egg = "0.6.0" [dev-dependencies] -anyhow = "1" +anyhow = { workspace = true } wat = { path = "../wat" } wasmprinter = { path = "../wasmprinter" } -env_logger = "0.9" +env_logger = { workspace = true } diff --git a/crates/wasm-mutate/README.md b/crates/wasm-mutate/README.md index d0dbc7aab6..fd7e099cf7 100644 --- a/crates/wasm-mutate/README.md +++ b/crates/wasm-mutate/README.md @@ -20,17 +20,16 @@ ## Usage -Add this to your `Cargo.toml`: +Add `wasm-mutate` to your `Cargo.toml`: -```toml -[dependencies] -wasm-mutate = "0.2.0" +```shell +$ cargo add wasm-mutate ``` -You can mutate a WebAssembly binary by using the cli tool: +You can also mutate a WebAssembly binary by using the cli tool: ```bash -./wasm-mutate original.wasm --seed 0 -o out.wasm --preserve-semantics +wasm-tools mutate original.wasm --seed 0 -o out.wasm --preserve-semantics ``` ## Features @@ -139,7 +138,7 @@ You can mutate a WebAssembly binary by using the cli tool: # License This project is licensed under the Apache 2.0 license with the LLVM exception. -See [LICENSE](LICENSE) for more details. +See [LICENSE](../../LICENSE) for more details. ### Contribution diff --git a/crates/wasm-mutate/src/info.rs b/crates/wasm-mutate/src/info.rs index 50e7d12cd6..3e2bf0b6f6 100644 --- a/crates/wasm-mutate/src/info.rs +++ b/crates/wasm-mutate/src/info.rs @@ -6,7 +6,7 @@ use std::collections::HashSet; use std::convert::TryFrom; use std::ops::Range; use wasm_encoder::{RawSection, SectionId}; -use wasmparser::{Chunk, Parser, Payload, SectionReader}; +use wasmparser::{Chunk, Parser, Payload}; /// Provides module information for future usage during mutation /// an instance of ModuleInfo could be user to determine which mutation could be applied @@ -87,25 +87,21 @@ impl<'a> ModuleInfo<'a> { continue; } - Payload::TypeSection(mut reader) => { + Payload::TypeSection(reader) => { info.types = Some(info.raw_sections.len()); info.section(SectionId::Type.into(), reader.range(), input_wasm); // Save function types - for _ in 0..reader.get_count() { - reader.read().map(|ty| { - let typeinfo = TypeInfo::try_from(ty).unwrap(); - info.types_map.push(typeinfo); - })?; + for ty in reader.into_iter_err_on_gc_types() { + info.types_map.push(ty?.into()); } } - Payload::ImportSection(mut reader) => { + Payload::ImportSection(reader) => { info.imports = Some(info.raw_sections.len()); info.section(SectionId::Import.into(), reader.range(), input_wasm); - for _ in 0..reader.get_count() { - let ty = reader.read()?; - match ty.ty { + for ty in reader { + match ty?.ty { wasmparser::TypeRef::Func(ty) => { // Save imported functions info.function_map.push(ty); @@ -133,55 +129,51 @@ impl<'a> ModuleInfo<'a> { } } } - Payload::FunctionSection(mut reader) => { + Payload::FunctionSection(reader) => { info.functions = Some(info.raw_sections.len()); info.section(SectionId::Function.into(), reader.range(), input_wasm); - for _ in 0..reader.get_count() { - reader.read().map(|ty| { - info.function_map.push(ty); - })?; + for ty in reader { + info.function_map.push(ty?); } } - Payload::TableSection(mut reader) => { + Payload::TableSection(reader) => { info.tables = Some(info.raw_sections.len()); - info.table_count += reader.get_count(); + info.table_count += reader.count(); info.section(SectionId::Table.into(), reader.range(), input_wasm); - for _ in 0..reader.get_count() { - let ty = reader.read()?; - let ty = PrimitiveTypeInfo::try_from(ty.element_type).unwrap(); + for table in reader { + let table = table?; + let ty = PrimitiveTypeInfo::try_from(table.ty.element_type).unwrap(); info.table_elem_types.push(ty); } } - Payload::MemorySection(mut reader) => { + Payload::MemorySection(reader) => { info.memories = Some(info.raw_sections.len()); - info.memory_count += reader.get_count(); + info.memory_count += reader.count(); info.section(SectionId::Memory.into(), reader.range(), input_wasm); - for _ in 0..reader.get_count() { - let ty = reader.read()?; - info.memory_types.push(ty); + for ty in reader { + info.memory_types.push(ty?); } } - Payload::GlobalSection(mut reader) => { + Payload::GlobalSection(reader) => { info.globals = Some(info.raw_sections.len()); info.section(SectionId::Global.into(), reader.range(), input_wasm); - for _ in 0..reader.get_count() { - let ty = reader.read()?; + for ty in reader { + let ty = ty?; // We only need the type of the global, not necessarily if is mutable or not let ty = PrimitiveTypeInfo::try_from(ty.ty.content_type).unwrap(); info.global_types.push(ty); } } - Payload::ExportSection(mut reader) => { + Payload::ExportSection(reader) => { info.exports = Some(info.raw_sections.len()); - info.exports_count = reader.get_count(); + info.exports_count = reader.count(); - for _ in 0..reader.get_count() { - let entry = reader.read()?; - info.export_names.insert(entry.name.into()); + for entry in reader.clone() { + info.export_names.insert(entry?.name.into()); } info.section(SectionId::Export.into(), reader.range(), input_wasm); @@ -193,12 +185,12 @@ impl<'a> ModuleInfo<'a> { } Payload::ElementSection(reader) => { info.elements = Some(info.raw_sections.len()); - info.elements_count = reader.get_count(); + info.elements_count = reader.count(); info.section(SectionId::Element.into(), reader.range(), input_wasm); } Payload::DataSection(reader) => { info.data = Some(info.raw_sections.len()); - info.data_segments_count = reader.get_count(); + info.data_segments_count = reader.count(); info.section(SectionId::Data.into(), reader.range(), input_wasm); } Payload::CustomSection(c) => { @@ -231,7 +223,7 @@ impl<'a> ModuleInfo<'a> { if let Some(section) = self.code { let section_data = self.raw_sections[section].data; wasmparser::CodeSectionReader::new(section_data, 0) - .map(|r| r.get_count() != 0) + .map(|r| r.count() != 0) .unwrap_or(false) } else { false @@ -316,6 +308,31 @@ impl<'a> ModuleInfo<'a> { module } + /// Move a section from index `src_idx` to `dest_idx` in the Wasm module + pub fn move_section(&self, src_idx: usize, dest_idx: usize) -> wasm_encoder::Module { + log::trace!( + "moving section from index {} to index {}", + src_idx, + dest_idx + ); + assert!(src_idx < self.raw_sections.len()); + assert!(dest_idx < self.raw_sections.len()); + assert_ne!(src_idx, dest_idx); + let mut module = wasm_encoder::Module::new(); + self.raw_sections.iter().enumerate().for_each(|(i, s)| { + if src_idx < dest_idx && i == dest_idx { + module.section(&self.raw_sections[src_idx]); + } + if i != src_idx { + module.section(s); + } + if dest_idx < src_idx && i == dest_idx { + module.section(&self.raw_sections[src_idx]); + } + }); + module + } + /// Replace the `i`th section in this module with the given new section. pub fn replace_section( &self, diff --git a/crates/wasm-mutate/src/lib.rs b/crates/wasm-mutate/src/lib.rs index 39b9b04a9c..09d2df888f 100644 --- a/crates/wasm-mutate/src/lib.rs +++ b/crates/wasm-mutate/src/lib.rs @@ -18,94 +18,21 @@ pub use error::*; use crate::mutators::{ add_function::AddFunctionMutator, add_type::AddTypeMutator, codemotion::CodemotionMutator, - function_body_unreachable::FunctionBodyUnreachable, modify_const_exprs::ConstExpressionMutator, - modify_data::ModifyDataMutator, peephole::PeepholeMutator, remove_export::RemoveExportMutator, - remove_item::RemoveItemMutator, remove_section::RemoveSection, - rename_export::RenameExportMutator, snip_function::SnipMutator, Item, + custom::AddCustomSectionMutator, custom::CustomSectionMutator, + custom::ReorderCustomSectionMutator, function_body_unreachable::FunctionBodyUnreachable, + modify_const_exprs::ConstExpressionMutator, modify_data::ModifyDataMutator, + peephole::PeepholeMutator, remove_export::RemoveExportMutator, remove_item::RemoveItemMutator, + remove_section::RemoveSection, rename_export::RenameExportMutator, snip_function::SnipMutator, + Item, }; use info::ModuleInfo; use mutators::Mutator; use rand::{rngs::SmallRng, Rng, SeedableRng}; -use std::{cell::Cell, sync::Arc}; +use std::sync::Arc; #[cfg(feature = "clap")] use clap::Parser; -macro_rules! define_mutators { - (@count) => {0}; - (@count $first: expr , $( $tail: expr ,) *) => { 1 + define_mutators!(@count $($tail , )*) }; - (@expand $self:ident, $discriminator: ident, $start: expr, . , $( $rest: expr ,)*) => {}; - // The dot (.) is the mark to avoid infinite recursion , something like and - // LR parser - (@expand $self:ident, $discriminator: ident, $start: expr, $first: expr , $( $head: expr ,)* . , $( $rest: expr ,)*) => { - if $discriminator == $start { - // Start by the current node - let m = $first; - - let can_mutate = m.can_mutate($self); - log::trace!("Can `{}` mutate? {}", m.name(), can_mutate); - if can_mutate { - log::debug!("attempting to mutate with `{}`", m.name()); - match m.clone().mutate($self) { - Ok(iter) => { - log::debug!("mutator `{}` succeeded", m.name()); - return Ok(Box::new(iter.into_iter().map(|r| r.map(|m| m.finish())))) - } - Err(e) => { - log::debug!("mutator `{}` failed: {}", m.name(), e); - return Err(e); - } - } - } - // Follow the tail - $( - let m = $rest; - - let can_mutate = m.can_mutate($self); - log::trace!("Can `{}` mutate? {}", m.name(), can_mutate); - if can_mutate { - log::debug!("attempting to mutate with `{}`", m.name()); - match m.clone().mutate($self) { - Ok(iter) => { - log::debug!("mutator `{}` succeeded", m.name()); - return Ok(Box::new(iter.into_iter().map(|r| r.map(|m| m.finish())))) - } - Err(e) => { - log::debug!("mutator {} failed: {}", m.name(), e); - return Err(e); - } - } - } - )* - // Follow the head - $( - let m = $head; - - if m.can_mutate($self) { - match m.clone().mutate($self) { - Ok(iter) => { - return Ok(Box::new(iter.into_iter().map(|r| r.map(|m| m.finish())))) - } - Err(e) => { - log::debug!("mutator {} failed: {}; will try again", m.name(), e); - return Err(e); - } - } - } - )* - }; - - define_mutators!(@expand $self, $discriminator, ($start + 1), $($head ,)* ., $($rest ,)* $first, ) - }; - ( $self: ident , ($first: expr , $( $tail: expr ,)* ) ) => { - { - let count = define_mutators!(@count $first , $($tail ,)*); - let discriminator:u32 = $self.rng().gen_range(0..count); - define_mutators!(@expand $self, discriminator , 0 , $first , $($tail ,)* . , ); - } - }; -} - // NB: only add this doc comment if we are not building the CLI, since otherwise // it will override the main CLI's about text. #[cfg_attr( @@ -174,10 +101,9 @@ pub struct WasmMutate<'wasm> { short, long, default_value = "18446744073709551615", // u64::MAX - parse(try_from_str = parse_fuel), ) )] - fuel: Cell, + fuel: u64, /// Only perform size-reducing transformations on the Wasm module. This /// allows `wasm-mutate` to be used as a test case reducer. @@ -196,11 +122,6 @@ pub struct WasmMutate<'wasm> { info: Option>, } -#[cfg(feature = "clap")] -fn parse_fuel(s: &str) -> Result, String> { - s.parse::().map(Cell::new).map_err(|s| s.to_string()) -} - impl Default for WasmMutate<'_> { fn default() -> Self { let seed = 3; @@ -209,7 +130,7 @@ impl Default for WasmMutate<'_> { preserve_semantics: false, reduce: false, raw_mutate_func: None, - fuel: Cell::new(u64::MAX), + fuel: u64::MAX, rng: None, info: None, } @@ -235,7 +156,7 @@ impl<'wasm> WasmMutate<'wasm> { /// Configure the fuel used during the mutation pub fn fuel(&mut self, fuel: u64) -> &mut Self { - self.fuel = Cell::new(fuel); + self.fuel = fuel; self } @@ -269,12 +190,12 @@ impl<'wasm> WasmMutate<'wasm> { self } - pub(crate) fn consume_fuel(&self, qt: u64) -> Result<()> { - if qt > self.fuel.get() { + pub(crate) fn consume_fuel(&mut self, qt: u64) -> Result<()> { + if qt > self.fuel { log::info!("Out of fuel"); return Err(Error::out_of_fuel()); } - self.fuel.set(self.fuel.get() - qt); + self.fuel -= qt; Ok(()) } @@ -285,45 +206,59 @@ impl<'wasm> WasmMutate<'wasm> { ) -> Result>> + 'a>> { self.setup(input_wasm)?; - // This macro just expands the logic to return an iterator form the - // mutators - // It simulates a circular checking of the mutators starting by a random - // one, returning the first one that can provides a mutation. - // All possible start indexes are calculated at compilation time, if N - // is the number of mutataros, N possible starting indexes are injected - // and compiled to the final code - define_mutators!( - self, - ( - PeepholeMutator::new(2), - RemoveExportMutator, - RenameExportMutator { max_name_size: 100 }, - SnipMutator, - CodemotionMutator, - FunctionBodyUnreachable, - AddTypeMutator { - max_params: 20, - max_results: 20, - }, - AddFunctionMutator, - RemoveSection::Custom, - RemoveSection::Empty, - ConstExpressionMutator::Global, - ConstExpressionMutator::ElementOffset, - ConstExpressionMutator::ElementFunc, - RemoveItemMutator(Item::Function), - RemoveItemMutator(Item::Global), - RemoveItemMutator(Item::Memory), - RemoveItemMutator(Item::Table), - RemoveItemMutator(Item::Type), - RemoveItemMutator(Item::Data), - RemoveItemMutator(Item::Element), - RemoveItemMutator(Item::Tag), - ModifyDataMutator { - max_data_size: 10 << 20, // 10MB - }, - ) - ); + const MUTATORS: &[&dyn Mutator] = &[ + &PeepholeMutator::new(2), + &RemoveExportMutator, + &RenameExportMutator { max_name_size: 100 }, + &SnipMutator, + &CodemotionMutator, + &FunctionBodyUnreachable, + &AddCustomSectionMutator, + &ReorderCustomSectionMutator, + &CustomSectionMutator, + &AddTypeMutator { + max_params: 20, + max_results: 20, + }, + &AddFunctionMutator, + &RemoveSection::Custom, + &RemoveSection::Empty, + &ConstExpressionMutator::Global, + &ConstExpressionMutator::ElementOffset, + &ConstExpressionMutator::ElementFunc, + &RemoveItemMutator(Item::Function), + &RemoveItemMutator(Item::Global), + &RemoveItemMutator(Item::Memory), + &RemoveItemMutator(Item::Table), + &RemoveItemMutator(Item::Type), + &RemoveItemMutator(Item::Data), + &RemoveItemMutator(Item::Element), + &RemoveItemMutator(Item::Tag), + &ModifyDataMutator { + max_data_size: 10 << 20, // 10MB + }, + ]; + + // Attempt all mutators, but start at an arbitrary index. + let start = self.rng().gen_range(0..MUTATORS.len()); + for m in MUTATORS.iter().cycle().skip(start).take(MUTATORS.len()) { + let can_mutate = m.can_mutate(self); + log::trace!("Can `{}` mutate? {}", m.name(), can_mutate); + if !can_mutate { + continue; + } + log::debug!("attempting to mutate with `{}`", m.name()); + match m.mutate(self) { + Ok(iter) => { + log::debug!("mutator `{}` succeeded", m.name()); + return Ok(Box::new(iter.into_iter().map(|r| r.map(|m| m.finish())))); + } + Err(e) => { + log::debug!("mutator `{}` failed: {}", m.name(), e); + return Err(e); + } + } + } Err(Error::no_mutations_applicable()) } diff --git a/crates/wasm-mutate/src/module.rs b/crates/wasm-mutate/src/module.rs index fe07a2912a..4431a14fed 100644 --- a/crates/wasm-mutate/src/module.rs +++ b/crates/wasm-mutate/src/module.rs @@ -1,8 +1,7 @@ -use crate::{Error, Result}; -use std::convert::TryFrom; -use wasm_encoder::{BlockType, ValType}; +use crate::Result; +use wasm_encoder::{BlockType, HeapType, RefType, ValType}; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub enum PrimitiveTypeInfo { I32, I64, @@ -34,33 +33,38 @@ impl From for PrimitiveTypeInfo { wasmparser::ValType::F32 => PrimitiveTypeInfo::F32, wasmparser::ValType::F64 => PrimitiveTypeInfo::F64, wasmparser::ValType::V128 => PrimitiveTypeInfo::V128, - wasmparser::ValType::FuncRef => PrimitiveTypeInfo::FuncRef, - wasmparser::ValType::ExternRef => PrimitiveTypeInfo::ExternRef, + wasmparser::ValType::Ref(t) => t.into(), } } } -impl TryFrom for TypeInfo { - type Error = Error; - - fn try_from(value: wasmparser::Type) -> Result { +impl From for PrimitiveTypeInfo { + fn from(value: wasmparser::RefType) -> Self { match value { - wasmparser::Type::Func(ft) => Ok(TypeInfo::Func(FuncInfo { - params: ft - .params() - .iter() - .map(|&t| PrimitiveTypeInfo::from(t)) - .collect(), - returns: ft - .results() - .iter() - .map(|&t| PrimitiveTypeInfo::from(t)) - .collect(), - })), + wasmparser::RefType::FUNCREF => PrimitiveTypeInfo::FuncRef, + wasmparser::RefType::EXTERNREF => PrimitiveTypeInfo::ExternRef, + _ => unimplemented!(), } } } +impl From for TypeInfo { + fn from(ft: wasmparser::FuncType) -> Self { + TypeInfo::Func(FuncInfo { + params: ft + .params() + .iter() + .map(|&t| PrimitiveTypeInfo::from(t)) + .collect(), + returns: ft + .results() + .iter() + .map(|&t| PrimitiveTypeInfo::from(t)) + .collect(), + }) + } +} + pub fn map_type(tpe: wasmparser::ValType) -> Result { match tpe { wasmparser::ValType::I32 => Ok(ValType::I32), @@ -68,11 +72,29 @@ pub fn map_type(tpe: wasmparser::ValType) -> Result { wasmparser::ValType::F32 => Ok(ValType::F32), wasmparser::ValType::F64 => Ok(ValType::F64), wasmparser::ValType::V128 => Ok(ValType::V128), - wasmparser::ValType::FuncRef => Ok(ValType::FuncRef), - wasmparser::ValType::ExternRef => Ok(ValType::ExternRef), + wasmparser::ValType::Ref(t) => Ok(ValType::Ref(map_ref_type(t)?)), } } +pub fn map_ref_type(ref_ty: wasmparser::RefType) -> Result { + Ok(RefType { + nullable: ref_ty.is_nullable(), + heap_type: match ref_ty.heap_type() { + wasmparser::HeapType::Func => HeapType::Func, + wasmparser::HeapType::Extern => HeapType::Extern, + wasmparser::HeapType::Any => HeapType::Any, + wasmparser::HeapType::None => HeapType::None, + wasmparser::HeapType::NoExtern => HeapType::NoExtern, + wasmparser::HeapType::NoFunc => HeapType::NoFunc, + wasmparser::HeapType::Eq => HeapType::Eq, + wasmparser::HeapType::Struct => HeapType::Struct, + wasmparser::HeapType::Array => HeapType::Array, + wasmparser::HeapType::I31 => HeapType::I31, + wasmparser::HeapType::Indexed(i) => HeapType::Indexed(i.into()), + }, + }) +} + pub fn map_block_type(ty: wasmparser::BlockType) -> Result { match ty { wasmparser::BlockType::Empty => Ok(BlockType::Empty), diff --git a/crates/wasm-mutate/src/mutators.rs b/crates/wasm-mutate/src/mutators.rs index 6836739700..9a64961ab9 100644 --- a/crates/wasm-mutate/src/mutators.rs +++ b/crates/wasm-mutate/src/mutators.rs @@ -12,13 +12,15 @@ //! specifycally at the code section level of the binary. The code motion mutator //! parses the code and provides an AST which is transformed in a semantically //! equivalent way. We provide two concrete implementations using this type of -//! mutator: [LoopUnrollMutator][codemotion::mutators::loop_unrolling::LoopUnrollMutator] and [IfComplementMutator][codemotion::mutators::if_complement::IfComplementMutator]. +//! mutator: [`LoopUnrollMutator`] and [`IfComplementMutator`]. //! //! The last group of mutators are the [**peephole //! mutators**][super::PeepholeMutator]. When it comes to the input Wasm binary code section, it //! iterates through the defined functions, and then each instruction of the //! functions is processed in order to construct an equivalent piece of code. //! +//! [`LoopUnrollMutator`]: crate::mutators::codemotion::loop_unrolling::LoopUnrollMutator +//! [`IfComplementMutator`]: crate::mutators::codemotion::if_complement::IfComplementMutator pub mod add_function; pub mod add_type; @@ -91,7 +93,7 @@ pub trait Mutator { /// `std::iter::once`, to give the fuzzer a chance to choose a new kind of /// mutation. fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, ) -> Result> + 'a>>; @@ -136,7 +138,7 @@ impl WasmMutate<'_> { assert!(can_mutate); - let attempts = 100; + let attempts = 2000; let mut last_mutation = None; for _ in 0..attempts { diff --git a/crates/wasm-mutate/src/mutators/add_function.rs b/crates/wasm-mutate/src/mutators/add_function.rs index 8216a6c964..345dabd3ab 100644 --- a/crates/wasm-mutate/src/mutators/add_function.rs +++ b/crates/wasm-mutate/src/mutators/add_function.rs @@ -5,7 +5,7 @@ use crate::module::{PrimitiveTypeInfo, TypeInfo}; use crate::{Result, WasmMutate}; use rand::Rng; use std::convert::TryFrom; -use wasm_encoder::{Instruction, Module, ValType}; +use wasm_encoder::{HeapType, Instruction, Module}; /// Mutator that adds new, empty functions to a Wasm module. #[derive(Clone, Copy)] @@ -13,7 +13,7 @@ pub struct AddFunctionMutator; impl Mutator for AddFunctionMutator { fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, ) -> Result> + 'a>> { let max_ty_idx = config.info().num_types() - 1; @@ -23,10 +23,9 @@ impl Mutator for AddFunctionMutator { let mut func_sec_enc = wasm_encoder::FunctionSection::new(); if let Some(func_sec_idx) = config.info().functions { let raw_func_sec = config.info().raw_sections[func_sec_idx]; - let mut reader = wasmparser::FunctionSectionReader::new(raw_func_sec.data, 0)?; - for _ in 0..reader.get_count() { - let x = reader.read()?; - func_sec_enc.function(x); + let reader = wasmparser::FunctionSectionReader::new(raw_func_sec.data, 0)?; + for x in reader { + func_sec_enc.function(x?); } } func_sec_enc.function(ty_idx); @@ -36,9 +35,9 @@ impl Mutator for AddFunctionMutator { let mut code_sec_enc = wasm_encoder::CodeSection::new(); if let Some(code_sec_idx) = config.info().code { let raw_code_sec = config.info().raw_sections[code_sec_idx]; - let mut reader = wasmparser::CodeSectionReader::new(raw_code_sec.data, 0)?; - for _ in 0..reader.get_count() { - let body = reader.read()?; + let reader = wasmparser::CodeSectionReader::new(raw_code_sec.data, 0)?; + for body in reader { + let body = body?; let range = body.range(); code_sec_enc.raw(&raw_code_sec.data[range.start..range.end]); } @@ -65,10 +64,10 @@ impl Mutator for AddFunctionMutator { func.instruction(&Instruction::V128Const(0)); } PrimitiveTypeInfo::FuncRef => { - func.instruction(&Instruction::RefNull(ValType::FuncRef)); + func.instruction(&Instruction::RefNull(HeapType::Func)); } PrimitiveTypeInfo::ExternRef => { - func.instruction(&Instruction::RefNull(ValType::ExternRef)); + func.instruction(&Instruction::RefNull(HeapType::Extern)); } PrimitiveTypeInfo::Empty => unreachable!(), } diff --git a/crates/wasm-mutate/src/mutators/add_type.rs b/crates/wasm-mutate/src/mutators/add_type.rs index fad8cb8757..f2fe0c3e8c 100644 --- a/crates/wasm-mutate/src/mutators/add_type.rs +++ b/crates/wasm-mutate/src/mutators/add_type.rs @@ -1,6 +1,7 @@ //! A mutator to add a new type to a Wasm module. use super::Mutator; +use crate::module::map_type; use crate::Result; use rand::Rng; use std::iter; @@ -22,8 +23,8 @@ impl AddTypeMutator { 2 => wasm_encoder::ValType::F32, 3 => wasm_encoder::ValType::F64, 4 => wasm_encoder::ValType::V128, - 5 => wasm_encoder::ValType::ExternRef, - 6 => wasm_encoder::ValType::FuncRef, + 5 => wasm_encoder::ValType::EXTERNREF, + 6 => wasm_encoder::ValType::FUNCREF, _ => unreachable!(), } } @@ -35,7 +36,7 @@ impl Mutator for AddTypeMutator { } fn mutate<'a>( - self, + &self, config: &'a mut crate::WasmMutate, ) -> crate::Result> + 'a>> { let count = config.rng().gen_range(0..=self.max_params); @@ -53,24 +54,22 @@ impl Mutator for AddTypeMutator { let mut types = wasm_encoder::TypeSection::new(); if let Some(old_types) = config.info().get_type_section() { // Copy the existing types section over into the encoder. - let mut reader = wasmparser::TypeSectionReader::new(old_types.data, 0)?; - for _ in 0..reader.get_count() { - let ty = reader.read()?; - match ty { - wasmparser::Type::Func(ty) => { - let params = ty - .params() - .iter() - .map(translate_type) - .collect::, _>>()?; - let results = ty - .results() - .iter() - .map(translate_type) - .collect::, _>>()?; - types.function(params, results); - } - } + let reader = wasmparser::TypeSectionReader::new(old_types.data, 0)?; + for ty in reader.into_iter_err_on_gc_types() { + let ty = ty?; + let params = ty + .params() + .iter() + .copied() + .map(map_type) + .collect::, _>>()?; + let results = ty + .results() + .iter() + .copied() + .map(map_type) + .collect::, _>>()?; + types.function(params, results); } // And then add our new type. types.function(params, results); @@ -87,18 +86,6 @@ impl Mutator for AddTypeMutator { } } -fn translate_type(ty: &wasmparser::ValType) -> Result { - Ok(match ty { - wasmparser::ValType::I32 => wasm_encoder::ValType::I32, - wasmparser::ValType::I64 => wasm_encoder::ValType::I64, - wasmparser::ValType::F32 => wasm_encoder::ValType::F32, - wasmparser::ValType::F64 => wasm_encoder::ValType::F64, - wasmparser::ValType::V128 => wasm_encoder::ValType::V128, - wasmparser::ValType::FuncRef => wasm_encoder::ValType::FuncRef, - wasmparser::ValType::ExternRef => wasm_encoder::ValType::ExternRef, - }) -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/wasm-mutate/src/mutators/codemotion.rs b/crates/wasm-mutate/src/mutators/codemotion.rs index d1ba8ebb42..b87c821968 100644 --- a/crates/wasm-mutate/src/mutators/codemotion.rs +++ b/crates/wasm-mutate/src/mutators/codemotion.rs @@ -64,19 +64,17 @@ impl CodemotionMutator { ) -> crate::Result<(Function, u32)> { let original_code_section = config.info().get_code_section(); - let mut sectionreader = CodeSectionReader::new(original_code_section.data, 0)?; - let function_count = sectionreader.get_count(); + let sectionreader = CodeSectionReader::new(original_code_section.data, 0)?; + let function_count = sectionreader.count(); let function_to_mutate = config.rng().gen_range(0..function_count); // This split strategy will avoid very often mutating the first function // and very rarely mutating the last function - let all_readers = (0..function_count) - .map(|_| sectionreader.read().unwrap()) - .collect::>(); + let all_readers = sectionreader.into_iter().collect::, _>>()?; for fidx in (function_to_mutate..function_count).chain(0..function_to_mutate) { config.consume_fuel(1)?; - let reader = all_readers[fidx as usize]; + let reader = all_readers[fidx as usize].clone(); let mut operatorreader = reader.get_operators_reader()?; operatorreader.allow_memarg64(true); @@ -133,7 +131,7 @@ pub trait AstMutator { /// Meta mutator for peephole impl Mutator for CodemotionMutator { fn mutate<'a>( - self, + &self, config: &mut WasmMutate<'a>, ) -> Result> + 'a>> { // Initialize mutators @@ -146,11 +144,11 @@ impl Mutator for CodemotionMutator { let mut codes = CodeSection::new(); let code_section = config.info().get_code_section(); - let mut sectionreader = CodeSectionReader::new(code_section.data, 0)?; + let sectionreader = CodeSectionReader::new(code_section.data, 0)?; - for fidx in 0..config.info().num_local_functions() { - let reader = sectionreader.read()?; - if fidx == function_to_mutate { + for (fidx, reader) in sectionreader.into_iter().enumerate() { + let reader = reader?; + if fidx as u32 == function_to_mutate { log::trace!("Mutating function {}", fidx); codes.function(&newfunc); } else { diff --git a/crates/wasm-mutate/src/mutators/codemotion/if_complement.rs b/crates/wasm-mutate/src/mutators/codemotion/if_complement.rs index 70e91bff88..c17a7e3519 100644 --- a/crates/wasm-mutate/src/mutators/codemotion/if_complement.rs +++ b/crates/wasm-mutate/src/mutators/codemotion/if_complement.rs @@ -52,7 +52,7 @@ impl IfComplementWriter { } } else { // Write an unreachable instruction - newfunc.instruction(&Instruction::Unreachable); + newfunc.instruction(&Instruction::Nop); } newfunc.instruction(&Instruction::Else); for ch in then { diff --git a/crates/wasm-mutate/src/mutators/codemotion/ir.rs b/crates/wasm-mutate/src/mutators/codemotion/ir.rs index 9e6522b5bf..a41c4569b0 100644 --- a/crates/wasm-mutate/src/mutators/codemotion/ir.rs +++ b/crates/wasm-mutate/src/mutators/codemotion/ir.rs @@ -271,14 +271,14 @@ impl AstBuilder { for (idx, (operator, _)) in operators.iter().enumerate() { match operator { - Operator::If { ty } => { + Operator::If { blockty } => { // push current code first if !parse_context.current_code_is_empty() { parse_context.push_current_code_as_node(); } parse_context.reset_code_range_at(idx + 1); parse_context.push_state(); - parse_context.push_frame(State::If, Some(*ty), idx); + parse_context.push_frame(State::If, Some(*blockty), idx); } Operator::Else => { if !parse_context.current_code_is_empty() { @@ -288,21 +288,21 @@ impl AstBuilder { parse_context.push_state(); parse_context.push_frame(State::Else, None, idx); } - Operator::Block { ty } => { + Operator::Block { blockty } => { if !parse_context.current_code_is_empty() { parse_context.push_current_code_as_node(); } parse_context.reset_code_range_at(idx + 1); parse_context.push_state(); - parse_context.push_frame(State::Block, Some(*ty), idx); + parse_context.push_frame(State::Block, Some(*blockty), idx); } - Operator::Loop { ty } => { + Operator::Loop { blockty } => { if !parse_context.current_code_is_empty() { parse_context.push_current_code_as_node(); } parse_context.reset_code_range_at(idx + 1); parse_context.push_state(); - parse_context.push_frame(State::Loop, Some(*ty), idx); + parse_context.push_frame(State::Loop, Some(*blockty), idx); } Operator::End => { if !parse_context.current_code_is_empty() { diff --git a/crates/wasm-mutate/src/mutators/codemotion/loop_unrolling.rs b/crates/wasm-mutate/src/mutators/codemotion/loop_unrolling.rs index 9c167455c7..9eb1b86e61 100644 --- a/crates/wasm-mutate/src/mutators/codemotion/loop_unrolling.rs +++ b/crates/wasm-mutate/src/mutators/codemotion/loop_unrolling.rs @@ -94,9 +94,9 @@ impl LoopUnrollWriter { to_fix.insert(idx, Instruction::BrIf(relative_depth + 1)); } } - Operator::BrTable { table } => { + Operator::BrTable { targets } => { let mut jmpfix = vec![]; - for i in table.targets() { + for i in targets.targets() { let d = i?; if d > current_depth { // Out jump...annotate for fixing @@ -106,7 +106,7 @@ impl LoopUnrollWriter { } } - let mut def = table.default(); + let mut def = targets.default(); if def > current_depth { def += 1; } diff --git a/crates/wasm-mutate/src/mutators/custom.rs b/crates/wasm-mutate/src/mutators/custom.rs index d32e870a1f..6991c4dece 100644 --- a/crates/wasm-mutate/src/mutators/custom.rs +++ b/crates/wasm-mutate/src/mutators/custom.rs @@ -1,5 +1,7 @@ //! Mutate custom sections. +use std::borrow::Cow; + use super::Mutator; use rand::{seq::SliceRandom, Rng}; @@ -12,7 +14,7 @@ impl Mutator for CustomSectionMutator { } fn mutate<'a>( - self, + &self, config: &'a mut crate::WasmMutate, ) -> crate::Result> + 'a>> { let custom_section_indices: Vec<_> = config @@ -67,15 +69,105 @@ impl Mutator for CustomSectionMutator { .info() .replace_section( custom_section_index, - &wasm_encoder::CustomSection { name, data }, + &wasm_encoder::CustomSection { + name: name.into(), + data: Cow::Borrowed(data), + }, ))))) } } +#[derive(Clone, Copy)] +pub struct AddCustomSectionMutator; + +const MAX_NEW_DATA_LEN: usize = 100; +const MAX_NEW_NAME_LEN: usize = 20; + +impl Mutator for AddCustomSectionMutator { + fn can_mutate(&self, config: &crate::WasmMutate) -> bool { + !config.reduce + } + + fn mutate<'a>( + &self, + config: &'a mut crate::WasmMutate, + ) -> crate::Result> + 'a>> { + let num_sections = config.info().raw_sections.len(); + let new_custom_section_idx = config.rng().gen_range(0..=num_sections); + let mut name = vec![]; + config.raw_mutate(&mut name, MAX_NEW_NAME_LEN)?; + let name = String::from_utf8_lossy(&name); + let mut data = vec![]; + config.raw_mutate(&mut data, MAX_NEW_DATA_LEN)?; + + Ok(Box::new(std::iter::once(Ok(config.info().insert_section( + new_custom_section_idx, + &wasm_encoder::CustomSection { + name: name.into(), + data: Cow::Borrowed(&data), + }, + ))))) + } +} + +#[derive(Copy, Clone)] +pub struct ReorderCustomSectionMutator; + +impl Mutator for ReorderCustomSectionMutator { + fn can_mutate(&self, config: &crate::WasmMutate) -> bool { + config.info().has_custom_section() && config.info().raw_sections.len() > 1 + } + + fn mutate<'a>( + &self, + config: &'a mut crate::WasmMutate, + ) -> crate::Result> + 'a>> { + let custom_section_indices: Vec<_> = config + .info() + .raw_sections + .iter() + .enumerate() + .filter(|(_i, s)| s.id == wasm_encoder::SectionId::Custom as u8) + .map(|(i, _s)| i) + .collect(); + assert!(!custom_section_indices.is_empty()); + + let src_idx = *custom_section_indices.choose(config.rng()).unwrap(); + let num_sections = config.info().raw_sections.len(); + let mut dest_idx; + loop { + dest_idx = config.rng().gen_range(0..num_sections); + if dest_idx != src_idx { + break; + } + config.consume_fuel(1)?; + } + + Ok(Box::new(std::iter::once(Ok(config + .info() + .move_section(src_idx, dest_idx))))) + } +} + #[cfg(test)] mod tests { use super::*; + #[test] + fn test_add_custom_section() { + crate::mutators::match_mutation( + r#" + (module) + "#, + AddCustomSectionMutator, + r#" + (module + (@custom "a" "b") + ) + "#, + ); + } + #[test] fn test_grow_custom_section() { crate::mutators::match_mutation( @@ -143,4 +235,23 @@ mod tests { "#, ); } + + #[test] + fn test_reorder_custom_section() { + crate::mutators::match_mutation( + r#" + (module + (@custom "name" "data") + (@custom "name2" "data") + ) + "#, + ReorderCustomSectionMutator, + r#" + (module + (@custom "name2" "data") + (@custom "name" "data") + ) + "#, + ) + } } diff --git a/crates/wasm-mutate/src/mutators/function_body_unreachable.rs b/crates/wasm-mutate/src/mutators/function_body_unreachable.rs index 6dd84bf52d..390ad98db3 100644 --- a/crates/wasm-mutate/src/mutators/function_body_unreachable.rs +++ b/crates/wasm-mutate/src/mutators/function_body_unreachable.rs @@ -14,36 +14,33 @@ pub struct FunctionBodyUnreachable; impl Mutator for FunctionBodyUnreachable { fn mutate<'a>( - self, + &self, config: &mut WasmMutate<'a>, ) -> Result> + 'a>> { let mut codes = CodeSection::new(); let code_section = config.info().get_code_section(); - let mut reader = CodeSectionReader::new(code_section.data, 0)?; + let reader = CodeSectionReader::new(code_section.data, 0)?; - let count = reader.get_count(); + let count = reader.count(); let function_to_mutate = config.rng().gen_range(0..count); - (0..count) - .map(|i| { - config.consume_fuel(1)?; + for (i, f) in reader.into_iter().enumerate() { + config.consume_fuel(1)?; - let f = reader.read().unwrap(); - if i == function_to_mutate { - log::trace!("Mutating function {}", i); - let locals = vec![]; - let mut f = Function::new(locals); - f.instruction(&Instruction::Unreachable); - f.instruction(&Instruction::End); + let f = f?; + if i as u32 == function_to_mutate { + log::trace!("Mutating function {}", i); + let locals = vec![]; + let mut f = Function::new(locals); + f.instruction(&Instruction::Unreachable); + f.instruction(&Instruction::End); - codes.function(&f); - } else { - codes.raw(&code_section.data[f.range().start..f.range().end]); - } - Ok(()) - }) - .collect::>>()?; + codes.function(&f); + } else { + codes.raw(&code_section.data[f.range().start..f.range().end]); + } + } Ok(Box::new(std::iter::once(Ok(config .info() diff --git a/crates/wasm-mutate/src/mutators/modify_const_exprs.rs b/crates/wasm-mutate/src/mutators/modify_const_exprs.rs index 60c67b159a..6ef54f7e0b 100644 --- a/crates/wasm-mutate/src/mutators/modify_const_exprs.rs +++ b/crates/wasm-mutate/src/mutators/modify_const_exprs.rs @@ -1,7 +1,7 @@ //! This mutator modifies the constant initializer expressions between various valid forms in //! entities which require constant initializers. -use crate::mutators::translate::{self, ConstExprKind, Item, Translator}; +use crate::mutators::translate::{self, ConstExprKind, DefaultTranslator, Item, Translator}; use crate::{Error, Mutator, Result}; use rand::Rng; use wasm_encoder::{ElementSection, GlobalSection}; @@ -91,7 +91,7 @@ impl<'cfg, 'wasm> Translator for InitTranslator<'cfg, 'wasm> { // as other values may not necessarily be valid (e.g. maximum table size is limited) let is_element_offset = matches!(kind, ConstExprKind::ElementOffset); let should_zero = is_element_offset || self.config.rng().gen::() & 0b11 == 0; - match ty { + match *ty { T::I32 if should_zero => CE::i32_const(0), T::I64 if should_zero => CE::i64_const(0), T::V128 if should_zero => CE::v128_const(0), @@ -124,8 +124,9 @@ impl<'cfg, 'wasm> Translator for InitTranslator<'cfg, 'wasm> { } else { f64::from_bits(self.config.rng().gen()) }), - T::FuncRef => CE::ref_null(wasm_encoder::ValType::FuncRef), - T::ExternRef => CE::ref_null(wasm_encoder::ValType::ExternRef), + T::FUNCREF => CE::ref_null(wasm_encoder::HeapType::Func), + T::EXTERNREF => CE::ref_null(wasm_encoder::HeapType::Extern), + T::Ref(_) => unimplemented!(), } } else { // FIXME: implement non-reducing mutations for constant expressions. @@ -139,7 +140,7 @@ impl<'cfg, 'wasm> Translator for InitTranslator<'cfg, 'wasm> { impl Mutator for ConstExpressionMutator { fn mutate<'a>( - self, + &self, config: &'a mut crate::WasmMutate, ) -> crate::Result> + 'a>> { let translator_kind = match self { @@ -154,24 +155,20 @@ impl Mutator for ConstExpressionMutator { let mutate_idx = config.rng().gen_range(0..num_total); let section = config.info().globals.ok_or(skip_err)?; let mut new_section = GlobalSection::new(); - let mut reader = - GlobalSectionReader::new(config.info().raw_sections[section].data, 0)?; + let reader = GlobalSectionReader::new(config.info().raw_sections[section].data, 0)?; let mut translator = InitTranslator { config, skip_inits: 0, kind: translator_kind, }; - for idx in 0..reader.get_count() { + for (idx, global) in reader.into_iter().enumerate() { translator.config.consume_fuel(1)?; - let start = reader.original_position(); - let global = reader.read()?; - let end = reader.original_position(); - if idx == mutate_idx { + let global = global?; + if idx as u32 == mutate_idx { log::trace!("Modifying global at index {}...", idx); translator.translate_global(global, &mut new_section)?; } else { - let old_section = &translator.config.info().raw_sections[section]; - new_section.raw(&old_section.data[start..end]); + DefaultTranslator.translate_global(global, &mut new_section)?; } } let new_module = config.info().replace_section(section, &new_section); @@ -182,23 +179,24 @@ impl Mutator for ConstExpressionMutator { let mutate_idx = config.rng().gen_range(0..num_total); let section = config.info().elements.ok_or(skip_err)?; let mut new_section = ElementSection::new(); - let mut reader = + let reader = ElementSectionReader::new(config.info().raw_sections[section].data, 0)?; let mut translator = InitTranslator { config, skip_inits: 0, kind: translator_kind, }; - for idx in 0..reader.get_count() { + for (idx, element) in reader.into_iter().enumerate() { translator.config.consume_fuel(1)?; - let start = reader.original_position(); - let element = reader.read()?; - let end = reader.original_position(); - if idx == mutate_idx { + let element = element?; + if idx as u32 == mutate_idx { if let Self::ElementFunc = self { // Pick a specific element item to mutate. We do this through an option // to skip a specific number of activations of the Translator methods. - let item_count = element.items.get_items_reader()?.get_count(); + let item_count = match &element.items { + wasmparser::ElementItems::Functions(r) => r.count(), + wasmparser::ElementItems::Expressions(_, r) => r.count(), + }; if item_count > 0 { let skip = translator.config.rng().gen_range(0..item_count); translator.skip_inits = skip @@ -214,8 +212,7 @@ impl Mutator for ConstExpressionMutator { ); translator.translate_element(element, &mut new_section)?; } else { - let old_section = &translator.config.info().raw_sections[section]; - new_section.raw(&old_section.data[start..end]); + DefaultTranslator.translate_element(element, &mut new_section)?; } } let new_module = config.info().replace_section(section, &new_section); @@ -290,9 +287,9 @@ mod tests { #[test] fn reduce_elem_funcref() { match_reduction( - r#"(module (table 0 funcref) (elem $a $b) (func $a) (func $b))"#, + r#"(module (table 0 funcref) (elem func $a $b) (func $a) (func $b))"#, super::ConstExpressionMutator::ElementFunc, - r#"(module (table 0 funcref) (elem $a $a) (func $a) (func $b))"#, + r#"(module (table 0 funcref) (elem func $a $a) (func $a) (func $b))"#, ); } diff --git a/crates/wasm-mutate/src/mutators/modify_data.rs b/crates/wasm-mutate/src/mutators/modify_data.rs index bbc998e6cf..5587050aee 100644 --- a/crates/wasm-mutate/src/mutators/modify_data.rs +++ b/crates/wasm-mutate/src/mutators/modify_data.rs @@ -14,19 +14,19 @@ pub struct ModifyDataMutator { impl Mutator for ModifyDataMutator { fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, ) -> Result> + 'a>> { let mut new_section = DataSection::new(); - let mut reader = DataSectionReader::new(config.info().get_data_section().data, 0)?; + let reader = DataSectionReader::new(config.info().get_data_section().data, 0)?; // Select an arbitrary data segment to modify. - let data_to_modify = config.rng().gen_range(0..reader.get_count()); + let data_to_modify = config.rng().gen_range(0..reader.count()); // Iterate over all data segments in the old data section and re-add // them to the `new_section` one-by-one. - for i in 0..reader.get_count() { - let data = reader.read()?; + for (i, data) in reader.into_iter().enumerate() { + let data = data?; let offset; // Preserve the mode of the data segment let mode = match &data.kind { @@ -49,7 +49,7 @@ impl Mutator for ModifyDataMutator { // If this is the correct data segment apply the mutation, // otherwise preserve the data. let mut data = data.data.to_vec(); - if i == data_to_modify { + if i as u32 == data_to_modify { config.raw_mutate(&mut data, self.max_data_size)?; } new_section.segment(DataSegment { mode, data }); diff --git a/crates/wasm-mutate/src/mutators/peephole.rs b/crates/wasm-mutate/src/mutators/peephole.rs index c2ea89a674..9110da9a2c 100644 --- a/crates/wasm-mutate/src/mutators/peephole.rs +++ b/crates/wasm-mutate/src/mutators/peephole.rs @@ -33,10 +33,10 @@ use self::{ lang::*, }, }; -use super::{Mutator, OperatorAndByteOffset}; +use super::{DefaultTranslator, Mutator, OperatorAndByteOffset, Translator}; use crate::{ module::{map_type, PrimitiveTypeInfo}, - Error, ModuleInfo, Result, WasmMutate, + Error, ErrorKind, ModuleInfo, Result, WasmMutate, }; use egg::{Rewrite, Runner}; use rand::{prelude::SmallRng, Rng}; @@ -56,7 +56,7 @@ type EG = egg::EGraph; impl PeepholeMutator { /// Initializes a new PeepholeMutator with fuel - pub fn new(max_depth: u32) -> Self { + pub const fn new(max_depth: u32) -> Self { PeepholeMutator { max_tree_depth: max_depth, rules: None, @@ -102,44 +102,26 @@ impl PeepholeMutator { } } - fn copy_locals(&self, reader: FunctionBody) -> Result { - // Create the new function - let mut localreader = reader.get_locals_reader()?; - // Get current locals and map to encoder types - let mut local_count = 0; - let current_locals = (0..localreader.get_count()) - .map(|_| { - let (count, ty) = localreader.read().unwrap(); - local_count += count; - (count, map_type(ty).unwrap()) - }) - .collect::>(); - - Ok(Function::new(current_locals /*copy locals here*/)) - } - fn random_mutate<'a>( - self, + &self, config: &'a mut WasmMutate, rules: &[Rewrite], ) -> Result> + 'a>> { let code_section = config.info().get_code_section(); - let mut sectionreader = CodeSectionReader::new(code_section.data, 0)?; - let function_count = sectionreader.get_count(); + let sectionreader = CodeSectionReader::new(code_section.data, 0)?; + let function_count = sectionreader.count(); let mut function_to_mutate = config.rng().gen_range(0..function_count); let mut visited_functions = 0; - let readers = (0..function_count) - .map(|_| sectionreader.read().unwrap()) - .collect::>(); + let readers = sectionreader.into_iter().collect::, _>>()?; loop { if visited_functions == function_count { return Err(Error::no_mutations_applicable()); } - let reader = readers[function_to_mutate as usize]; + let reader = readers[function_to_mutate as usize].clone(); let mut operatorreader = reader.get_operators_reader()?; operatorreader.allow_memarg64(true); let mut localsreader = reader.get_locals_reader()?; @@ -229,8 +211,6 @@ impl PeepholeMutator { // In theory this will return the Id of the operator eterm let root = egraph.add_expr(&start); let startcmp = start.clone(); - // Since this construction is expensive then more fuel is consumed - let config4fuel = config.clone(); // If the number of nodes in the egraph is not large, then // continue the search @@ -274,7 +254,9 @@ impl PeepholeMutator { .map(move |expr| { log::trace!("Yielding expression:\n{}", expr.pretty(60)); - let mut newfunc = self.copy_locals(reader)?; + config.consume_fuel(1)?; + + let mut newfunc = copy_locals(reader.clone())?; let needed_resources = Encoder::build_function( config, opcode_to_mutate, @@ -288,14 +270,14 @@ impl PeepholeMutator { let mut codes = CodeSection::new(); let code_section = config.info().get_code_section(); - let mut sectionreader = CodeSectionReader::new(code_section.data, 0)?; + let sectionreader = CodeSectionReader::new(code_section.data, 0)?; // this mutator is applicable to internal functions, so // it starts by randomly selecting an index between // the imported functions and the total count, total=imported + internal - for fidx in 0..config.info().num_local_functions() { - let reader = sectionreader.read()?; - if fidx == function_to_mutate { + for (fidx, func) in sectionreader.into_iter().enumerate() { + let reader = func?; + if fidx as u32 == function_to_mutate { codes.function(&newfunc); } else { codes.raw( @@ -312,17 +294,10 @@ impl PeepholeMutator { // If the global section was already there, try to copy it to the // new raw section let global_section = config.info().get_global_section(); - let mut globalreader = - GlobalSectionReader::new(global_section.data, 0)?; - let count = globalreader.get_count(); - let mut start = globalreader.original_position(); - - for _ in 0..count { - let _ = globalreader.read()?; - let current_pos = globalreader.original_position(); - let global = &global_section.data[start..current_pos]; - new_global_section.raw(global); - start = current_pos; + let globalreader = GlobalSectionReader::new(global_section.data, 0)?; + + for g in globalreader { + DefaultTranslator.translate_global(g?, &mut new_global_section)?; } } @@ -407,21 +382,41 @@ impl PeepholeMutator { false }, ); + Ok(module) }) - // Consume fuel for each returned expression and it is expensive - .take_while(move |_| config4fuel.consume_fuel(1).is_ok()); + .map_while(|module: Result| match module { + Ok(module) => Some(Ok(module)), + Err(e) if matches!(e.kind(), ErrorKind::OutOfFuel) => None, + Err(e) => Some(Err(e)), + }); return Ok(Box::new(iterator)); } function_to_mutate = (function_to_mutate + 1) % function_count; visited_functions += 1; } + + fn copy_locals(reader: FunctionBody) -> Result { + // Create the new function + let mut localreader = reader.get_locals_reader()?; + // Get current locals and map to encoder types + let mut local_count = 0; + let current_locals = (0..localreader.get_count()) + .map(|_| { + let (count, ty) = localreader.read().unwrap(); + local_count += count; + (count, map_type(ty).unwrap()) + }) + .collect::>(); + + Ok(Function::new(current_locals /*copy locals here*/)) + } } /// To separate the methods will allow us to test rule by rule fn mutate_with_rules<'a>( - self, + &self, config: &'a mut WasmMutate, rules: &[Rewrite], ) -> Result> + 'a>> { @@ -432,7 +427,7 @@ impl PeepholeMutator { /// Meta mutator for peephole impl Mutator for PeepholeMutator { fn mutate<'a>( - self, + &self, config: &'a mut crate::WasmMutate, ) -> Result> + 'a>> { let rules = match self.rules.clone() { @@ -574,6 +569,7 @@ mod tests { /// Condition to apply the unfold operator /// check that the var is a constant + #[allow(dead_code)] fn is_const(vari: &'static str) -> impl Fn(&mut EG, Id, &Subst) -> bool { move |egraph: &mut EG, _, subst| { let var = vari.parse(); @@ -613,7 +609,11 @@ mod tests { } } + // Random numbers vary by pointer-width presumably due to `usize` at some + // point factoring in, and this test is only known to pass within a + // reasonable amount of time on 64-bit platforms. #[test] + #[cfg(target_pointer_width = "64")] fn test_peep_unfold2() { let rules: &[Rewrite] = &[ rewrite!("unfold-2"; "?x" => "(i32.unfold ?x)" if is_const("?x") if is_type("?x", PrimitiveTypeInfo::I32)), @@ -633,8 +633,8 @@ mod tests { (type (;0;) (func (result i32))) (func (;0;) (type 0) (result i32) (local i32 i32) - i32.const -1985698784 - i32.const 1985698840 + i32.const 1697131274 + i32.const -1697131218 i32.add) (export "exported_func" (func 0))) "#, @@ -1593,7 +1593,7 @@ mod tests { seed: u64, ) { let mut config = WasmMutate::default(); - config.fuel(300); + config.fuel(10000); config.seed(seed); let mutator = PeepholeMutator::new_with_rules(3, rules.to_vec()); diff --git a/crates/wasm-mutate/src/mutators/peephole/dfg.rs b/crates/wasm-mutate/src/mutators/peephole/dfg.rs index 2d24225c0d..8934d11824 100644 --- a/crates/wasm-mutate/src/mutators/peephole/dfg.rs +++ b/crates/wasm-mutate/src/mutators/peephole/dfg.rs @@ -663,15 +663,15 @@ impl<'a> DFGBuilder { self.push_node(Lang::TableSize(*table), idx); } - Operator::DataDrop { segment } => { - self.empty_node(Lang::DataDrop(*segment), idx); + Operator::DataDrop { data_index } => { + self.empty_node(Lang::DataDrop(*data_index), idx); } - Operator::ElemDrop { segment } => { - self.empty_node(Lang::ElemDrop(*segment), idx); + Operator::ElemDrop { elem_index } => { + self.empty_node(Lang::ElemDrop(*elem_index), idx); } - Operator::MemoryInit { mem, segment } => { + Operator::MemoryInit { mem, data_index } => { let a = Id::from(self.pop_operand(idx, false)); let b = Id::from(self.pop_operand(idx, false)); let c = Id::from(self.pop_operand(idx, false)); @@ -679,22 +679,22 @@ impl<'a> DFGBuilder { Lang::MemoryInit( MemoryInit { memory: *mem, - segment: *segment, + segment: *data_index, }, [c, b, a], ), idx, ); } - Operator::MemoryCopy { src, dst } => { + Operator::MemoryCopy { src_mem, dst_mem } => { let a = Id::from(self.pop_operand(idx, false)); let b = Id::from(self.pop_operand(idx, false)); let c = Id::from(self.pop_operand(idx, false)); self.empty_node( Lang::MemoryCopy( MemoryCopy { - src: *src, - dst: *dst, + src: *src_mem, + dst: *dst_mem, }, [c, b, a], ), @@ -709,7 +709,7 @@ impl<'a> DFGBuilder { self.empty_node(Lang::MemoryFill(*mem, [c, b, a]), idx); } - Operator::TableInit { table, segment } => { + Operator::TableInit { table, elem_index } => { let a = Id::from(self.pop_operand(idx, false)); let b = Id::from(self.pop_operand(idx, false)); let c = Id::from(self.pop_operand(idx, false)); @@ -717,7 +717,7 @@ impl<'a> DFGBuilder { Lang::TableInit( TableInit { table: *table, - segment: *segment, + segment: *elem_index, }, [c, b, a], ), @@ -762,15 +762,18 @@ impl<'a> DFGBuilder { } Operator::RefNull { - ty: wasmparser::ValType::ExternRef, + hty: wasmparser::HeapType::Extern, } => { self.push_node(Lang::RefNull(RefType::Extern), idx); } Operator::RefNull { - ty: wasmparser::ValType::FuncRef, + hty: wasmparser::HeapType::Func, } => { self.push_node(Lang::RefNull(RefType::Func), idx); } + Operator::RefNull { .. } => { + unimplemented!() + } Operator::RefFunc { function_index } => { self.push_node(Lang::RefFunc(*function_index), idx); } @@ -945,7 +948,7 @@ impl<'a> DFGBuilder { Operator::I8x16MinU => self.binop(idx, Lang::I8x16MinU), Operator::I8x16MaxS => self.binop(idx, Lang::I8x16MaxS), Operator::I8x16MaxU => self.binop(idx, Lang::I8x16MaxU), - Operator::I8x16RoundingAverageU => self.binop(idx, Lang::I8x16AvgrU), + Operator::I8x16AvgrU => self.binop(idx, Lang::I8x16AvgrU), Operator::I16x8ExtAddPairwiseI8x16S => { self.unop(idx, Lang::I16x8ExtAddPairwiseI8x16S) @@ -978,7 +981,7 @@ impl<'a> DFGBuilder { Operator::I16x8MinU => self.binop(idx, Lang::I16x8MinU), Operator::I16x8MaxS => self.binop(idx, Lang::I16x8MaxS), Operator::I16x8MaxU => self.binop(idx, Lang::I16x8MaxU), - Operator::I16x8RoundingAverageU => self.binop(idx, Lang::I16x8AvgrU), + Operator::I16x8AvgrU => self.binop(idx, Lang::I16x8AvgrU), Operator::I16x8ExtMulLowI8x16S => self.binop(idx, Lang::I16x8ExtMulLowI8x16S), Operator::I16x8ExtMulHighI8x16S => self.binop(idx, Lang::I16x8ExtMulHighI8x16S), Operator::I16x8ExtMulLowI8x16U => self.binop(idx, Lang::I16x8ExtMulLowI8x16U), diff --git a/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder/expr2wasm.rs b/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder/expr2wasm.rs index 822c39a51a..65f5a3522a 100644 --- a/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder/expr2wasm.rs +++ b/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder/expr2wasm.rs @@ -106,16 +106,16 @@ pub fn expr2wasm( Lang::I64Load(memarg, _) => insn(Instruction::I64Load(memarg.into())), Lang::F32Load(memarg, _) => insn(Instruction::F32Load(memarg.into())), Lang::F64Load(memarg, _) => insn(Instruction::F64Load(memarg.into())), - Lang::I32Load8U(memarg, _) => insn(Instruction::I32Load8_U(memarg.into())), - Lang::I32Load8S(memarg, _) => insn(Instruction::I32Load8_S(memarg.into())), - Lang::I32Load16U(memarg, _) => insn(Instruction::I32Load16_U(memarg.into())), - Lang::I32Load16S(memarg, _) => insn(Instruction::I32Load16_S(memarg.into())), - Lang::I64Load8U(memarg, _) => insn(Instruction::I64Load8_U(memarg.into())), - Lang::I64Load8S(memarg, _) => insn(Instruction::I64Load8_S(memarg.into())), - Lang::I64Load16U(memarg, _) => insn(Instruction::I64Load16_U(memarg.into())), - Lang::I64Load16S(memarg, _) => insn(Instruction::I64Load16_S(memarg.into())), - Lang::I64Load32U(memarg, _) => insn(Instruction::I64Load32_U(memarg.into())), - Lang::I64Load32S(memarg, _) => insn(Instruction::I64Load32_S(memarg.into())), + Lang::I32Load8U(memarg, _) => insn(Instruction::I32Load8U(memarg.into())), + Lang::I32Load8S(memarg, _) => insn(Instruction::I32Load8S(memarg.into())), + Lang::I32Load16U(memarg, _) => insn(Instruction::I32Load16U(memarg.into())), + Lang::I32Load16S(memarg, _) => insn(Instruction::I32Load16S(memarg.into())), + Lang::I64Load8U(memarg, _) => insn(Instruction::I64Load8U(memarg.into())), + Lang::I64Load8S(memarg, _) => insn(Instruction::I64Load8S(memarg.into())), + Lang::I64Load16U(memarg, _) => insn(Instruction::I64Load16U(memarg.into())), + Lang::I64Load16S(memarg, _) => insn(Instruction::I64Load16S(memarg.into())), + Lang::I64Load32U(memarg, _) => insn(Instruction::I64Load32U(memarg.into())), + Lang::I64Load32S(memarg, _) => insn(Instruction::I64Load32S(memarg.into())), Lang::RandI32 => insn(Instruction::I32Const(config.rng().gen())), Lang::RandI64 => insn(Instruction::I64Const(config.rng().gen())), Lang::RandF32 => { @@ -328,13 +328,13 @@ pub fn expr2wasm( Lang::MemoryInit(init, _) => { newfunc.instruction(&Instruction::MemoryInit { mem: init.memory, - data: init.segment, + data_index: init.segment, }); } Lang::MemoryCopy(cp, _) => { newfunc.instruction(&Instruction::MemoryCopy { - src: cp.src, - dst: cp.dst, + src_mem: cp.src, + dst_mem: cp.dst, }); } Lang::MemoryFill(mem, _) => insn(Instruction::MemoryFill(*mem)), @@ -342,21 +342,21 @@ pub fn expr2wasm( Lang::TableInit(init, _) => { newfunc.instruction(&Instruction::TableInit { table: init.table, - segment: init.segment, + elem_index: init.segment, }); } Lang::TableCopy(cp, _) => { newfunc.instruction(&Instruction::TableCopy { - src: cp.src, - dst: cp.dst, + src_table: cp.src, + dst_table: cp.dst, }); } - Lang::TableFill(table, _) => insn(Instruction::TableFill { table: *table }), - Lang::ElemDrop(idx) => insn(Instruction::ElemDrop { segment: *idx }), - Lang::TableGrow(table, _) => insn(Instruction::TableGrow { table: *table }), - Lang::TableSize(table) => insn(Instruction::TableSize { table: *table }), - Lang::TableGet(table, _) => insn(Instruction::TableGet { table: *table }), - Lang::TableSet(table, _) => insn(Instruction::TableSet { table: *table }), + Lang::TableFill(table, _) => insn(Instruction::TableFill(*table)), + Lang::ElemDrop(idx) => insn(Instruction::ElemDrop(*idx)), + Lang::TableGrow(table, _) => insn(Instruction::TableGrow(*table)), + Lang::TableSize(table) => insn(Instruction::TableSize(*table)), + Lang::TableGet(table, _) => insn(Instruction::TableGet(*table)), + Lang::TableSet(table, _) => insn(Instruction::TableSet(*table)), Lang::I32UseGlobal(_) => { // Request a new global let request = ResourceRequest::Global { @@ -419,74 +419,46 @@ pub fn expr2wasm( Lang::V128Bitselect(_) => insn(Instruction::V128Bitselect), Lang::V128Load(memarg, _) => { - newfunc.instruction(&Instruction::V128Load { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load(memarg.into())); } Lang::V128Load8x8S(memarg, _) => { - newfunc.instruction(&Instruction::V128Load8x8S { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load8x8S(memarg.into())); } Lang::V128Load8x8U(memarg, _) => { - newfunc.instruction(&Instruction::V128Load8x8U { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load8x8U(memarg.into())); } Lang::V128Load16x4S(memarg, _) => { - newfunc.instruction(&Instruction::V128Load16x4S { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load16x4S(memarg.into())); } Lang::V128Load16x4U(memarg, _) => { - newfunc.instruction(&Instruction::V128Load16x4U { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load16x4U(memarg.into())); } Lang::V128Load32x2S(memarg, _) => { - newfunc.instruction(&Instruction::V128Load32x2S { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load32x2S(memarg.into())); } Lang::V128Load32x2U(memarg, _) => { - newfunc.instruction(&Instruction::V128Load32x2U { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load32x2U(memarg.into())); } Lang::V128Load8Splat(memarg, _) => { - newfunc.instruction(&Instruction::V128Load8Splat { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load8Splat(memarg.into())); } Lang::V128Load16Splat(memarg, _) => { - newfunc.instruction(&Instruction::V128Load16Splat { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load16Splat(memarg.into())); } Lang::V128Load32Splat(memarg, _) => { - newfunc.instruction(&Instruction::V128Load32Splat { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load32Splat(memarg.into())); } Lang::V128Load64Splat(memarg, _) => { - newfunc.instruction(&Instruction::V128Load64Splat { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load64Splat(memarg.into())); } Lang::V128Load32Zero(memarg, _) => { - newfunc.instruction(&Instruction::V128Load32Zero { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load32Zero(memarg.into())); } Lang::V128Load64Zero(memarg, _) => { - newfunc.instruction(&Instruction::V128Load64Zero { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Load64Zero(memarg.into())); } Lang::V128Store(memarg, _) => { - newfunc.instruction(&Instruction::V128Store { - memarg: memarg.into(), - }); + newfunc.instruction(&Instruction::V128Store(memarg.into())); } Lang::V128Load8Lane(memarg, _) => { newfunc.instruction(&Instruction::V128Load8Lane { @@ -537,48 +509,20 @@ pub fn expr2wasm( }); } - Lang::I8x16ExtractLaneS(lane, _) => { - insn(Instruction::I8x16ExtractLaneS { lane: *lane }) - } - Lang::I8x16ExtractLaneU(lane, _) => { - insn(Instruction::I8x16ExtractLaneU { lane: *lane }) - } - Lang::I8x16ReplaceLane(lane, _) => { - insn(Instruction::I8x16ReplaceLane { lane: *lane }) - } - Lang::I16x8ExtractLaneS(lane, _) => { - insn(Instruction::I16x8ExtractLaneS { lane: *lane }) - } - Lang::I16x8ExtractLaneU(lane, _) => { - insn(Instruction::I16x8ExtractLaneU { lane: *lane }) - } - Lang::I16x8ReplaceLane(lane, _) => { - insn(Instruction::I16x8ReplaceLane { lane: *lane }) - } - Lang::I32x4ExtractLane(lane, _) => { - insn(Instruction::I32x4ExtractLane { lane: *lane }) - } - Lang::I32x4ReplaceLane(lane, _) => { - insn(Instruction::I32x4ReplaceLane { lane: *lane }) - } - Lang::I64x2ExtractLane(lane, _) => { - insn(Instruction::I64x2ExtractLane { lane: *lane }) - } - Lang::I64x2ReplaceLane(lane, _) => { - insn(Instruction::I64x2ReplaceLane { lane: *lane }) - } - Lang::F32x4ExtractLane(lane, _) => { - insn(Instruction::F32x4ExtractLane { lane: *lane }) - } - Lang::F32x4ReplaceLane(lane, _) => { - insn(Instruction::F32x4ReplaceLane { lane: *lane }) - } - Lang::F64x2ExtractLane(lane, _) => { - insn(Instruction::F64x2ExtractLane { lane: *lane }) - } - Lang::F64x2ReplaceLane(lane, _) => { - insn(Instruction::F64x2ReplaceLane { lane: *lane }) - } + Lang::I8x16ExtractLaneS(lane, _) => insn(Instruction::I8x16ExtractLaneS(*lane)), + Lang::I8x16ExtractLaneU(lane, _) => insn(Instruction::I8x16ExtractLaneU(*lane)), + Lang::I8x16ReplaceLane(lane, _) => insn(Instruction::I8x16ReplaceLane(*lane)), + Lang::I16x8ExtractLaneS(lane, _) => insn(Instruction::I16x8ExtractLaneS(*lane)), + Lang::I16x8ExtractLaneU(lane, _) => insn(Instruction::I16x8ExtractLaneU(*lane)), + Lang::I16x8ReplaceLane(lane, _) => insn(Instruction::I16x8ReplaceLane(*lane)), + Lang::I32x4ExtractLane(lane, _) => insn(Instruction::I32x4ExtractLane(*lane)), + Lang::I32x4ReplaceLane(lane, _) => insn(Instruction::I32x4ReplaceLane(*lane)), + Lang::I64x2ExtractLane(lane, _) => insn(Instruction::I64x2ExtractLane(*lane)), + Lang::I64x2ReplaceLane(lane, _) => insn(Instruction::I64x2ReplaceLane(*lane)), + Lang::F32x4ExtractLane(lane, _) => insn(Instruction::F32x4ExtractLane(*lane)), + Lang::F32x4ReplaceLane(lane, _) => insn(Instruction::F32x4ReplaceLane(*lane)), + Lang::F64x2ExtractLane(lane, _) => insn(Instruction::F64x2ExtractLane(*lane)), + Lang::F64x2ReplaceLane(lane, _) => insn(Instruction::F64x2ReplaceLane(*lane)), Lang::I8x16Swizzle(_) => insn(Instruction::I8x16Swizzle), Lang::I8x16Splat(_) => insn(Instruction::I8x16Splat), @@ -657,7 +601,7 @@ pub fn expr2wasm( Lang::I8x16MinU(_) => insn(Instruction::I8x16MinU), Lang::I8x16MaxS(_) => insn(Instruction::I8x16MaxS), Lang::I8x16MaxU(_) => insn(Instruction::I8x16MaxU), - Lang::I8x16AvgrU(_) => insn(Instruction::I8x16RoundingAverageU), + Lang::I8x16AvgrU(_) => insn(Instruction::I8x16AvgrU), Lang::I16x8ExtAddPairwiseI8x16S(_) => { insn(Instruction::I16x8ExtAddPairwiseI8x16S) @@ -690,7 +634,7 @@ pub fn expr2wasm( Lang::I16x8MinU(_) => insn(Instruction::I16x8MinU), Lang::I16x8MaxS(_) => insn(Instruction::I16x8MaxS), Lang::I16x8MaxU(_) => insn(Instruction::I16x8MaxU), - Lang::I16x8AvgrU(_) => insn(Instruction::I16x8RoundingAverageU), + Lang::I16x8AvgrU(_) => insn(Instruction::I16x8AvgrU), Lang::I16x8ExtMulLowI8x16S(_) => insn(Instruction::I16x8ExtMulLowI8x16S), Lang::I16x8ExtMulHighI8x16S(_) => insn(Instruction::I16x8ExtMulHighI8x16S), Lang::I16x8ExtMulLowI8x16U(_) => insn(Instruction::I16x8ExtMulLowI8x16U), diff --git a/crates/wasm-mutate/src/mutators/peephole/eggsy/lang.rs b/crates/wasm-mutate/src/mutators/peephole/eggsy/lang.rs index f0257f0f8e..b1b77f274f 100644 --- a/crates/wasm-mutate/src/mutators/peephole/eggsy/lang.rs +++ b/crates/wasm-mutate/src/mutators/peephole/eggsy/lang.rs @@ -4,7 +4,7 @@ use egg::Id; use std::convert::TryInto; use std::fmt::{self, Display}; use std::str::FromStr; -use wasm_encoder::ValType; +use wasm_encoder::HeapType; /// This is a macro used to define the `Lang` enum. /// @@ -1070,11 +1070,11 @@ pub enum RefType { Extern, } -impl From for ValType { +impl From for HeapType { fn from(rt: RefType) -> Self { match rt { - RefType::Func => ValType::FuncRef, - RefType::Extern => ValType::ExternRef, + RefType::Func => HeapType::Func, + RefType::Extern => HeapType::Extern, } } } diff --git a/crates/wasm-mutate/src/mutators/peephole/rules.rs b/crates/wasm-mutate/src/mutators/peephole/rules.rs index 1c247cc2f0..8a5c92cf27 100644 --- a/crates/wasm-mutate/src/mutators/peephole/rules.rs +++ b/crates/wasm-mutate/src/mutators/peephole/rules.rs @@ -15,180 +15,187 @@ use super::{ impl PeepholeMutator { /// Returns the rewriting rules. /// - /// Define new fules here for the peephole mutator. + /// Define new rules here for the peephole mutator. pub fn get_rules(&self, config: &WasmMutate) -> Vec> { let mut rules = vec![]; - // Various identities. + macro_rules! rewrite { + ($name:tt; $lhs:tt => $rhs:tt $(if $cond:expr)*) => { + self.add_rewrite(&mut rules, $name, $lhs, $rhs, rewrite!(@cond $($cond)*)); + }; + ($name:tt; $lhs:tt <=> $rhs:tt $(if $cond:expr)*) => { + self.add_bidirectional_rewrite(&mut rules, $name, $lhs, $rhs, rewrite!(@cond $($cond)*)); + }; + + (@cond $($cond:expr)*) => (&[$($cond),*]); + } + + //// Various identities. if config.reduce { // NB: these only go one way when we are reducing. - rules.extend(vec![ - rewrite!("i32.or--1"; "(i32.or ?x i32.const.-1)" => "i32.const.-1"), - rewrite!("i64.or--1"; "(i64.or ?x i64.const.-1)" => "i64.const.-1"), - rewrite!("i32.or-x-x"; "(i32.or ?x ?x)" => "?x"), - rewrite!("i64.or-x-x"; "(i64.or ?x ?x)" => "?x"), - rewrite!("i32.and-x-x"; "(i32.and ?x ?x)" => "?x"), - rewrite!("i64.and-x-x"; "(i64.and ?x ?x)" => "?x"), - rewrite!("select-same-branches"; "(select ?y ?y ?x)" => "?y"), - rewrite!("i32.sub-0"; "(i32.sub ?x i32.const.0)" => "?x"), - rewrite!("i64.sub-0"; "(i64.sub ?x i64.const.0)" => "?x"), - rewrite!("i32.mul-x-1"; "(i32.mul ?x i32.const.1)" => "?x"), - rewrite!("i64.mul-x-1"; "(i64.mul ?x i64.const.1)" => "?x"), - rewrite!("f32.mul-x-1"; "(f32.mul ?x f32.const.1,0)" => "?x"), - rewrite!("f64.mul-x-1"; "(f64.mul ?x f64.const.1,0)" => "?x"), - rewrite!("i32.add-x-0"; "(i32.add ?x i32.const.0)" => "?x"), - rewrite!("i64.add-x-0"; "(i64.add ?x i64.const.0)" => "?x"), - rewrite!("f32-add-x-0"; "(f32.add ?x f32.const.0,0)" => "?x"), - rewrite!("f64.add-x-0"; "(f64.add ?x f64.const.0,0)" => "?x"), - rewrite!("i32.xor-x-0"; "(i32.xor ?x i32.const.0)" => "?x"), - rewrite!("i64.xor-x-0"; "(i64.xor ?x i64.const.0)" => "?x"), - rewrite!("i32.eq-x-0"; "(i32.eq ?x i32.const.0)" => "(i32.eqz ?x)"), - rewrite!("i64.eq-x-0"; "(i64.eq ?x i64.const.0)" => "(i64.eqz ?x)"), - rewrite!("i32.shl-by-0"; "(i32.shl ?x i32.const.0)" => "?x"), - rewrite!("i64.shl-by-0"; "(i64.shl ?x i64.const.0)" => "?x"), - rewrite!("i32.shr_u-by-0"; "(i32.shr_u ?x i32.const.0)" => "?x"), - rewrite!("i64.shr_u-by-0"; "(i64.shr_u ?x i64.const.0)" => "?x"), - rewrite!("i32.shr_s-by-0"; "(i32.shr_s ?x i32.const.0)" => "?x"), - rewrite!("i64.shr_s-by-0"; "(i64.shr_s ?x i64.const.0)" => "?x"), - ]); + rewrite!("i32.or--1"; "(i32.or ?x i32.const.-1)" => "i32.const.-1"); + rewrite!("i64.or--1"; "(i64.or ?x i64.const.-1)" => "i64.const.-1"); + rewrite!("i32.or-x-x"; "(i32.or ?x ?x)" => "?x"); + rewrite!("i64.or-x-x"; "(i64.or ?x ?x)" => "?x"); + rewrite!("i32.and-x-x"; "(i32.and ?x ?x)" => "?x"); + rewrite!("i64.and-x-x"; "(i64.and ?x ?x)" => "?x"); + rewrite!("select-same-branches"; "(select ?y ?y ?x)" => "?y"); + rewrite!("i32.sub-0"; "(i32.sub ?x i32.const.0)" => "?x"); + rewrite!("i64.sub-0"; "(i64.sub ?x i64.const.0)" => "?x"); + rewrite!("i32.mul-x-1"; "(i32.mul ?x i32.const.1)" => "?x"); + rewrite!("i64.mul-x-1"; "(i64.mul ?x i64.const.1)" => "?x"); + rewrite!("f32.mul-x-1"; "(f32.mul ?x f32.const.1,0)" => "?x"); + rewrite!("f64.mul-x-1"; "(f64.mul ?x f64.const.1,0)" => "?x"); + rewrite!("i32.add-x-0"; "(i32.add ?x i32.const.0)" => "?x"); + rewrite!("i64.add-x-0"; "(i64.add ?x i64.const.0)" => "?x"); + rewrite!("f32-add-x-0"; "(f32.add ?x f32.const.0,0)" => "?x"); + rewrite!("f64.add-x-0"; "(f64.add ?x f64.const.0,0)" => "?x"); + rewrite!("i32.xor-x-0"; "(i32.xor ?x i32.const.0)" => "?x"); + rewrite!("i64.xor-x-0"; "(i64.xor ?x i64.const.0)" => "?x"); + rewrite!("i32.eq-x-0"; "(i32.eq ?x i32.const.0)" => "(i32.eqz ?x)"); + rewrite!("i64.eq-x-0"; "(i64.eq ?x i64.const.0)" => "(i64.eqz ?x)"); + rewrite!("i32.shl-by-0"; "(i32.shl ?x i32.const.0)" => "?x"); + rewrite!("i64.shl-by-0"; "(i64.shl ?x i64.const.0)" => "?x"); + rewrite!("i32.shr_u-by-0"; "(i32.shr_u ?x i32.const.0)" => "?x"); + rewrite!("i64.shr_u-by-0"; "(i64.shr_u ?x i64.const.0)" => "?x"); + rewrite!("i32.shr_s-by-0"; "(i32.shr_s ?x i32.const.0)" => "?x"); + rewrite!("i64.shr_s-by-0"; "(i64.shr_s ?x i64.const.0)" => "?x"); } else { - rules.extend(vec![ - rewrite!("i32.or--1"; "(i32.or ?x i32.const.-1)" => "i32.const.-1"), - rewrite!("i64.or--1"; "(i64.or ?x i64.const.-1)" => "i64.const.-1"), - ]); + rewrite!("i32.or--1"; "(i32.or ?x i32.const.-1)" => "i32.const.-1"); + rewrite!("i64.or--1"; "(i64.or ?x i64.const.-1)" => "i64.const.-1"); - rules.extend(rewrite!( + rewrite!( "i32.or-x-x"; "(i32.or ?x ?x)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.or-x-x"; "(i64.or ?x ?x)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.and-x-x"; "(i32.and ?x ?x)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.and-x-x"; "(i64.and ?x ?x)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); - rules.push(rewrite!("select-same-branches"; "(select ?y ?y ?x)" => "?y")); + rewrite!("select-same-branches"; "(select ?y ?y ?x)" => "?y"); - rules.extend(rewrite!( + rewrite!( "i32.sub-0"; "(i32.sub ?x i32.const.0)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.sub-0"; "(i64.sub ?x i64.const.0)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.mul-x-1"; "?x" <=> "(i32.mul ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.mul-x-1"; "?x" <=> "(i64.mul ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); - rules.extend(rewrite!( + rewrite!( "f32.mul-x-1"; "?x" <=> "(f32.mul ?x f32.const.1,0)" if self.is_type("?x", PrimitiveTypeInfo::F32) - )); - rules.extend(rewrite!( + ); + rewrite!( "f64.mul-x-1"; "?x" <=> "(f64.mul ?x f64.const.1,0)" if self.is_type("?x", PrimitiveTypeInfo::F64) - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.add-x-0"; "?x" <=> "(i32.add ?x i32.const.0)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.add-x-0"; "?x" <=> "(i64.add ?x i64.const.0)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); - rules.extend(rewrite!( + ); + rewrite!( "f32-add-x-0"; "?x" <=> "(f32.add ?x f32.const.0,0)" if self.is_type("?x", PrimitiveTypeInfo::F32) - )); - rules.extend(rewrite!( + ); + rewrite!( "f64.add-x-0"; "?x" <=> "(f64.add ?x f64.const.0,0)" if self.is_type("?x", PrimitiveTypeInfo::F64) - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.xor-x-0"; "?x" <=> "(i32.xor ?x i32.const.0)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.xor-x-0"; "?x" <=> "(i64.xor ?x i64.const.0)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.eq-x-0"; "(i32.eq ?x i32.const.0)" <=> "(i32.eqz ?x)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.eq-x-0"; "(i64.eq ?x i64.const.0)" <=> "(i64.eqz ?x)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.shl-by-0"; "(i32.shl ?x i32.const.0)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.shl-by-0"; "(i64.shl ?x i64.const.0)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.shr_u-by-0"; "(i32.shr_u ?x i32.const.0)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.shr_u-by-0"; "(i64.shr_u ?x i64.const.0)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.shr_s-by-0"; "(i32.shr_s ?x i32.const.0)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.shr_s-by-0"; "(i64.shr_s ?x i64.const.0)" <=> "?x" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); } // A bunch of commutativity rules. @@ -196,207 +203,185 @@ impl PeepholeMutator { // Even though these don't reduce code size themselves, they can help // other rules apply, so we add them even when we aren't just reducing. - rules.extend(rewrite!("i32.add-commutes"; "(i32.add ?x ?y)" <=> "(i32.add ?y ?x)")); - rules.extend(rewrite!("i64.add-commutes"; "(i64.add ?x ?y)" <=> "(i64.add ?y ?x)")); - rules.extend(rewrite!("f32.add-commutes"; "(f32.add ?x ?y)" <=> "(f32.add ?y ?x)")); - rules.extend(rewrite!("f64.add-commutes"; "(f64.add ?x ?y)" <=> "(f64.add ?y ?x)")); + rewrite!("i32.add-commutes"; "(i32.add ?x ?y)" <=> "(i32.add ?y ?x)"); + rewrite!("i64.add-commutes"; "(i64.add ?x ?y)" <=> "(i64.add ?y ?x)"); + rewrite!("f32.add-commutes"; "(f32.add ?x ?y)" <=> "(f32.add ?y ?x)"); + rewrite!("f64.add-commutes"; "(f64.add ?x ?y)" <=> "(f64.add ?y ?x)"); - rules.extend(rewrite!("i32.mul-commutes"; "(i32.mul ?x ?y)" <=> "(i32.mul ?y ?x)" )); - rules.extend(rewrite!("i64.mul-commutes"; "(i64.mul ?x ?y)" <=> "(i64.mul ?y ?x)" )); - rules.extend(rewrite!("f32.mul-commutes"; "(f32.mul ?x ?y)" <=> "(f32.mul ?y ?x)" )); - rules.extend(rewrite!("f64.mul-commutes"; "(f64.mul ?x ?y)" <=> "(f64.mul ?y ?x)" )); + rewrite!("i32.mul-commutes"; "(i32.mul ?x ?y)" <=> "(i32.mul ?y ?x)" ); + rewrite!("i64.mul-commutes"; "(i64.mul ?x ?y)" <=> "(i64.mul ?y ?x)" ); + rewrite!("f32.mul-commutes"; "(f32.mul ?x ?y)" <=> "(f32.mul ?y ?x)" ); + rewrite!("f64.mul-commutes"; "(f64.mul ?x ?y)" <=> "(f64.mul ?y ?x)" ); - rules.extend(rewrite!("i32.and-commutes"; "(i32.and ?x ?y)" <=> "(i32.and ?y ?x)")); - rules.extend(rewrite!("i64.and-commutes"; "(i64.and ?x ?y)" <=> "(i64.and ?y ?x)")); + rewrite!("i32.and-commutes"; "(i32.and ?x ?y)" <=> "(i32.and ?y ?x)"); + rewrite!("i64.and-commutes"; "(i64.and ?x ?y)" <=> "(i64.and ?y ?x)"); - rules.extend(rewrite!("i32.or-commutes"; "(i32.or ?x ?y)" <=> "(i32.or ?y ?x)")); - rules.extend(rewrite!("i64.or-commutes"; "(i64.or ?x ?y)" <=> "(i64.or ?y ?x)")); + rewrite!("i32.or-commutes"; "(i32.or ?x ?y)" <=> "(i32.or ?y ?x)"); + rewrite!("i64.or-commutes"; "(i64.or ?x ?y)" <=> "(i64.or ?y ?x)"); - rules.extend(rewrite!("i32.xor-commutes"; "(i32.xor ?x ?y)" <=> "(i32.xor ?y ?x)")); - rules.extend(rewrite!("i64.xor-commutes"; "(i64.xor ?x ?y)" <=> "(i64.xor ?y ?x)")); + rewrite!("i32.xor-commutes"; "(i32.xor ?x ?y)" <=> "(i32.xor ?y ?x)"); + rewrite!("i64.xor-commutes"; "(i64.xor ?x ?y)" <=> "(i64.xor ?y ?x)"); - rules.extend(rewrite!("i32.eq-commutes"; "(i32.eq ?x ?y)" <=> "(i32.eq ?y ?x)")); - rules.extend(rewrite!("i64.eq-commutes"; "(i64.eq ?x ?y)" <=> "(i64.eq ?y ?x)")); + rewrite!("i32.eq-commutes"; "(i32.eq ?x ?y)" <=> "(i32.eq ?y ?x)"); + rewrite!("i64.eq-commutes"; "(i64.eq ?x ?y)" <=> "(i64.eq ?y ?x)"); // A bunch of associativity rules. // // Even though these don't reduce code size themselves, they can help // other rules apply, so we add them even when we aren't just reducing. - rules.extend(rewrite!( + rewrite!( "i32.mul-associates"; "(i32.mul ?x (i32.mul ?y ?z))" <=> "(i32.mul (i32.mul ?x ?y) ?z)" - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.mul-associates"; "(i64.mul ?x (i64.mul ?y ?z))" <=> "(i64.mul (i64.mul ?x ?y) ?z)" - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.add-associates"; "(i32.add ?x (i32.add ?y ?z))" <=> "(i32.add (i32.add ?x ?y) ?z)" - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.add-associates"; "(i64.add ?x (i64.add ?y ?z))" <=> "(i64.add (i64.add ?x ?y) ?z)" - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.and-associates"; "(i32.and ?x (i32.and ?y ?z))" <=> "(i32.and (i32.and ?x ?y) ?z)" - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.and-associates"; "(i64.and ?x (i64.and ?y ?z))" <=> "(i64.and (i64.and ?x ?y) ?z)" - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.or-associates"; "(i32.or ?x (i32.or ?y ?z))" <=> "(i32.or (i32.or ?x ?y) ?z)" - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.or-associates"; "(i64.or ?x (i64.or ?y ?z))" <=> "(i64.or (i64.or ?x ?y) ?z)" - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.xor-associates"; "(i32.xor ?x (i32.xor ?y ?z))" <=> "(i32.xor (i32.xor ?x ?y) ?z)" - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.xor-associates"; "(i64.xor ?x (i64.xor ?y ?z))" <=> "(i64.xor (i64.xor ?x ?y) ?z)" - )); + ); - rules.extend(rewrite!( + rewrite!( "i32.eq-associates"; "(i32.eq ?x (i32.eq ?y ?z))" <=> "(i32.eq (i32.eq ?x ?y) ?z)" - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.eq-associates"; "(i64.eq ?x (i64.eq ?y ?z))" <=> "(i64.eq (i64.eq ?x ?y) ?z)" - )); + ); // Undoing `x * 2 ==> x << 1` strength reduction, etc... if !config.reduce { - rules.extend( - rewrite!("i32.mul-by-2"; "(i32.shl ?x i32.const.1)" <=> "(i32.mul ?x i32.const.2)"), - ); - rules.extend( - rewrite!("i64.mul-by-2"; "(i64.shl ?x i64.const.1)" <=> "(i64.mul ?x i64.const.2)"), - ); - rules.extend( - rewrite!("i32.mul-by-4"; "(i32.shl ?x i32.const.2)" <=> "(i32.mul ?x i32.const.4)"), - ); - rules.extend( - rewrite!("i64.mul-by-4"; "(i64.shl ?x i64.const.2)" <=> "(i64.mul ?x i64.const.4)"), - ); - rules.extend( - rewrite!("i32.mul-by-8"; "(i32.shl ?x i32.const.3)" <=> "(i32.mul ?x i32.const.8)"), - ); - rules.extend( - rewrite!("i64.mul-by-8"; "(i64.shl ?x i64.const.3)" <=> "(i64.mul ?x i64.const.8)"), - ); + rewrite!("i32.mul-by-2"; "(i32.shl ?x i32.const.1)" <=> "(i32.mul ?x i32.const.2)"); + rewrite!("i64.mul-by-2"; "(i64.shl ?x i64.const.1)" <=> "(i64.mul ?x i64.const.2)"); + rewrite!("i32.mul-by-4"; "(i32.shl ?x i32.const.2)" <=> "(i32.mul ?x i32.const.4)"); + rewrite!("i64.mul-by-4"; "(i64.shl ?x i64.const.2)" <=> "(i64.mul ?x i64.const.4)"); + rewrite!("i32.mul-by-8"; "(i32.shl ?x i32.const.3)" <=> "(i32.mul ?x i32.const.8)"); + rewrite!("i64.mul-by-8"; "(i64.shl ?x i64.const.3)" <=> "(i64.mul ?x i64.const.8)"); } // Invert a `select` condition and swap its consequent and alternative. if !config.reduce { - rules.extend( - rewrite!("select-invert"; "(select ?x ?y ?z)" <=> "(select ?y ?x (i32.eqz ?z))"), - ); + rewrite!("select-invert"; "(select ?x ?y ?z)" <=> "(select ?y ?x (i32.eqz ?z))"); } // Convert `x + x` into `x * 2`. if !config.reduce { - rules.extend(rewrite!("i32.add-x-x"; "(i32.add ?x ?x)" <=> "(i32.mul ?x i32.const.2)")); - rules.extend(rewrite!("i64.add-x-x"; "(i64.add ?x ?x)" <=> "(i64.mul ?x i64.const.2)")); + rewrite!("i32.add-x-x"; "(i32.add ?x ?x)" <=> "(i32.mul ?x i32.const.2)"); + rewrite!("i64.add-x-x"; "(i64.add ?x ?x)" <=> "(i64.mul ?x i64.const.2)"); } // Mess with dropped subexpressions. - if !config.reduce { - rules.extend(vec![ - rewrite!( - "i32.drop-x"; - "(drop ?x)" => "(drop i32.rand)" - if self.is_type("?x", PrimitiveTypeInfo::I32) - ), - rewrite!( - "i64.drop-x"; - "(drop ?x)" => "(drop i64.rand)" - if self.is_type("?x", PrimitiveTypeInfo::I64) - ), - rewrite!( - "f32.drop-x"; - "(drop ?x)" => "(drop f32.const.0,0)" - if self.is_type("?x", PrimitiveTypeInfo::F32) - ), - rewrite!( - "f64.drop-x"; - "(drop ?x)" => "(drop f32.const.0,0)" - if self.is_type("?x", PrimitiveTypeInfo::F64) - ), - ]); + if !config.reduce && !config.preserve_semantics { + rewrite!( + "i32.drop-x"; + "(drop ?x)" => "(drop i32.rand)" + if self.is_type("?x", PrimitiveTypeInfo::I32) + ); + rewrite!( + "i64.drop-x"; + "(drop ?x)" => "(drop i64.rand)" + if self.is_type("?x", PrimitiveTypeInfo::I64) + ); + rewrite!( + "f32.drop-x"; + "(drop ?x)" => "(drop f32.const.0,0)" + if self.is_type("?x", PrimitiveTypeInfo::F32) + ); + rewrite!( + "f64.drop-x"; + "(drop ?x)" => "(drop f32.const.0,0)" + if self.is_type("?x", PrimitiveTypeInfo::F64) + ); } // Insert some stack-neutral sub-expressions. if !config.reduce { - rules.extend(vec![ - rewrite!("container-nop-x"; "?x" => "(container nop ?x)"), - rewrite!("container-x-nop"; "?x" => "(container ?x nop)"), - rewrite!("container-drop-i32.rand-x"; "?x" => "(container (drop i32.rand) ?x)"), - rewrite!("container-drop-i64.rand-x"; "?x" => "(container (drop i64.rand) ?x)"), - rewrite!("container-x-drop-i32.rand"; "?x" => "(container ?x (drop i32.rand))"), - rewrite!("container-x-drop-i64.rand"; "?x" => "(container ?x (drop i64.rand))"), - ]); + rewrite!("container-nop-x"; "?x" => "(container nop ?x)"); + rewrite!("container-x-nop"; "?x" => "(container ?x nop)"); + rewrite!("container-drop-i32.rand-x"; "?x" => "(container (drop i32.rand) ?x)"); + rewrite!("container-drop-i64.rand-x"; "?x" => "(container (drop i64.rand) ?x)"); + rewrite!("container-x-drop-i32.rand"; "?x" => "(container ?x (drop i32.rand))"); + rewrite!("container-x-drop-i64.rand"; "?x" => "(container ?x (drop i64.rand))"); } // Spill expressions to a new global and then use the global's value. if !config.reduce { let max_globals = 100_000; - rules.extend(vec![ - rewrite!( - "i32.use_of_global"; - "?x" => "(i32.use_of_global ?x)" - if self.is_type("?x", PrimitiveTypeInfo::I32) - if self.global_count_less_than(config, max_globals) - ), - rewrite!( - "i64.use_of_global"; - "?x" => "(i64.use_of_global ?x)" - if self.is_type("?x", PrimitiveTypeInfo::I64) - if self.global_count_less_than(config, max_globals) - ), - rewrite!( - "f32.use_of_global"; - "?x" => "(f32.use_of_global ?x)" - if self.is_type("?x", PrimitiveTypeInfo::F32) - if self.global_count_less_than(config, max_globals) - ), - rewrite!( - "f64.use_of_global"; - "?x" => "(f64.use_of_global ?x)" - if self.is_type("?x", PrimitiveTypeInfo::F64) - if self.global_count_less_than(config, max_globals) - ), - ]); + rewrite!( + "i32.use_of_global"; + "?x" => "(i32.use_of_global ?x)" + if self.is_type("?x", PrimitiveTypeInfo::I32) + if self.global_count_less_than(config, max_globals) + ); + rewrite!( + "i64.use_of_global"; + "?x" => "(i64.use_of_global ?x)" + if self.is_type("?x", PrimitiveTypeInfo::I64) + if self.global_count_less_than(config, max_globals) + ); + rewrite!( + "f32.use_of_global"; + "?x" => "(f32.use_of_global ?x)" + if self.is_type("?x", PrimitiveTypeInfo::F32) + if self.global_count_less_than(config, max_globals) + ); + rewrite!( + "f64.use_of_global"; + "?x" => "(f64.use_of_global ?x)" + if self.is_type("?x", PrimitiveTypeInfo::F64) + if self.global_count_less_than(config, max_globals) + ); } // Unfolding constants. if !config.reduce { - rules.extend(vec![ - rewrite!( - "i32.unfold"; - "?x" => "(i32.unfold ?x)" - if self.is_const("?x") - if self.is_type("?x", PrimitiveTypeInfo::I32) - ), - rewrite!( - "i64.unfold"; - "?x" => "(i64.unfold ?x)" - if self.is_const("?x") - if self.is_type("?x", PrimitiveTypeInfo::I64) - ), - ]); + rewrite!( + "i32.unfold"; + "?x" => "(i32.unfold ?x)" + if self.is_const("?x") + if self.is_type("?x", PrimitiveTypeInfo::I32) + ); + rewrite!( + "i64.unfold"; + "?x" => "(i64.unfold ?x)" + if self.is_const("?x") + if self.is_type("?x", PrimitiveTypeInfo::I64) + ); } // If we aren't preserving semantics, then go wild with mutations. Only @@ -404,271 +389,317 @@ impl PeepholeMutator { // Wasm. if !config.preserve_semantics { // Replace an expression with either zero, one, or a random constant. - rules.extend(vec![ - rewrite!( - "replace-with-i32-1"; - "?x" => "i32.const.1" - if self.is_type("?x", PrimitiveTypeInfo::I32) - ), - rewrite!( - "replace-with-i64-1"; - "?x" => "i64.const.1" - if self.is_type("?x", PrimitiveTypeInfo::I64) - ), - rewrite!( - "replace-with-f32-1.0"; - "?x" => "f32.const.1,0" - if self.is_type("?x", PrimitiveTypeInfo::F32) - ), - rewrite!( - "replace-with-f64-1.0"; - "?x" => "f64.const.1,0" - if self.is_type("?x", PrimitiveTypeInfo::F64) - ), - rewrite!( - "replace-with-i32-0"; - "?x" => "i32.const.0" - if self.is_type("?x", PrimitiveTypeInfo::I32) - ), - rewrite!( - "replace-with-i64-0"; - "?x" => "i64.const.0" - if self.is_type("?x", PrimitiveTypeInfo::I64) - ), - rewrite!( - "replace-with-f32-0"; - "?x" => "f32.const.0,0" - if self.is_type("?x", PrimitiveTypeInfo::F32) - ), - rewrite!( - "replace-with-f64-0"; - "?x" => "f64.const.0,0" - if self.is_type("?x", PrimitiveTypeInfo::F64) - ), - rewrite!( - "replace-with-v128-0"; - "?x" => "v128.const.0" - if self.is_type("?x", PrimitiveTypeInfo::V128) - ), - rewrite!( - "replace-with-i32.rand"; - "?x" => "i32.rand" - if self.is_type("?x", PrimitiveTypeInfo::I32) - ), - rewrite!( - "replace-with-i64.rand"; - "?x" => "i64.rand" - if self.is_type("?x", PrimitiveTypeInfo::I64) - ), - rewrite!( - "replace-with-f32.rand"; - "?x" => "f32.rand" - if self.is_type("?x", PrimitiveTypeInfo::F32) - ), - rewrite!( - "replace-with-f64.rand"; - "?x" => "f64.rand" - if self.is_type("?x", PrimitiveTypeInfo::F64) - ), - rewrite!( - "replace-with-ref-null-func"; - "?x" => "ref.null.func" - if self.is_type("?x", PrimitiveTypeInfo::FuncRef) - ), - rewrite!( - "replace-with-ref-null-extern"; - "?x" => "ref.null.extern" - if self.is_type("?x", PrimitiveTypeInfo::ExternRef) - ), - // Try to outright delete some instructions and containers to - // help make input even smaller in wasm-shrink cases. - rewrite!( - "remove-drop"; - "(drop ?x)" => "(container)" - ), - rewrite!( - "remove-nop"; - "nop" => "(container)" - ), - rewrite!( - "remove-global.set.0"; - "(global.set.0 ?x)" => "(container)" - ), - rewrite!( - "remove-global.set.1"; - "(global.set.1 ?x)" => "(container)" - ), - rewrite!( - "remove-elem.drop.0"; - "(elem.drop.0)" => "(container)" - ), - rewrite!( - "remove-elem.drop.1"; - "(elem.drop.1)" => "(container)" - ), - rewrite!( - "remove-data.drop.0"; - "(data.drop.0)" => "(container)" - ), - rewrite!( - "remove-data.drop.1"; - "(data.drop.1)" => "(container)" - ), - ]); + rewrite!( + "replace-with-i32-1"; + "?x" => "i32.const.1" + if self.is_type("?x", PrimitiveTypeInfo::I32) + ); + rewrite!( + "replace-with-i64-1"; + "?x" => "i64.const.1" + if self.is_type("?x", PrimitiveTypeInfo::I64) + ); + rewrite!( + "replace-with-f32-1.0"; + "?x" => "f32.const.1,0" + if self.is_type("?x", PrimitiveTypeInfo::F32) + ); + rewrite!( + "replace-with-f64-1.0"; + "?x" => "f64.const.1,0" + if self.is_type("?x", PrimitiveTypeInfo::F64) + ); + rewrite!( + "replace-with-i32-0"; + "?x" => "i32.const.0" + if self.is_type("?x", PrimitiveTypeInfo::I32) + ); + rewrite!( + "replace-with-i64-0"; + "?x" => "i64.const.0" + if self.is_type("?x", PrimitiveTypeInfo::I64) + ); + rewrite!( + "replace-with-f32-0"; + "?x" => "f32.const.0,0" + if self.is_type("?x", PrimitiveTypeInfo::F32) + ); + rewrite!( + "replace-with-f64-0"; + "?x" => "f64.const.0,0" + if self.is_type("?x", PrimitiveTypeInfo::F64) + ); + rewrite!( + "replace-with-v128-0"; + "?x" => "v128.const.0" + if self.is_type("?x", PrimitiveTypeInfo::V128) + ); + rewrite!( + "replace-with-i32.rand"; + "?x" => "i32.rand" + if self.is_type("?x", PrimitiveTypeInfo::I32) + ); + rewrite!( + "replace-with-i64.rand"; + "?x" => "i64.rand" + if self.is_type("?x", PrimitiveTypeInfo::I64) + ); + rewrite!( + "replace-with-f32.rand"; + "?x" => "f32.rand" + if self.is_type("?x", PrimitiveTypeInfo::F32) + ); + rewrite!( + "replace-with-f64.rand"; + "?x" => "f64.rand" + if self.is_type("?x", PrimitiveTypeInfo::F64) + ); + rewrite!( + "replace-with-ref-null-func"; + "?x" => "ref.null.func" + if self.is_type("?x", PrimitiveTypeInfo::FuncRef) + ); + rewrite!( + "replace-with-ref-null-extern"; + "?x" => "ref.null.extern" + if self.is_type("?x", PrimitiveTypeInfo::ExternRef) + ); + // Try to outright delete some instructions and containers to + // help make input even smaller in wasm-shrink cases. + rewrite!( + "remove-drop"; + "(drop ?x)" => "(container)" + ); + rewrite!( + "remove-nop"; + "nop" => "(container)" + ); + rewrite!( + "remove-global.set.0"; + "(global.set.0 ?x)" => "(container)" + ); + rewrite!( + "remove-global.set.1"; + "(global.set.1 ?x)" => "(container)" + ); + rewrite!( + "remove-elem.drop.0"; + "(elem.drop.0)" => "(container)" + ); + rewrite!( + "remove-elem.drop.1"; + "(elem.drop.1)" => "(container)" + ); + rewrite!( + "remove-data.drop.0"; + "(data.drop.0)" => "(container)" + ); + rewrite!( + "remove-data.drop.1"; + "(data.drop.1)" => "(container)" + ); if !config.reduce { // `x <=> x + 1` - rules.extend(rewrite!( + rewrite!( "i32.add-1"; "?x" <=> "(i32.add ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.add-1"; "?x" <=> "(i64.add ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); // `x <=> x - 1` - rules.extend(rewrite!( + rewrite!( "i32.sub-1"; "?x" <=> "(i32.sub ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.sub-1"; "?x" <=> "(i64.sub ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); // `x <=> x & 1` - rules.extend(rewrite!( + rewrite!( "i32.and-1"; "?x" <=> "(i32.and ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.and-1"; "?x" <=> "(i64.and ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); // `x <=> x | 1` - rules.extend(rewrite!( + rewrite!( "i32.or-1"; "?x" <=> "(i32.or ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.or-1"; "?x" <=> "(i64.or ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); // `x <=> x ^ 1` - rules.extend(rewrite!( + rewrite!( "i32.xor-1"; "?x" <=> "(i32.xor ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.xor-1"; "?x" <=> "(i64.xor ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); // `x <=> x << 1` - rules.extend(rewrite!( + rewrite!( "i32.shl-1"; "?x" <=> "(i32.shl ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.shl-1"; "?x" <=> "(i64.shl ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); // `x <=> x >> 1` - rules.extend(rewrite!( + rewrite!( "i32.shr_u-1"; "?x" <=> "(i32.shr_u ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.shr_u-1"; "?x" <=> "(i64.shr_u ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); - rules.extend(rewrite!( + ); + rewrite!( "i32.shr_s-1"; "?x" <=> "(i32.shr_s ?x i32.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I32) - )); - rules.extend(rewrite!( + ); + rewrite!( "i64.shr_s-1"; "?x" <=> "(i64.shr_s ?x i64.const.1)" if self.is_type("?x", PrimitiveTypeInfo::I64) - )); + ); } } rules } - /// Checks if a variable is of a specific type. - fn is_type( + fn is_type(&self, var: &str, ty: PrimitiveTypeInfo) -> Condition { + Condition::Type(var.parse().unwrap(), ty) + } + + fn is_const(&self, var: &str) -> Condition { + Condition::Const(var.parse().unwrap()) + } + + /// Condition that check for number of module globals + fn global_count_less_than(&self, config: &WasmMutate, allowed: usize) -> Condition { + let count = config.info().get_global_count(); + Condition::Bool(count < allowed) + } + + fn add_bidirectional_rewrite( &self, - vari: &'static str, - t: PrimitiveTypeInfo, - ) -> impl Fn(&mut EG, Id, &Subst) -> bool { - move |egraph: &mut EG, _, subst| { - let var = vari.parse(); - match var { - Ok(var) => { - let eclass = &egraph[subst[var]]; - match &eclass.data { - Some(d) => d.tpe == t, - None => false, - } - } - Err(_) => false, - } - } + rules: &mut Vec>, + name: &str, + lhs: &str, + rhs: &str, + cond: &[Condition], + ) { + self.add_rewrite(rules, name, lhs, rhs, cond); + self.add_rewrite(rules, &format!("{name}-rev"), rhs, lhs, cond); + } + + fn add_rewrite( + &self, + rules: &mut Vec>, + name: &str, + lhs: &str, + rhs: &str, + cond: &[Condition], + ) { + let name = name.to_string(); + let long_name = format!("{lhs} => {rhs}"); + let lhs = lhs.parse::>().unwrap(); + let rhs = rhs.parse::>().unwrap(); + rules.push(match cond.len() { + 0 => Rewrite::new(name, long_name, lhs, rhs).unwrap(), + 1 => Rewrite::new( + name, + long_name, + lhs, + egg::ConditionalApplier { + condition: cond[0].clone(), + applier: rhs, + }, + ) + .unwrap(), + 2 => Rewrite::new( + name, + long_name, + lhs, + egg::ConditionalApplier { + condition: cond[0].clone(), + applier: egg::ConditionalApplier { + condition: cond[1].clone(), + applier: rhs, + }, + }, + ) + .unwrap(), + _ => unimplemented!(), + }); } +} + +#[derive(Clone)] +enum Condition { + Type(egg::Var, PrimitiveTypeInfo), + Const(egg::Var), + Bool(bool), +} - /// Check whether the given variable is a constant. - fn is_const(&self, vari: &'static str) -> impl Fn(&mut EG, Id, &Subst) -> bool { - move |egraph: &mut EG, _, subst| { - let var = vari.parse(); - match var { - Ok(var) => { - let eclass = &egraph[subst[var]]; - if eclass.nodes.len() == 1 { - let node = &eclass.nodes[0]; - match node { - Lang::I32(_) => true, - Lang::I64(_) => true, - Lang::F32(_) => true, - Lang::F64(_) => true, - _ => false, - } - } else { - false +impl egg::Condition for Condition { + fn check(&self, egraph: &mut EG, _eclass: Id, subst: &Subst) -> bool { + match *self { + Condition::Type(var, t) => { + let eclass = &egraph[subst[var]]; + match &eclass.data { + Some(d) => d.tpe == t, + None => false, + } + } + Condition::Const(var) => { + let eclass = &egraph[subst[var]]; + if eclass.nodes.len() == 1 { + let node = &eclass.nodes[0]; + match node { + Lang::I32(_) => true, + Lang::I64(_) => true, + Lang::F32(_) => true, + Lang::F64(_) => true, + _ => false, } + } else { + false } - Err(_) => false, } + Condition::Bool(b) => b, } } - - /// Condition that check for number of module globals - fn global_count_less_than( - &self, - config: &WasmMutate, - allowed: usize, - ) -> impl Fn(&mut EG, Id, &Subst) -> bool { - let count = config.info().get_global_count(); - move |_egraph: &mut EG, _, _subst| count < allowed - } } diff --git a/crates/wasm-mutate/src/mutators/remove_export.rs b/crates/wasm-mutate/src/mutators/remove_export.rs index a01df8a322..f0c4507086 100644 --- a/crates/wasm-mutate/src/mutators/remove_export.rs +++ b/crates/wasm-mutate/src/mutators/remove_export.rs @@ -12,19 +12,19 @@ pub struct RemoveExportMutator; impl Mutator for RemoveExportMutator { fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, ) -> Result> + 'a>> { let mut exports = ExportSection::new(); - let mut reader = ExportSectionReader::new(config.info().get_exports_section().data, 0)?; - let max_exports = reader.get_count() as u64; + let reader = ExportSectionReader::new(config.info().get_exports_section().data, 0)?; + let max_exports = u64::from(reader.count()); let skip_at = config.rng().gen_range(0..max_exports); - for i in 0..max_exports { + for (i, export) in reader.into_iter().enumerate() { + let export = export?; config.consume_fuel(1)?; - let export = reader.read().unwrap(); - if skip_at == i { + if skip_at == i as u64 { log::trace!("Removing export {:?} at index {}", export, skip_at); continue; } diff --git a/crates/wasm-mutate/src/mutators/remove_item.rs b/crates/wasm-mutate/src/mutators/remove_item.rs index 2d953c2624..b3283326c2 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -7,6 +7,7 @@ //! mutator largely translates between `wasmparser` structures and //! `wasm_encoder` structures. +use crate::mutators::translate::ConstExprKind; use crate::mutators::{translate, Item, Mutator, Translator}; use crate::Error; use crate::{ModuleInfo, Result, WasmMutate}; @@ -15,8 +16,8 @@ use std::collections::HashSet; use wasm_encoder::*; use wasmparser::{ BinaryReader, CodeSectionReader, DataSectionReader, ElementSectionReader, ExportSectionReader, - ExternalKind, FunctionSectionReader, GlobalSectionReader, ImportSectionReader, - MemorySectionReader, Operator, SectionReader, TableSectionReader, TagSectionReader, + ExternalKind, FromReader, FunctionSectionReader, GlobalSectionReader, ImportSectionReader, + MemorySectionReader, Operator, TableInit, TableSectionReader, TagSectionReader, TypeSectionReader, }; @@ -31,12 +32,9 @@ impl Mutator for RemoveItemMutator { } fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, - ) -> Result> + 'a>> - where - Self: Copy, - { + ) -> Result> + 'a>> { let idx = self.0.choose_removal_index(config); log::trace!("attempting to remove {:?} index {}", self.0, idx); @@ -136,9 +134,12 @@ impl RemoveItem { self.filter_out( &mut module, 0, - TypeSectionReader::new(section.data, 0)?, + TypeSectionReader::new(section.data, 0)?.into_iter_err_on_gc_types(), Item::Type, - |me, ty, section| me.translate_type_def(ty, section), + |me, ty, section| { + me.translate_func_type(ty,section)?; + Ok(()) + }, )?; }, @@ -216,9 +217,21 @@ impl RemoveItem { info.num_imported_tables(), TableSectionReader::new(section.data, 0)?, Item::Table, - |me, ty, section: &mut TableSection| { - let ty = me.translate_table_type(&ty)?; - section.table(ty); + |me, table, section: &mut TableSection| { + let ty = me.translate_table_type(&table.ty)?; + match &table.init { + TableInit::RefNull => { + section.table(ty); + } + TableInit::Expr(expr) => { + let init = me.translate_const_expr( + expr, + &table.ty.element_type.into(), + ConstExprKind::TableInit, + )?; + section.table_with_init(ty, &init); + } + } Ok(()) }, )?; @@ -359,22 +372,22 @@ impl RemoveItem { /// The `offset` provided is the initial offset in the index space, for /// example the global section starts at the offset equal to the number of /// imported globals because local globals are numbered afterwards. - fn filter_out( + fn filter_out<'a, S, T>( &mut self, module: &mut Module, offset: u32, - mut section: S, + section: impl IntoIterator>, section_item: Item, - encode: impl Fn(&mut Self, S::Item, &mut T) -> Result<()>, + encode: impl Fn(&mut Self, S, &mut T) -> Result<()>, ) -> Result<()> where - S: SectionReader, + S: FromReader<'a>, T: Default + Section, { let mut result = T::default(); let mut index = offset; - while !section.eof() { - let item = section.read()?; + for item in section { + let item = item?; if index != self.idx || section_item != self.item { encode(self, item, &mut result)?; } @@ -417,11 +430,8 @@ impl Translator for RemoveItem { } } - if item != self.item { - // Different kind of item, no change - Ok(idx) - } else if idx < self.idx { - // A later item was removed, so this index doesn't change + if item != self.item || idx < self.idx { + // Different kind of item or a later item was removed, index doesn't change Ok(idx) } else if idx == self.idx { // If we're removing a referenced item then that means that this @@ -539,7 +549,7 @@ mod tests { #[test] fn remove_elem() { crate::mutators::match_mutation( - r#"(module (elem))"#, + r#"(module (elem funcref))"#, RemoveItemMutator(Item::Element), r#"(module)"#, ); diff --git a/crates/wasm-mutate/src/mutators/remove_section.rs b/crates/wasm-mutate/src/mutators/remove_section.rs index 578dce2b6b..aeb52dc9b0 100644 --- a/crates/wasm-mutate/src/mutators/remove_section.rs +++ b/crates/wasm-mutate/src/mutators/remove_section.rs @@ -19,19 +19,19 @@ fn is_empty_section(section: &wasm_encoder::RawSection) -> bool { crate::module::match_section_id! { match section.id; Custom => Ok(section.data.is_empty()), - Type => TypeSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), - Import => ImportSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), - Function => FunctionSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), - Table => FunctionSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), - Memory => MemorySectionReader::new(section.data, 0).map(|r| r.get_count() == 0), - Global => GlobalSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), - Export => ExportSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), + Type => TypeSectionReader::new(section.data, 0).map(|r| r.count() == 0), + Import => ImportSectionReader::new(section.data, 0).map(|r| r.count() == 0), + Function => FunctionSectionReader::new(section.data, 0).map(|r| r.count() == 0), + Table => FunctionSectionReader::new(section.data, 0).map(|r| r.count() == 0), + Memory => MemorySectionReader::new(section.data, 0).map(|r| r.count() == 0), + Global => GlobalSectionReader::new(section.data, 0).map(|r| r.count() == 0), + Export => ExportSectionReader::new(section.data, 0).map(|r| r.count() == 0), Start => Ok(section.data.is_empty()), - Element => ElementSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), - Code => CodeSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), - Data => DataSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), + Element => ElementSectionReader::new(section.data, 0).map(|r| r.count() == 0), + Code => CodeSectionReader::new(section.data, 0).map(|r| r.count() == 0), + Data => DataSectionReader::new(section.data, 0).map(|r| r.count() == 0), DataCount => Ok(section.data.is_empty()), - Tag => TagSectionReader::new(section.data, 0).map(|r| r.get_count() == 0), + Tag => TagSectionReader::new(section.data, 0).map(|r| r.count() == 0), _ => Ok(section.data.is_empty()), } .unwrap_or(false) @@ -50,12 +50,9 @@ impl Mutator for RemoveSection { } fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, - ) -> Result> + 'a>> - where - Self: Copy, - { + ) -> Result> + 'a>> { let removal_candidates = config .info() .raw_sections diff --git a/crates/wasm-mutate/src/mutators/rename_export.rs b/crates/wasm-mutate/src/mutators/rename_export.rs index 9e6707bb6e..b8842f1dd7 100644 --- a/crates/wasm-mutate/src/mutators/rename_export.rs +++ b/crates/wasm-mutate/src/mutators/rename_export.rs @@ -44,20 +44,19 @@ impl RenameExportMutator { impl Mutator for RenameExportMutator { fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, ) -> Result> + 'a>> { let mut exports = ExportSection::new(); - let mut reader = ExportSectionReader::new(config.info().get_exports_section().data, 0)?; - let max_exports = reader.get_count() as u64; + let reader = ExportSectionReader::new(config.info().get_exports_section().data, 0)?; + let max_exports = u64::from(reader.count()); let skip_at = config.rng().gen_range(0..max_exports); - for i in 0..max_exports { + for (i, export) in reader.into_iter().enumerate() { + let export = export?; config.consume_fuel(1)?; - let export = reader.read().unwrap(); - - let new_name = if skip_at != i { + let new_name = if skip_at != i as u64 { // otherwise bypass String::from(export.name) } else { diff --git a/crates/wasm-mutate/src/mutators/snip_function.rs b/crates/wasm-mutate/src/mutators/snip_function.rs index 3e6d89520d..f3c2cb8d12 100644 --- a/crates/wasm-mutate/src/mutators/snip_function.rs +++ b/crates/wasm-mutate/src/mutators/snip_function.rs @@ -3,9 +3,8 @@ use super::Mutator; use crate::module::{PrimitiveTypeInfo, TypeInfo}; use crate::{Result, WasmMutate}; - use rand::Rng; -use wasm_encoder::{CodeSection, Function, Instruction, Module, ValType}; +use wasm_encoder::{CodeSection, Function, HeapType, Instruction, Module}; use wasmparser::CodeSectionReader; /// Mutator that replaces the body of a function with an empty body @@ -14,23 +13,24 @@ pub struct SnipMutator; impl Mutator for SnipMutator { fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, ) -> Result> + 'a>> { let mut codes = CodeSection::new(); let code_section = config.info().get_code_section(); - let mut reader = CodeSectionReader::new(code_section.data, 0)?; - let count = reader.get_count(); + let reader = CodeSectionReader::new(code_section.data, 0)?; + let count = reader.count(); let function_to_mutate = config.rng().gen_range(0..count); let ftype = config .info() - .get_functype_idx(function_to_mutate + config.info().num_imported_functions()); + .get_functype_idx(function_to_mutate + config.info().num_imported_functions()) + .clone(); - for i in 0..count { + for (i, func) in reader.into_iter().enumerate() { config.consume_fuel(1)?; - let f = reader.read().unwrap(); + let f = func?; - if i != function_to_mutate { + if i as u32 != function_to_mutate { codes.raw(&code_section.data[f.range().start..f.range().end]); continue; } @@ -40,7 +40,7 @@ impl Mutator for SnipMutator { let locals = vec![]; let mut f = Function::new(locals); - match ftype { + match &ftype { TypeInfo::Func(t) => { for primitive in t.returns.iter() { match primitive { @@ -60,10 +60,10 @@ impl Mutator for SnipMutator { f.instruction(&Instruction::V128Const(0)); } PrimitiveTypeInfo::FuncRef => { - f.instruction(&Instruction::RefNull(ValType::FuncRef)); + f.instruction(&Instruction::RefNull(HeapType::Func)); } PrimitiveTypeInfo::ExternRef => { - f.instruction(&Instruction::RefNull(ValType::ExternRef)); + f.instruction(&Instruction::RefNull(HeapType::Extern)); } PrimitiveTypeInfo::Empty => { unreachable!() diff --git a/crates/wasm-mutate/src/mutators/start.rs b/crates/wasm-mutate/src/mutators/start.rs index 82f7f5d689..45daa4fe8e 100644 --- a/crates/wasm-mutate/src/mutators/start.rs +++ b/crates/wasm-mutate/src/mutators/start.rs @@ -14,12 +14,9 @@ impl Mutator for RemoveStartSection { } fn mutate<'a>( - self, + &self, config: &'a mut WasmMutate, - ) -> Result> + 'a>> - where - Self: Copy, - { + ) -> Result> + 'a>> { let mut module = Module::new(); let start_section_index = config.info().start.unwrap(); diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs index a7ac63eb73..f3044817df 100644 --- a/crates/wasm-mutate/src/mutators/translate.rs +++ b/crates/wasm-mutate/src/mutators/translate.rs @@ -1,6 +1,6 @@ use crate::{Error, Result}; use wasm_encoder::*; -use wasmparser::{DataKind, ElementItem, ElementKind, FunctionBody, Global, Operator, Type}; +use wasmparser::{DataKind, ElementKind, FunctionBody, Global, Operator}; #[derive(Debug, Hash, Eq, PartialEq, Copy, Clone)] pub enum Item { @@ -20,13 +20,14 @@ pub enum ConstExprKind { ElementOffset, ElementFunction, DataOffset, + TableInit, } pub trait Translator { fn as_obj(&mut self) -> &mut dyn Translator; - fn translate_type_def(&mut self, ty: Type, s: &mut TypeSection) -> Result<()> { - type_def(self.as_obj(), ty, s) + fn translate_func_type(&mut self, ty: wasmparser::FuncType, s: &mut TypeSection) -> Result<()> { + func_type(self.as_obj(), ty, s) } fn translate_table_type( @@ -58,6 +59,14 @@ pub trait Translator { ty(self.as_obj(), t) } + fn translate_refty(&mut self, t: &wasmparser::RefType) -> Result { + refty(self.as_obj(), t) + } + + fn translate_heapty(&mut self, t: &wasmparser::HeapType) -> Result { + heapty(self.as_obj(), t) + } + fn translate_global(&mut self, g: Global, s: &mut GlobalSection) -> Result<()> { global(self.as_obj(), g, s) } @@ -100,7 +109,7 @@ pub trait Translator { } fn remap(&mut self, item: Item, idx: u32) -> Result { - drop(item); + let _ = item; Ok(idx) } } @@ -113,22 +122,22 @@ impl Translator for DefaultTranslator { } } -pub fn type_def(t: &mut dyn Translator, ty: Type, s: &mut TypeSection) -> Result<()> { - match ty { - Type::Func(f) => { - s.function( - f.params() - .iter() - .map(|ty| t.translate_ty(ty)) - .collect::>>()?, - f.results() - .iter() - .map(|ty| t.translate_ty(ty)) - .collect::>>()?, - ); - Ok(()) - } - } +pub fn func_type( + t: &mut dyn Translator, + ty: wasmparser::FuncType, + s: &mut TypeSection, +) -> Result<()> { + s.function( + ty.params() + .iter() + .map(|ty| t.translate_ty(ty)) + .collect::>>()?, + ty.results() + .iter() + .map(|ty| t.translate_ty(ty)) + .collect::>>()?, + ); + Ok(()) } pub fn table_type( @@ -136,7 +145,7 @@ pub fn table_type( ty: &wasmparser::TableType, ) -> Result { Ok(wasm_encoder::TableType { - element_type: t.translate_ty(&ty.element_type)?, + element_type: t.translate_refty(&ty.element_type)?, minimum: ty.initial, maximum: ty.maximum, }) @@ -171,15 +180,39 @@ pub fn tag_type(t: &mut dyn Translator, ty: &wasmparser::TagType) -> Result Result { +pub fn ty(t: &mut dyn Translator, ty: &wasmparser::ValType) -> Result { match ty { wasmparser::ValType::I32 => Ok(ValType::I32), wasmparser::ValType::I64 => Ok(ValType::I64), wasmparser::ValType::F32 => Ok(ValType::F32), wasmparser::ValType::F64 => Ok(ValType::F64), wasmparser::ValType::V128 => Ok(ValType::V128), - wasmparser::ValType::FuncRef => Ok(ValType::FuncRef), - wasmparser::ValType::ExternRef => Ok(ValType::ExternRef), + wasmparser::ValType::Ref(ty) => Ok(ValType::Ref(t.translate_refty(ty)?)), + } +} + +pub fn refty(t: &mut dyn Translator, ty: &wasmparser::RefType) -> Result { + Ok(RefType { + nullable: ty.is_nullable(), + heap_type: t.translate_heapty(&ty.heap_type())?, + }) +} + +pub fn heapty(t: &mut dyn Translator, ty: &wasmparser::HeapType) -> Result { + match ty { + wasmparser::HeapType::Func => Ok(HeapType::Func), + wasmparser::HeapType::Extern => Ok(HeapType::Extern), + wasmparser::HeapType::Any => Ok(HeapType::Any), + wasmparser::HeapType::None => Ok(HeapType::None), + wasmparser::HeapType::NoExtern => Ok(HeapType::NoExtern), + wasmparser::HeapType::NoFunc => Ok(HeapType::NoFunc), + wasmparser::HeapType::Eq => Ok(HeapType::Eq), + wasmparser::HeapType::Struct => Ok(HeapType::Struct), + wasmparser::HeapType::Array => Ok(HeapType::Array), + wasmparser::HeapType::I31 => Ok(HeapType::I31), + wasmparser::HeapType::Indexed(i) => { + Ok(HeapType::Indexed(t.remap(Item::Type, (*i).into())?)) + } } } @@ -206,7 +239,7 @@ pub fn const_expr( match op { Operator::RefFunc { .. } | Operator::RefNull { - ty: wasmparser::ValType::FuncRef, + hty: wasmparser::HeapType::Func, .. } | Operator::GlobalGet { .. } => {} @@ -237,696 +270,125 @@ pub fn element( &wasmparser::ValType::I32, ConstExprKind::ElementOffset, )?; + let table_index = table_index.unwrap_or(0); + let table = t.remap(Item::Table, table_index)?; ElementMode::Active { - table: Some(t.remap(Item::Table, *table_index)?), + table: if table == 0 { None } else { Some(table) }, offset: &offset, } } ElementKind::Passive => ElementMode::Passive, ElementKind::Declared => ElementMode::Declared, }; - let element_type = t.translate_ty(&element.ty)?; - let mut functions = Vec::new(); - let mut exprs = Vec::new(); - let mut reader = element.items.get_items_reader()?; - for _ in 0..reader.get_count() { - match reader.read()? { - ElementItem::Func(idx) => { - functions.push(t.remap(Item::Function, idx)?); - } - ElementItem::Expr(expr) => { - exprs.push(t.translate_const_expr( - &expr, - &element.ty, - ConstExprKind::ElementFunction, - )?); - } - } - } - s.segment(ElementSegment { - mode, - element_type, - elements: if reader.uses_exprs() { - Elements::Expressions(&exprs) - } else { + let functions; + let exprs; + let elements = match element.items { + wasmparser::ElementItems::Functions(reader) => { + functions = reader + .into_iter() + .map(|f| t.remap(Item::Function, f?)) + .collect::, _>>()?; Elements::Functions(&functions) - }, - }); + } + wasmparser::ElementItems::Expressions(ty, reader) => { + exprs = reader + .into_iter() + .map(|f| { + t.translate_const_expr( + &f?, + &wasmparser::ValType::Ref(ty), + ConstExprKind::ElementFunction, + ) + }) + .collect::, _>>()?; + Elements::Expressions(t.translate_refty(&ty)?, &exprs) + } + }; + s.segment(ElementSegment { mode, elements }); Ok(()) } -/// This is a pretty gnarly function that translates from `wasmparser` -/// operators to `wasm_encoder` operators. It's quite large because there's -/// quite a few wasm instructions. The theory though is that at least each -/// individual case is pretty self-contained. +#[allow(unused_variables)] pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result> { use wasm_encoder::Instruction as I; - use wasmparser::Operator as O; - Ok(match op { - O::Unreachable => I::Unreachable, - O::Nop => I::Nop, - - O::Block { ty } => I::Block(t.translate_block_type(ty)?), - O::Loop { ty } => I::Loop(t.translate_block_type(ty)?), - O::If { ty } => I::If(t.translate_block_type(ty)?), - O::Else => I::Else, - - O::Try { ty } => I::Try(t.translate_block_type(ty)?), - O::Catch { index } => I::Catch(t.remap(Item::Tag, *index)?), - O::Throw { index } => I::Throw(t.remap(Item::Tag, *index)?), - O::Rethrow { relative_depth } => I::Rethrow(*relative_depth), - O::End => I::End, - O::Br { relative_depth } => I::Br(*relative_depth), - O::BrIf { relative_depth } => I::BrIf(*relative_depth), - O::BrTable { table } => I::BrTable( - table + + macro_rules! translate { + ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + Ok(match op { + $( + wasmparser::Operator::$op $({ $($arg),* })? => { + $( + $(let $arg = translate!(map $arg $arg);)* + )? + translate!(build $op $($($arg)*)?) + } + )* + }) + }; + + // This case is used to map, based on the name of the field, from the + // wasmparser payload type to the wasm-encoder payload type through + // `Translator` as applicable. + (map $arg:ident tag_index) => (t.remap(Item::Tag, *$arg)?); + (map $arg:ident function_index) => (t.remap(Item::Function, *$arg)?); + (map $arg:ident table) => (t.remap(Item::Table, *$arg)?); + (map $arg:ident table_index) => (t.remap(Item::Table, *$arg)?); + (map $arg:ident table) => (t.remap(Item::Table, *$arg)?); + (map $arg:ident dst_table) => (t.remap(Item::Table, *$arg)?); + (map $arg:ident src_table) => (t.remap(Item::Table, *$arg)?); + (map $arg:ident type_index) => (t.remap(Item::Type, *$arg)?); + (map $arg:ident global_index) => (t.remap(Item::Global, *$arg)?); + (map $arg:ident mem) => (t.remap(Item::Memory, *$arg)?); + (map $arg:ident src_mem) => (t.remap(Item::Memory, *$arg)?); + (map $arg:ident dst_mem) => (t.remap(Item::Memory, *$arg)?); + (map $arg:ident data_index) => (t.remap(Item::Data, *$arg)?); + (map $arg:ident elem_index) => (t.remap(Item::Element, *$arg)?); + (map $arg:ident blockty) => (t.translate_block_type($arg)?); + (map $arg:ident relative_depth) => (*$arg); + (map $arg:ident targets) => (( + $arg .targets() .collect::, wasmparser::BinaryReaderError>>()? .into(), - table.default(), - ), + $arg.default(), + )); + (map $arg:ident table_byte) => (()); + (map $arg:ident mem_byte) => (()); + (map $arg:ident flags) => (()); + (map $arg:ident ty) => (t.translate_ty($arg)?); + (map $arg:ident hty) => (t.translate_heapty($arg)?); + (map $arg:ident memarg) => (t.translate_memarg($arg)?); + (map $arg:ident local_index) => (*$arg); + (map $arg:ident value) => ($arg); + (map $arg:ident lane) => (*$arg); + (map $arg:ident lanes) => (*$arg); + + // This case takes the arguments of a wasmparser instruction and creates + // a wasm-encoder instruction. There are a few special cases for where + // the structure of a wasmparser instruction differs from that of + // wasm-encoder. + (build $op:ident) => (I::$op); + (build BrTable $arg:ident) => (I::BrTable($arg.0, $arg.1)); + (build I32Const $arg:ident) => (I::I32Const(*$arg)); + (build I64Const $arg:ident) => (I::I64Const(*$arg)); + (build F32Const $arg:ident) => (I::F32Const(f32::from_bits($arg.bits()))); + (build F64Const $arg:ident) => (I::F64Const(f64::from_bits($arg.bits()))); + (build V128Const $arg:ident) => (I::V128Const($arg.i128())); + (build $op:ident $arg:ident) => (I::$op($arg)); + (build CallIndirect $ty:ident $table:ident $_:ident) => (I::CallIndirect { + ty: $ty, + table: $table, + }); + (build ReturnCallIndirect $ty:ident $table:ident) => (I::ReturnCallIndirect { + ty: $ty, + table: $table, + }); + (build MemoryGrow $mem:ident $_:ident) => (I::MemoryGrow($mem)); + (build MemorySize $mem:ident $_:ident) => (I::MemorySize($mem)); + (build $op:ident $($arg:ident)*) => (I::$op { $($arg),* }); + } - O::Return => I::Return, - O::Call { function_index } => I::Call(t.remap(Item::Function, *function_index)?), - O::CallIndirect { - index, - table_index, - table_byte: _, - } => I::CallIndirect { - ty: t.remap(Item::Type, *index)?, - table: t.remap(Item::Table, *table_index)?, - }, - O::Delegate { relative_depth } => I::Delegate(*relative_depth), - O::CatchAll => I::CatchAll, - O::Drop => I::Drop, - O::Select => I::Select, - O::TypedSelect { ty } => I::TypedSelect(t.translate_ty(ty)?), - - O::LocalGet { local_index } => I::LocalGet(*local_index), - O::LocalSet { local_index } => I::LocalSet(*local_index), - O::LocalTee { local_index } => I::LocalTee(*local_index), - - O::GlobalGet { global_index } => I::GlobalGet(t.remap(Item::Global, *global_index)?), - O::GlobalSet { global_index } => I::GlobalSet(t.remap(Item::Global, *global_index)?), - - O::I32Load { memarg } => I::I32Load(t.translate_memarg(memarg)?), - O::I64Load { memarg } => I::I64Load(t.translate_memarg(memarg)?), - O::F32Load { memarg } => I::F32Load(t.translate_memarg(memarg)?), - O::F64Load { memarg } => I::F64Load(t.translate_memarg(memarg)?), - O::I32Load8S { memarg } => I::I32Load8_S(t.translate_memarg(memarg)?), - O::I32Load8U { memarg } => I::I32Load8_U(t.translate_memarg(memarg)?), - O::I32Load16S { memarg } => I::I32Load16_S(t.translate_memarg(memarg)?), - O::I32Load16U { memarg } => I::I32Load16_U(t.translate_memarg(memarg)?), - O::I64Load8S { memarg } => I::I64Load8_S(t.translate_memarg(memarg)?), - O::I64Load8U { memarg } => I::I64Load8_U(t.translate_memarg(memarg)?), - O::I64Load16S { memarg } => I::I64Load16_S(t.translate_memarg(memarg)?), - O::I64Load16U { memarg } => I::I64Load16_U(t.translate_memarg(memarg)?), - O::I64Load32S { memarg } => I::I64Load32_S(t.translate_memarg(memarg)?), - O::I64Load32U { memarg } => I::I64Load32_U(t.translate_memarg(memarg)?), - O::I32Store { memarg } => I::I32Store(t.translate_memarg(memarg)?), - O::I64Store { memarg } => I::I64Store(t.translate_memarg(memarg)?), - O::F32Store { memarg } => I::F32Store(t.translate_memarg(memarg)?), - O::F64Store { memarg } => I::F64Store(t.translate_memarg(memarg)?), - O::I32Store8 { memarg } => I::I32Store8(t.translate_memarg(memarg)?), - O::I32Store16 { memarg } => I::I32Store16(t.translate_memarg(memarg)?), - O::I64Store8 { memarg } => I::I64Store8(t.translate_memarg(memarg)?), - O::I64Store16 { memarg } => I::I64Store16(t.translate_memarg(memarg)?), - O::I64Store32 { memarg } => I::I64Store32(t.translate_memarg(memarg)?), - - O::MemorySize { mem, .. } => I::MemorySize(t.remap(Item::Memory, *mem)?), - O::MemoryGrow { mem, .. } => I::MemoryGrow(t.remap(Item::Memory, *mem)?), - - O::I32Const { value } => I::I32Const(*value), - O::I64Const { value } => I::I64Const(*value), - O::F32Const { value } => I::F32Const(f32::from_bits(value.bits())), - O::F64Const { value } => I::F64Const(f64::from_bits(value.bits())), - - O::RefNull { ty } => I::RefNull(t.translate_ty(ty)?), - O::RefIsNull => I::RefIsNull, - O::RefFunc { function_index } => I::RefFunc(t.remap(Item::Function, *function_index)?), - - O::I32Eqz => I::I32Eqz, - O::I32Eq => I::I32Eq, - O::I32Ne => I::I32Ne, - O::I32LtS => I::I32LtS, - O::I32LtU => I::I32LtU, - O::I32GtS => I::I32GtS, - O::I32GtU => I::I32GtU, - O::I32LeS => I::I32LeS, - O::I32LeU => I::I32LeU, - O::I32GeS => I::I32GeS, - O::I32GeU => I::I32GeU, - O::I64Eqz => I::I64Eqz, - O::I64Eq => I::I64Eq, - O::I64Ne => I::I64Ne, - O::I64LtS => I::I64LtS, - O::I64LtU => I::I64LtU, - O::I64GtS => I::I64GtS, - O::I64GtU => I::I64GtU, - O::I64LeS => I::I64LeS, - O::I64LeU => I::I64LeU, - O::I64GeS => I::I64GeS, - O::I64GeU => I::I64GeU, - O::F32Eq => I::F32Eq, - O::F32Ne => I::F32Ne, - O::F32Lt => I::F32Lt, - O::F32Gt => I::F32Gt, - O::F32Le => I::F32Le, - O::F32Ge => I::F32Ge, - O::F64Eq => I::F64Eq, - O::F64Ne => I::F64Ne, - O::F64Lt => I::F64Lt, - O::F64Gt => I::F64Gt, - O::F64Le => I::F64Le, - O::F64Ge => I::F64Ge, - O::I32Clz => I::I32Clz, - O::I32Ctz => I::I32Ctz, - O::I32Popcnt => I::I32Popcnt, - O::I32Add => I::I32Add, - O::I32Sub => I::I32Sub, - O::I32Mul => I::I32Mul, - O::I32DivS => I::I32DivS, - O::I32DivU => I::I32DivU, - O::I32RemS => I::I32RemS, - O::I32RemU => I::I32RemU, - O::I32And => I::I32And, - O::I32Or => I::I32Or, - O::I32Xor => I::I32Xor, - O::I32Shl => I::I32Shl, - O::I32ShrS => I::I32ShrS, - O::I32ShrU => I::I32ShrU, - O::I32Rotl => I::I32Rotl, - O::I32Rotr => I::I32Rotr, - O::I64Clz => I::I64Clz, - O::I64Ctz => I::I64Ctz, - O::I64Popcnt => I::I64Popcnt, - O::I64Add => I::I64Add, - O::I64Sub => I::I64Sub, - O::I64Mul => I::I64Mul, - O::I64DivS => I::I64DivS, - O::I64DivU => I::I64DivU, - O::I64RemS => I::I64RemS, - O::I64RemU => I::I64RemU, - O::I64And => I::I64And, - O::I64Or => I::I64Or, - O::I64Xor => I::I64Xor, - O::I64Shl => I::I64Shl, - O::I64ShrS => I::I64ShrS, - O::I64ShrU => I::I64ShrU, - O::I64Rotl => I::I64Rotl, - O::I64Rotr => I::I64Rotr, - O::F32Abs => I::F32Abs, - O::F32Neg => I::F32Neg, - O::F32Ceil => I::F32Ceil, - O::F32Floor => I::F32Floor, - O::F32Trunc => I::F32Trunc, - O::F32Nearest => I::F32Nearest, - O::F32Sqrt => I::F32Sqrt, - O::F32Add => I::F32Add, - O::F32Sub => I::F32Sub, - O::F32Mul => I::F32Mul, - O::F32Div => I::F32Div, - O::F32Min => I::F32Min, - O::F32Max => I::F32Max, - O::F32Copysign => I::F32Copysign, - O::F64Abs => I::F64Abs, - O::F64Neg => I::F64Neg, - O::F64Ceil => I::F64Ceil, - O::F64Floor => I::F64Floor, - O::F64Trunc => I::F64Trunc, - O::F64Nearest => I::F64Nearest, - O::F64Sqrt => I::F64Sqrt, - O::F64Add => I::F64Add, - O::F64Sub => I::F64Sub, - O::F64Mul => I::F64Mul, - O::F64Div => I::F64Div, - O::F64Min => I::F64Min, - O::F64Max => I::F64Max, - O::F64Copysign => I::F64Copysign, - O::I32WrapI64 => I::I32WrapI64, - O::I32TruncF32S => I::I32TruncF32S, - O::I32TruncF32U => I::I32TruncF32U, - O::I32TruncF64S => I::I32TruncF64S, - O::I32TruncF64U => I::I32TruncF64U, - O::I64ExtendI32S => I::I64ExtendI32S, - O::I64ExtendI32U => I::I64ExtendI32U, - O::I64TruncF32S => I::I64TruncF32S, - O::I64TruncF32U => I::I64TruncF32U, - O::I64TruncF64S => I::I64TruncF64S, - O::I64TruncF64U => I::I64TruncF64U, - O::F32ConvertI32S => I::F32ConvertI32S, - O::F32ConvertI32U => I::F32ConvertI32U, - O::F32ConvertI64S => I::F32ConvertI64S, - O::F32ConvertI64U => I::F32ConvertI64U, - O::F32DemoteF64 => I::F32DemoteF64, - O::F64ConvertI32S => I::F64ConvertI32S, - O::F64ConvertI32U => I::F64ConvertI32U, - O::F64ConvertI64S => I::F64ConvertI64S, - O::F64ConvertI64U => I::F64ConvertI64U, - O::F64PromoteF32 => I::F64PromoteF32, - O::I32ReinterpretF32 => I::I32ReinterpretF32, - O::I64ReinterpretF64 => I::I64ReinterpretF64, - O::F32ReinterpretI32 => I::F32ReinterpretI32, - O::F64ReinterpretI64 => I::F64ReinterpretI64, - O::I32Extend8S => I::I32Extend8S, - O::I32Extend16S => I::I32Extend16S, - O::I64Extend8S => I::I64Extend8S, - O::I64Extend16S => I::I64Extend16S, - O::I64Extend32S => I::I64Extend32S, - - O::I32TruncSatF32S => I::I32TruncSatF32S, - O::I32TruncSatF32U => I::I32TruncSatF32U, - O::I32TruncSatF64S => I::I32TruncSatF64S, - O::I32TruncSatF64U => I::I32TruncSatF64U, - O::I64TruncSatF32S => I::I64TruncSatF32S, - O::I64TruncSatF32U => I::I64TruncSatF32U, - O::I64TruncSatF64S => I::I64TruncSatF64S, - O::I64TruncSatF64U => I::I64TruncSatF64U, - - O::MemoryInit { segment, mem } => I::MemoryInit { - data: t.remap(Item::Data, *segment)?, - mem: t.remap(Item::Memory, *mem)?, - }, - O::DataDrop { segment } => I::DataDrop(t.remap(Item::Data, *segment)?), - O::MemoryCopy { src, dst } => I::MemoryCopy { - src: t.remap(Item::Memory, *src)?, - dst: t.remap(Item::Memory, *dst)?, - }, - O::MemoryFill { mem, .. } => I::MemoryFill(t.remap(Item::Memory, *mem)?), - - O::TableInit { segment, table } => I::TableInit { - segment: t.remap(Item::Element, *segment)?, - table: t.remap(Item::Table, *table)?, - }, - O::ElemDrop { segment } => I::ElemDrop { - segment: t.remap(Item::Element, *segment)?, - }, - O::TableCopy { - dst_table, - src_table, - } => I::TableCopy { - dst: t.remap(Item::Table, *dst_table)?, - src: t.remap(Item::Table, *src_table)?, - }, - O::TableFill { table } => I::TableFill { - table: t.remap(Item::Table, *table)?, - }, - O::TableGet { table } => I::TableGet { - table: t.remap(Item::Table, *table)?, - }, - O::TableSet { table } => I::TableSet { - table: t.remap(Item::Table, *table)?, - }, - O::TableGrow { table } => I::TableGrow { - table: t.remap(Item::Table, *table)?, - }, - O::TableSize { table } => I::TableSize { - table: t.remap(Item::Table, *table)?, - }, - - O::V128Load { memarg } => I::V128Load { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load8x8S { memarg } => I::V128Load8x8S { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load8x8U { memarg } => I::V128Load8x8U { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load16x4S { memarg } => I::V128Load16x4S { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load16x4U { memarg } => I::V128Load16x4U { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load32x2S { memarg } => I::V128Load32x2S { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load32x2U { memarg } => I::V128Load32x2U { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load8Splat { memarg } => I::V128Load8Splat { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load16Splat { memarg } => I::V128Load16Splat { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load32Splat { memarg } => I::V128Load32Splat { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load64Splat { memarg } => I::V128Load64Splat { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load32Zero { memarg } => I::V128Load32Zero { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load64Zero { memarg } => I::V128Load64Zero { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Store { memarg } => I::V128Store { - memarg: t.translate_memarg(memarg)?, - }, - O::V128Load8Lane { memarg, lane } => I::V128Load8Lane { - memarg: t.translate_memarg(memarg)?, - lane: *lane, - }, - O::V128Load16Lane { memarg, lane } => I::V128Load16Lane { - memarg: t.translate_memarg(memarg)?, - lane: *lane, - }, - O::V128Load32Lane { memarg, lane } => I::V128Load32Lane { - memarg: t.translate_memarg(memarg)?, - lane: *lane, - }, - O::V128Load64Lane { memarg, lane } => I::V128Load64Lane { - memarg: t.translate_memarg(memarg)?, - lane: *lane, - }, - O::V128Store8Lane { memarg, lane } => I::V128Store8Lane { - memarg: t.translate_memarg(memarg)?, - lane: *lane, - }, - O::V128Store16Lane { memarg, lane } => I::V128Store16Lane { - memarg: t.translate_memarg(memarg)?, - lane: *lane, - }, - O::V128Store32Lane { memarg, lane } => I::V128Store32Lane { - memarg: t.translate_memarg(memarg)?, - lane: *lane, - }, - O::V128Store64Lane { memarg, lane } => I::V128Store64Lane { - memarg: t.translate_memarg(memarg)?, - lane: *lane, - }, - - O::V128Const { value } => I::V128Const(value.i128()), - O::I8x16Shuffle { lanes } => I::I8x16Shuffle { lanes: *lanes }, - O::I8x16ExtractLaneS { lane } => I::I8x16ExtractLaneS { lane: *lane }, - O::I8x16ExtractLaneU { lane } => I::I8x16ExtractLaneU { lane: *lane }, - O::I8x16ReplaceLane { lane } => I::I8x16ReplaceLane { lane: *lane }, - O::I16x8ExtractLaneS { lane } => I::I16x8ExtractLaneS { lane: *lane }, - O::I16x8ExtractLaneU { lane } => I::I16x8ExtractLaneU { lane: *lane }, - O::I16x8ReplaceLane { lane } => I::I16x8ReplaceLane { lane: *lane }, - O::I32x4ExtractLane { lane } => I::I32x4ExtractLane { lane: *lane }, - O::I32x4ReplaceLane { lane } => I::I32x4ReplaceLane { lane: *lane }, - O::I64x2ExtractLane { lane } => I::I64x2ExtractLane { lane: *lane }, - O::I64x2ReplaceLane { lane } => I::I64x2ReplaceLane { lane: *lane }, - O::F32x4ExtractLane { lane } => I::F32x4ExtractLane { lane: *lane }, - O::F32x4ReplaceLane { lane } => I::F32x4ReplaceLane { lane: *lane }, - O::F64x2ExtractLane { lane } => I::F64x2ExtractLane { lane: *lane }, - O::F64x2ReplaceLane { lane } => I::F64x2ReplaceLane { lane: *lane }, - - O::I8x16Swizzle => I::I8x16Swizzle, - O::I8x16Splat => I::I8x16Splat, - O::I16x8Splat => I::I16x8Splat, - O::I32x4Splat => I::I32x4Splat, - O::I64x2Splat => I::I64x2Splat, - O::F32x4Splat => I::F32x4Splat, - O::F64x2Splat => I::F64x2Splat, - O::I8x16Eq => I::I8x16Eq, - O::I8x16Ne => I::I8x16Ne, - O::I8x16LtS => I::I8x16LtS, - O::I8x16LtU => I::I8x16LtU, - O::I8x16GtS => I::I8x16GtS, - O::I8x16GtU => I::I8x16GtU, - O::I8x16LeS => I::I8x16LeS, - O::I8x16LeU => I::I8x16LeU, - O::I8x16GeS => I::I8x16GeS, - O::I8x16GeU => I::I8x16GeU, - O::I16x8Eq => I::I16x8Eq, - O::I16x8Ne => I::I16x8Ne, - O::I16x8LtS => I::I16x8LtS, - O::I16x8LtU => I::I16x8LtU, - O::I16x8GtS => I::I16x8GtS, - O::I16x8GtU => I::I16x8GtU, - O::I16x8LeS => I::I16x8LeS, - O::I16x8LeU => I::I16x8LeU, - O::I16x8GeS => I::I16x8GeS, - O::I16x8GeU => I::I16x8GeU, - O::I32x4Eq => I::I32x4Eq, - O::I32x4Ne => I::I32x4Ne, - O::I32x4LtS => I::I32x4LtS, - O::I32x4LtU => I::I32x4LtU, - O::I32x4GtS => I::I32x4GtS, - O::I32x4GtU => I::I32x4GtU, - O::I32x4LeS => I::I32x4LeS, - O::I32x4LeU => I::I32x4LeU, - O::I32x4GeS => I::I32x4GeS, - O::I32x4GeU => I::I32x4GeU, - O::I64x2Eq => I::I64x2Eq, - O::I64x2Ne => I::I64x2Ne, - O::I64x2LtS => I::I64x2LtS, - O::I64x2GtS => I::I64x2GtS, - O::I64x2LeS => I::I64x2LeS, - O::I64x2GeS => I::I64x2GeS, - O::F32x4Eq => I::F32x4Eq, - O::F32x4Ne => I::F32x4Ne, - O::F32x4Lt => I::F32x4Lt, - O::F32x4Gt => I::F32x4Gt, - O::F32x4Le => I::F32x4Le, - O::F32x4Ge => I::F32x4Ge, - O::F64x2Eq => I::F64x2Eq, - O::F64x2Ne => I::F64x2Ne, - O::F64x2Lt => I::F64x2Lt, - O::F64x2Gt => I::F64x2Gt, - O::F64x2Le => I::F64x2Le, - O::F64x2Ge => I::F64x2Ge, - O::V128Not => I::V128Not, - O::V128And => I::V128And, - O::V128AndNot => I::V128AndNot, - O::V128Or => I::V128Or, - O::V128Xor => I::V128Xor, - O::V128Bitselect => I::V128Bitselect, - O::V128AnyTrue => I::V128AnyTrue, - O::I8x16Abs => I::I8x16Abs, - O::I8x16Neg => I::I8x16Neg, - O::I8x16Popcnt => I::I8x16Popcnt, - O::I8x16AllTrue => I::I8x16AllTrue, - O::I8x16Bitmask => I::I8x16Bitmask, - O::I8x16NarrowI16x8S => I::I8x16NarrowI16x8S, - O::I8x16NarrowI16x8U => I::I8x16NarrowI16x8U, - O::I8x16Shl => I::I8x16Shl, - O::I8x16ShrS => I::I8x16ShrS, - O::I8x16ShrU => I::I8x16ShrU, - O::I8x16Add => I::I8x16Add, - O::I8x16AddSatS => I::I8x16AddSatS, - O::I8x16AddSatU => I::I8x16AddSatU, - O::I8x16Sub => I::I8x16Sub, - O::I8x16SubSatS => I::I8x16SubSatS, - O::I8x16SubSatU => I::I8x16SubSatU, - O::I8x16MinS => I::I8x16MinS, - O::I8x16MinU => I::I8x16MinU, - O::I8x16MaxS => I::I8x16MaxS, - O::I8x16MaxU => I::I8x16MaxU, - O::I8x16RoundingAverageU => I::I8x16RoundingAverageU, - O::I16x8ExtAddPairwiseI8x16S => I::I16x8ExtAddPairwiseI8x16S, - O::I16x8ExtAddPairwiseI8x16U => I::I16x8ExtAddPairwiseI8x16U, - O::I16x8Abs => I::I16x8Abs, - O::I16x8Neg => I::I16x8Neg, - O::I16x8Q15MulrSatS => I::I16x8Q15MulrSatS, - O::I16x8AllTrue => I::I16x8AllTrue, - O::I16x8Bitmask => I::I16x8Bitmask, - O::I16x8NarrowI32x4S => I::I16x8NarrowI32x4S, - O::I16x8NarrowI32x4U => I::I16x8NarrowI32x4U, - O::I16x8ExtendLowI8x16S => I::I16x8ExtendLowI8x16S, - O::I16x8ExtendHighI8x16S => I::I16x8ExtendHighI8x16S, - O::I16x8ExtendLowI8x16U => I::I16x8ExtendLowI8x16U, - O::I16x8ExtendHighI8x16U => I::I16x8ExtendHighI8x16U, - O::I16x8Shl => I::I16x8Shl, - O::I16x8ShrS => I::I16x8ShrS, - O::I16x8ShrU => I::I16x8ShrU, - O::I16x8Add => I::I16x8Add, - O::I16x8AddSatS => I::I16x8AddSatS, - O::I16x8AddSatU => I::I16x8AddSatU, - O::I16x8Sub => I::I16x8Sub, - O::I16x8SubSatS => I::I16x8SubSatS, - O::I16x8SubSatU => I::I16x8SubSatU, - O::I16x8Mul => I::I16x8Mul, - O::I16x8MinS => I::I16x8MinS, - O::I16x8MinU => I::I16x8MinU, - O::I16x8MaxS => I::I16x8MaxS, - O::I16x8MaxU => I::I16x8MaxU, - O::I16x8RoundingAverageU => I::I16x8RoundingAverageU, - O::I16x8ExtMulLowI8x16S => I::I16x8ExtMulLowI8x16S, - O::I16x8ExtMulHighI8x16S => I::I16x8ExtMulHighI8x16S, - O::I16x8ExtMulLowI8x16U => I::I16x8ExtMulLowI8x16U, - O::I16x8ExtMulHighI8x16U => I::I16x8ExtMulHighI8x16U, - O::I32x4ExtAddPairwiseI16x8S => I::I32x4ExtAddPairwiseI16x8S, - O::I32x4ExtAddPairwiseI16x8U => I::I32x4ExtAddPairwiseI16x8U, - O::I32x4Abs => I::I32x4Abs, - O::I32x4Neg => I::I32x4Neg, - O::I32x4AllTrue => I::I32x4AllTrue, - O::I32x4Bitmask => I::I32x4Bitmask, - O::I32x4ExtendLowI16x8S => I::I32x4ExtendLowI16x8S, - O::I32x4ExtendHighI16x8S => I::I32x4ExtendHighI16x8S, - O::I32x4ExtendLowI16x8U => I::I32x4ExtendLowI16x8U, - O::I32x4ExtendHighI16x8U => I::I32x4ExtendHighI16x8U, - O::I32x4Shl => I::I32x4Shl, - O::I32x4ShrS => I::I32x4ShrS, - O::I32x4ShrU => I::I32x4ShrU, - O::I32x4Add => I::I32x4Add, - O::I32x4Sub => I::I32x4Sub, - O::I32x4Mul => I::I32x4Mul, - O::I32x4MinS => I::I32x4MinS, - O::I32x4MinU => I::I32x4MinU, - O::I32x4MaxS => I::I32x4MaxS, - O::I32x4MaxU => I::I32x4MaxU, - O::I32x4DotI16x8S => I::I32x4DotI16x8S, - O::I32x4ExtMulLowI16x8S => I::I32x4ExtMulLowI16x8S, - O::I32x4ExtMulHighI16x8S => I::I32x4ExtMulHighI16x8S, - O::I32x4ExtMulLowI16x8U => I::I32x4ExtMulLowI16x8U, - O::I32x4ExtMulHighI16x8U => I::I32x4ExtMulHighI16x8U, - O::I64x2Abs => I::I64x2Abs, - O::I64x2Neg => I::I64x2Neg, - O::I64x2AllTrue => I::I64x2AllTrue, - O::I64x2Bitmask => I::I64x2Bitmask, - O::I64x2ExtendLowI32x4S => I::I64x2ExtendLowI32x4S, - O::I64x2ExtendHighI32x4S => I::I64x2ExtendHighI32x4S, - O::I64x2ExtendLowI32x4U => I::I64x2ExtendLowI32x4U, - O::I64x2ExtendHighI32x4U => I::I64x2ExtendHighI32x4U, - O::I64x2Shl => I::I64x2Shl, - O::I64x2ShrS => I::I64x2ShrS, - O::I64x2ShrU => I::I64x2ShrU, - O::I64x2Add => I::I64x2Add, - O::I64x2Sub => I::I64x2Sub, - O::I64x2Mul => I::I64x2Mul, - O::I64x2ExtMulLowI32x4S => I::I64x2ExtMulLowI32x4S, - O::I64x2ExtMulHighI32x4S => I::I64x2ExtMulHighI32x4S, - O::I64x2ExtMulLowI32x4U => I::I64x2ExtMulLowI32x4U, - O::I64x2ExtMulHighI32x4U => I::I64x2ExtMulHighI32x4U, - O::F32x4Ceil => I::F32x4Ceil, - O::F32x4Floor => I::F32x4Floor, - O::F32x4Trunc => I::F32x4Trunc, - O::F32x4Nearest => I::F32x4Nearest, - O::F32x4Abs => I::F32x4Abs, - O::F32x4Neg => I::F32x4Neg, - O::F32x4Sqrt => I::F32x4Sqrt, - O::F32x4Add => I::F32x4Add, - O::F32x4Sub => I::F32x4Sub, - O::F32x4Mul => I::F32x4Mul, - O::F32x4Div => I::F32x4Div, - O::F32x4Min => I::F32x4Min, - O::F32x4Max => I::F32x4Max, - O::F32x4PMin => I::F32x4PMin, - O::F32x4PMax => I::F32x4PMax, - O::F64x2Ceil => I::F64x2Ceil, - O::F64x2Floor => I::F64x2Floor, - O::F64x2Trunc => I::F64x2Trunc, - O::F64x2Nearest => I::F64x2Nearest, - O::F64x2Abs => I::F64x2Abs, - O::F64x2Neg => I::F64x2Neg, - O::F64x2Sqrt => I::F64x2Sqrt, - O::F64x2Add => I::F64x2Add, - O::F64x2Sub => I::F64x2Sub, - O::F64x2Mul => I::F64x2Mul, - O::F64x2Div => I::F64x2Div, - O::F64x2Min => I::F64x2Min, - O::F64x2Max => I::F64x2Max, - O::F64x2PMin => I::F64x2PMin, - O::F64x2PMax => I::F64x2PMax, - O::I32x4TruncSatF32x4S => I::I32x4TruncSatF32x4S, - O::I32x4TruncSatF32x4U => I::I32x4TruncSatF32x4U, - O::F32x4ConvertI32x4S => I::F32x4ConvertI32x4S, - O::F32x4ConvertI32x4U => I::F32x4ConvertI32x4U, - O::I32x4TruncSatF64x2SZero => I::I32x4TruncSatF64x2SZero, - O::I32x4TruncSatF64x2UZero => I::I32x4TruncSatF64x2UZero, - O::F64x2ConvertLowI32x4S => I::F64x2ConvertLowI32x4S, - O::F64x2ConvertLowI32x4U => I::F64x2ConvertLowI32x4U, - O::F32x4DemoteF64x2Zero => I::F32x4DemoteF64x2Zero, - O::F64x2PromoteLowF32x4 => I::F64x2PromoteLowF32x4, - O::I8x16RelaxedSwizzle => I::I8x16RelaxedSwizzle, - O::I32x4RelaxedTruncSatF32x4S => I::I32x4RelaxedTruncSatF32x4S, - O::I32x4RelaxedTruncSatF32x4U => I::I32x4RelaxedTruncSatF32x4U, - O::I32x4RelaxedTruncSatF64x2SZero => I::I32x4RelaxedTruncSatF64x2SZero, - O::I32x4RelaxedTruncSatF64x2UZero => I::I32x4RelaxedTruncSatF64x2UZero, - O::F32x4Fma => I::F32x4Fma, - O::F32x4Fms => I::F32x4Fms, - O::F64x2Fma => I::F64x2Fma, - O::F64x2Fms => I::F64x2Fms, - O::I8x16LaneSelect => I::I8x16LaneSelect, - O::I16x8LaneSelect => I::I16x8LaneSelect, - O::I32x4LaneSelect => I::I32x4LaneSelect, - O::I64x2LaneSelect => I::I64x2LaneSelect, - O::F32x4RelaxedMin => I::F32x4RelaxedMin, - O::F32x4RelaxedMax => I::F32x4RelaxedMax, - O::F64x2RelaxedMin => I::F64x2RelaxedMin, - O::F64x2RelaxedMax => I::F64x2RelaxedMax, - - // Note that these cases are not supported in `wasm_encoder` yet, - // and in general `wasmparser` often parses more things than - // `wasm_encoder` supports. If these are seen we simply say that - // this mutation isn't applicable because `wasm-encoder` can't - // create the new function anyway. - O::MemoryAtomicNotify { .. } - | O::MemoryAtomicWait32 { .. } - | O::MemoryAtomicWait64 { .. } - | O::I32AtomicLoad { .. } - | O::I64AtomicLoad { .. } - | O::I32AtomicLoad8U { .. } - | O::I32AtomicLoad16U { .. } - | O::I64AtomicLoad8U { .. } - | O::I64AtomicLoad16U { .. } - | O::I64AtomicLoad32U { .. } - | O::I32AtomicStore { .. } - | O::I64AtomicStore { .. } - | O::I32AtomicStore8 { .. } - | O::I32AtomicStore16 { .. } - | O::I64AtomicStore8 { .. } - | O::I64AtomicStore16 { .. } - | O::I64AtomicStore32 { .. } - | O::I32AtomicRmwAdd { .. } - | O::I64AtomicRmwAdd { .. } - | O::I32AtomicRmw8AddU { .. } - | O::I32AtomicRmw16AddU { .. } - | O::I64AtomicRmw8AddU { .. } - | O::I64AtomicRmw16AddU { .. } - | O::I64AtomicRmw32AddU { .. } - | O::I32AtomicRmwSub { .. } - | O::I64AtomicRmwSub { .. } - | O::I32AtomicRmw8SubU { .. } - | O::I32AtomicRmw16SubU { .. } - | O::I64AtomicRmw8SubU { .. } - | O::I64AtomicRmw16SubU { .. } - | O::I64AtomicRmw32SubU { .. } - | O::I32AtomicRmwAnd { .. } - | O::I64AtomicRmwAnd { .. } - | O::I32AtomicRmw8AndU { .. } - | O::I32AtomicRmw16AndU { .. } - | O::I64AtomicRmw8AndU { .. } - | O::I64AtomicRmw16AndU { .. } - | O::I64AtomicRmw32AndU { .. } - | O::I32AtomicRmwOr { .. } - | O::I64AtomicRmwOr { .. } - | O::I32AtomicRmw8OrU { .. } - | O::I32AtomicRmw16OrU { .. } - | O::I64AtomicRmw8OrU { .. } - | O::I64AtomicRmw16OrU { .. } - | O::I64AtomicRmw32OrU { .. } - | O::I32AtomicRmwXor { .. } - | O::I64AtomicRmwXor { .. } - | O::I32AtomicRmw8XorU { .. } - | O::I32AtomicRmw16XorU { .. } - | O::I64AtomicRmw8XorU { .. } - | O::I64AtomicRmw16XorU { .. } - | O::I64AtomicRmw32XorU { .. } - | O::I32AtomicRmwXchg { .. } - | O::I64AtomicRmwXchg { .. } - | O::I32AtomicRmw8XchgU { .. } - | O::I32AtomicRmw16XchgU { .. } - | O::I64AtomicRmw8XchgU { .. } - | O::I64AtomicRmw16XchgU { .. } - | O::I64AtomicRmw32XchgU { .. } - | O::I32AtomicRmwCmpxchg { .. } - | O::I64AtomicRmwCmpxchg { .. } - | O::I32AtomicRmw8CmpxchgU { .. } - | O::I32AtomicRmw16CmpxchgU { .. } - | O::I64AtomicRmw8CmpxchgU { .. } - | O::I64AtomicRmw16CmpxchgU { .. } - | O::I64AtomicRmw32CmpxchgU { .. } - | O::ReturnCall { .. } - | O::ReturnCallIndirect { .. } - | O::AtomicFence { .. } => return Err(Error::no_mutations_applicable()), - }) + wasmparser::for_each_operator!(translate) } pub fn block_type(t: &mut dyn Translator, ty: &wasmparser::BlockType) -> Result { diff --git a/crates/wasm-mutate/tests/tests.rs b/crates/wasm-mutate/tests/tests.rs index 9fba9466c0..6d97df157c 100644 --- a/crates/wasm-mutate/tests/tests.rs +++ b/crates/wasm-mutate/tests/tests.rs @@ -45,6 +45,7 @@ fn integration_test() { Ok(it) => it, Err(e) => match e.kind() { ErrorKind::NoMutationsApplicable => continue, + ErrorKind::OutOfFuel => break, _ => panic!("{}", e), }, }; diff --git a/crates/wasm-shrink/Cargo.toml b/crates/wasm-shrink/Cargo.toml index 8f6050b41d..1d5cf1d281 100644 --- a/crates/wasm-shrink/Cargo.toml +++ b/crates/wasm-shrink/Cargo.toml @@ -2,24 +2,24 @@ authors = ["Nick Fitzgerald "] categories = ["command-line-utilities", "development-tools", "development-tools::testing", "wasm"] description = "A WebAssembly test case shrinker" -edition = "2021" +edition.workspace = true keywords = ["reducer", "reduce", "bug", "crash"] license = "Apache-2.0 WITH LLVM-exception" readme = "./README.md" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-shrink" name = "wasm-shrink" -version = "0.1.9" +version = "0.1.39" [dependencies] -anyhow = "1" +anyhow = { workspace = true } blake3 = "1.2.0" -log = "0.4" -rand = { version = "0.8.4", features = ["small_rng"] } -clap = { version = "3.0", optional = true, features = ['derive'] } -wasm-mutate = { version = "0.2.7", path = "../wasm-mutate" } -wasmparser = { version = "0.90.0", path = "../wasmparser" } +log = { workspace = true } +rand = { workspace = true } +clap = { workspace = true, optional = true } +wasm-mutate = { workspace = true } +wasmparser = { workspace = true } [dev-dependencies] -env_logger = "0.9" +env_logger = { workspace = true } wasmprinter = { path = "../wasmprinter" } wat = { path = "../wat" } diff --git a/crates/wasm-shrink/README.md b/crates/wasm-shrink/README.md index 629884a65c..d860556475 100644 --- a/crates/wasm-shrink/README.md +++ b/crates/wasm-shrink/README.md @@ -24,7 +24,7 @@ compiler). ### Install ``` -$ cargo install --git https://github.com/bytecodealliance/wasm-tools.git +$ cargo install wasm-tools ``` ### Writing a Predicate Script @@ -65,10 +65,10 @@ and non-zero if there is *not* any match. This is useful for predicate scripts. ### Run -To run `wasm-shrink` pass it the predicate and the initial test case: +To run `wasm-tools shrink` pass it the predicate and the initial test case: ```bash -$ wasm-shrink predicate.sh test-case.wasm -o shrunken.wasm +$ wasm-tools shrink predicate.sh test-case.wasm -o shrunken.wasm ``` The shrunken Wasm file will be written to `shrunken.wasm` in this case, but if @@ -78,7 +78,7 @@ case's name. You can see all options by passing `--help`: ```bash -$ wasm-shrink --help +$ wasm-tools shrink --help ``` ## Embed as a Library @@ -88,9 +88,8 @@ allow programmatic usage. First, add a dependency to your `Cargo.toml`: -```toml -[dependencies] -wasm-shrink = "0.1.0" +```sh +$ cargo add wasm-shrink ``` Then use the `wasm_shrink::WasmShrink` builder to configure and run a shrinking diff --git a/crates/wasm-shrink/src/lib.rs b/crates/wasm-shrink/src/lib.rs index 09a8b0b264..63315f73a1 100755 --- a/crates/wasm-shrink/src/lib.rs +++ b/crates/wasm-shrink/src/lib.rs @@ -233,9 +233,12 @@ impl ShrinkRun { saturating_float_to_int: true, sign_extension: true, component_model: false, + function_references: false, + gc: false, + component_model_values: false, - // We'll never enable this here. - deterministic_only: false, + floats: true, + memory_control: true, }); validator.validate_all(wasm)?; diff --git a/crates/wasm-smith/Cargo.toml b/crates/wasm-smith/Cargo.toml index 10d19e55f9..bad10cb80e 100644 --- a/crates/wasm-smith/Cargo.toml +++ b/crates/wasm-smith/Cargo.toml @@ -3,12 +3,12 @@ authors = ["Nick Fitzgerald "] categories = ["command-line-utilities", "development-tools", "development-tools::testing", "wasm"] description = "A WebAssembly test case generator" documentation = "https://docs.rs/wasm-smith" -edition = "2021" +edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" name = "wasm-smith" readme = "./README.md" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-smith" -version = "0.11.4" +version = "0.12.21" exclude = ["/benches/corpus"] [[bench]] @@ -16,20 +16,23 @@ name = "corpus" harness = false [dependencies] -arbitrary = { version = "1.1.0", features = ["derive"] } +arbitrary = { workspace = true, features = ["derive"] } flagset = "0.4" -indexmap = "1.6" -leb128 = "0.2.4" -serde = { version = "1", features = ['derive'], optional = true } -wasm-encoder = { version = "0.16.0", path = "../wasm-encoder" } -wasmparser = { version = "0.90.0", path = "../wasmparser" } +indexmap = { workspace = true } +leb128 = { workspace = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +wasm-encoder = { workspace = true } +wasmparser = { workspace = true } [dev-dependencies] -criterion = "0.3.3" -libfuzzer-sys = "0.4.0" -rand = { version = "0.8.0", features = ["small_rng"] } +criterion = { workspace = true } +rand = { workspace = true } wasmprinter = { path = "../wasmprinter" } wat = { path = "../wat" } +[target.'cfg(not(target_family = "wasm"))'.dev-dependencies] +libfuzzer-sys = { workspace = true } + [features] -_internal_cli = ["serde", "flagset/serde"] +_internal_cli = ["serde", "serde_derive"] diff --git a/crates/wasm-smith/README.md b/crates/wasm-smith/README.md index a841bd1c84..489918aca4 100644 --- a/crates/wasm-smith/README.md +++ b/crates/wasm-smith/README.md @@ -5,7 +5,6 @@ [![](https://docs.rs/wasm-smith/badge.svg)](https://docs.rs/wasm-smith/) [![](https://img.shields.io/crates/v/wasm-smith.svg)](https://crates.io/crates/wasm-smith) [![](https://img.shields.io/crates/d/wasm-smith.svg)](https://crates.io/crates/wasm-smith) -![Rust](https://github.com/fitzgen/wasm-smith/workflows/Rust/badge.svg) * [Features](#features) * [Usage](#usage) @@ -46,11 +45,8 @@ $ cargo fuzz add my_wasm_smith_fuzz_target Next, add `wasm-smith` to your dependencies: -```toml -# fuzz/Cargo.toml - -[dependencies] -wasm-smith = "0.4.0" +```shell +$ cargo add wasm-smith ``` Then, define your fuzz target so that it takes arbitrary `wasm_smith::Module`s @@ -79,7 +75,7 @@ $ cargo fuzz run my_wasm_smith_fuzz_target ``` > **Note:** Also check out [the `validate` fuzz -> target](https://github.com/fitzgen/wasm-smith/blob/main/fuzz/fuzz_targets/validate.rs) +> target](https://github.com/bytecodealliance/wasm-tools/blob/main/fuzz/src/validate.rs) > defined in this repository. Using the `wasmparser` crate, it checks that every > module generated by `wasm-smith` validates successfully. @@ -88,13 +84,13 @@ $ cargo fuzz run my_wasm_smith_fuzz_target Install the CLI tool via `cargo`: ```shell -$ cargo install --git https://github.com/bytecodealliance/wasm-tools +$ cargo install wasm-tools ``` Convert some arbitrary input into a valid Wasm module: ```shell -$ head -c 100 /dev/urandom | wasm-smith -o test.wasm +$ head -c 100 /dev/urandom | wasm-tools smith -o test.wasm ``` Finally, run your tool on the generated Wasm module: diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs index 5cc02af0ff..440226bc4a 100644 --- a/crates/wasm-smith/src/component.rs +++ b/crates/wasm-smith/src/component.rs @@ -1,7 +1,8 @@ //! Generation of Wasm //! [components](https://github.com/WebAssembly/component-model). -#![allow(unused_variables, dead_code)] // TODO FITZGEN +// FIXME(#1000): component support in `wasm-smith` is a work in progress. +#![allow(unused_variables, dead_code)] use crate::{arbitrary_loop, Config, DefaultConfig}; use arbitrary::{Arbitrary, Result, Unstructured}; @@ -13,6 +14,7 @@ use std::{ rc::Rc, }; use wasm_encoder::{ComponentTypeRef, ComponentValType, PrimitiveValType, TypeBounds, ValType}; +use wasmparser::names::KebabString; mod encode; @@ -122,7 +124,10 @@ struct ComponentContext { num_imports: usize, // The set of names of imports we've generated thus far. - import_names: HashSet, + import_names: HashSet, + + // The set of URLs of imports we've generated thus far. + import_urls: HashSet, // This component's function index space. funcs: Vec, @@ -185,6 +190,7 @@ impl ComponentContext { component: Component::empty(), num_imports: 0, import_names: HashSet::default(), + import_urls: HashSet::default(), funcs: vec![], component_funcs: vec![], scalar_component_funcs: vec![], @@ -422,7 +428,7 @@ impl ComponentBuilder { choices.push(Self::arbitrary_component_section); } - // TODO FITZGEN + // FIXME(#1000) // // choices.push(Self::arbitrary_instance_section); // choices.push(Self::arbitrary_export_section); @@ -632,12 +638,9 @@ impl ComponentBuilder { && (for_type_def || scope.types.len() < self.config.max_types()) { choices.push(|me, u| { - Ok(ComponentTypeRef::Type( - TypeBounds::Eq, - u.int_in_range( - 0..=u32::try_from(me.current_type_scope().types.len() - 1).unwrap(), - )?, - )) + Ok(ComponentTypeRef::Type(TypeBounds::Eq(u.int_in_range( + 0..=u32::try_from(me.current_type_scope().types.len() - 1).unwrap(), + )?))) }); } @@ -1022,7 +1025,9 @@ impl ComponentBuilder { ) -> Result> { let mut defs = vec![]; let mut imports = HashSet::new(); + let mut import_urls = HashSet::new(); let mut exports = HashSet::new(); + let mut export_urls = HashSet::new(); self.with_types_scope(|me| { arbitrary_loop(u, 0, 100, |u| { @@ -1034,8 +1039,13 @@ impl ComponentBuilder { if me.current_type_scope().can_ref_type() && u.int_in_range::(0..=3)? == 0 { if let Some(ty) = me.arbitrary_type_ref(u, true, true)? { // Imports. - let name = crate::unique_string(100, &mut imports, u)?; - defs.push(ComponentTypeDef::Import(Import { name, ty })); + let name = crate::unique_kebab_string(100, &mut imports, u)?; + let url = if u.arbitrary()? { + Some(crate::unique_url(100, &mut import_urls, u)?) + } else { + None + }; + defs.push(ComponentTypeDef::Import(Import { name, url, ty })); return Ok(true); } @@ -1043,7 +1053,8 @@ impl ComponentBuilder { } // Type definitions, exports, and aliases. - let def = me.arbitrary_instance_type_def(u, &mut exports, type_fuel)?; + let def = + me.arbitrary_instance_type_def(u, &mut exports, &mut export_urls, type_fuel)?; defs.push(def.into()); Ok(true) }) @@ -1059,6 +1070,7 @@ impl ComponentBuilder { ) -> Result> { let mut defs = vec![]; let mut exports = HashSet::new(); + let mut export_urls = HashSet::new(); self.with_types_scope(|me| { arbitrary_loop(u, 0, 100, |u| { @@ -1067,7 +1079,12 @@ impl ComponentBuilder { return Ok(false); } - defs.push(me.arbitrary_instance_type_def(u, &mut exports, type_fuel)?); + defs.push(me.arbitrary_instance_type_def( + u, + &mut exports, + &mut export_urls, + type_fuel, + )?); Ok(true) }) })?; @@ -1078,13 +1095,15 @@ impl ComponentBuilder { fn arbitrary_instance_type_def( &mut self, u: &mut Unstructured, - exports: &mut HashSet, + exports: &mut HashSet, + export_urls: &mut HashSet, type_fuel: &mut u32, ) -> Result { let mut choices: Vec< fn( &mut ComponentBuilder, - &mut HashSet, + &mut HashSet, + &mut HashSet, &mut Unstructured, &mut u32, ) -> Result, @@ -1092,10 +1111,20 @@ impl ComponentBuilder { // Export. if self.current_type_scope().can_ref_type() { - choices.push(|me, exports, u, _type_fuel| { + choices.push(|me, exports, export_urls, u, _type_fuel| { + let ty = me.arbitrary_type_ref(u, false, true)?.unwrap(); + if let ComponentTypeRef::Type(TypeBounds::Eq(idx)) = ty { + let ty = me.current_type_scope().get(idx).clone(); + me.current_type_scope_mut().push(ty); + } Ok(InstanceTypeDecl::Export { - name: crate::unique_string(100, exports, u)?, - ty: me.arbitrary_type_ref(u, false, true)?.unwrap(), + name: crate::unique_kebab_string(100, exports, u)?, + url: if u.arbitrary()? { + Some(crate::unique_url(100, export_urls, u)?) + } else { + None + }, + ty, }) }); } @@ -1106,7 +1135,7 @@ impl ComponentBuilder { .iter() .any(|scope| !scope.types.is_empty() || !scope.core_types.is_empty()) { - choices.push(|me, _exports, u, _type_fuel| { + choices.push(|me, _exports, _export_urls, u, _type_fuel| { let alias = me.arbitrary_outer_type_alias(u)?; match &alias { Alias::Outer { @@ -1124,7 +1153,7 @@ impl ComponentBuilder { } // Core type definition. - choices.push(|me, _exports, u, type_fuel| { + choices.push(|me, _exports, _export_urls, u, type_fuel| { let ty = me.arbitrary_core_type(u, type_fuel)?; me.current_type_scope_mut().push_core(ty.clone()); Ok(InstanceTypeDecl::CoreType(ty)) @@ -1132,7 +1161,7 @@ impl ComponentBuilder { // Type definition. if self.types.len() < self.config.max_nesting_depth() { - choices.push(|me, _exports, u, type_fuel| { + choices.push(|me, _exports, _export_urls, u, type_fuel| { let ty = me.arbitrary_type(u, type_fuel)?; me.current_type_scope_mut().push(ty.clone()); Ok(InstanceTypeDecl::Type(ty)) @@ -1140,7 +1169,7 @@ impl ComponentBuilder { } let f = u.choose(&choices)?; - f(self, exports, u, type_fuel) + f(self, exports, export_urls, u, type_fuel) } fn arbitrary_outer_core_type_alias( @@ -1221,41 +1250,6 @@ impl ComponentBuilder { let mut results = Vec::new(); let mut names = HashSet::new(); - fn push( - b: &ComponentBuilder, - u: &mut Unstructured, - type_fuel: &mut u32, - names: &mut HashSet, - items: &mut Vec<(Option, ComponentValType)>, - ) -> Result { - *type_fuel = type_fuel.saturating_sub(1); - if *type_fuel == 0 { - return Ok(false); - } - - // If the collection is empty (i.e. first push), then arbitrarily give it a name. - // Otherwise, all of the items must be named. - let name = if items.is_empty() { - // Most of the time we should have named parameters/results. - u.ratio::(99, 100)? - .then(|| crate::unique_non_empty_string(100, names, u)) - .transpose()? - } else { - Some(crate::unique_non_empty_string(100, names, u)?) - }; - - let ty = b.arbitrary_component_val_type(u)?; - - items.push((name, ty)); - - // There can be only one unnamed parameter/result. - if items.len() == 1 && items[0].0.is_none() { - return Ok(false); - } - - Ok(true) - } - // Note: parameters are currently limited to a maximum of 16 // because any additional parameters will require indirect access // via a pointer argument; when this occurs, validation of any @@ -1266,7 +1260,17 @@ impl ComponentBuilder { // we should increase this maximum to test indirect parameter // passing. arbitrary_loop(u, 0, 16, |u| { - push(self, u, type_fuel, &mut names, &mut params) + *type_fuel = type_fuel.saturating_sub(1); + if *type_fuel == 0 { + return Ok(false); + } + + let name = crate::unique_kebab_string(100, &mut names, u)?; + let ty = self.arbitrary_component_val_type(u)?; + + params.push((name, ty)); + + Ok(true) })?; names.clear(); @@ -1275,7 +1279,32 @@ impl ComponentBuilder { // required. When the memory option is implemented, this restriction // should be relaxed. arbitrary_loop(u, 0, 1, |u| { - push(self, u, type_fuel, &mut names, &mut results) + *type_fuel = type_fuel.saturating_sub(1); + if *type_fuel == 0 { + return Ok(false); + } + + // If the result list is empty (i.e. first push), then arbitrarily give + // the result a name. Otherwise, all of the subsequent items must be named. + let name = if results.is_empty() { + // Most of the time we should have a single, unnamed result. + u.ratio::(10, 100)? + .then(|| crate::unique_kebab_string(100, &mut names, u)) + .transpose()? + } else { + Some(crate::unique_kebab_string(100, &mut names, u)?) + }; + + let ty = self.arbitrary_component_val_type(u)?; + + results.push((name, ty)); + + // There can be only one unnamed result. + if results.len() == 1 && results[0].0.is_none() { + return Ok(false); + } + + Ok(true) })?; Ok(Rc::new(FuncType { params, results })) @@ -1332,7 +1361,7 @@ impl ComponentBuilder { return Ok(false); } - let name = crate::unique_non_empty_string(100, &mut field_names, u)?; + let name = crate::unique_kebab_string(100, &mut field_names, u)?; let ty = self.arbitrary_component_val_type(u)?; fields.push((name, ty)); @@ -1354,7 +1383,7 @@ impl ComponentBuilder { return Ok(false); } - let name = crate::unique_non_empty_string(100, &mut case_names, u)?; + let name = crate::unique_kebab_string(100, &mut case_names, u)?; let ty = u .arbitrary::()? @@ -1404,7 +1433,7 @@ impl ComponentBuilder { return Ok(false); } - fields.push(crate::unique_non_empty_string(100, &mut field_names, u)?); + fields.push(crate::unique_kebab_string(100, &mut field_names, u)?); Ok(true) })?; Ok(FlagsType { fields }) @@ -1419,26 +1448,12 @@ impl ComponentBuilder { return Ok(false); } - variants.push(crate::unique_non_empty_string(100, &mut variant_names, u)?); + variants.push(crate::unique_kebab_string(100, &mut variant_names, u)?); Ok(true) })?; Ok(EnumType { variants }) } - fn arbitrary_union_type(&self, u: &mut Unstructured, type_fuel: &mut u32) -> Result { - let mut variants = vec![]; - arbitrary_loop(u, 1, 100, |u| { - *type_fuel = type_fuel.saturating_sub(1); - if *type_fuel == 0 { - return Ok(false); - } - - variants.push(self.arbitrary_component_val_type(u)?); - Ok(true) - })?; - Ok(UnionType { variants }) - } - fn arbitrary_option_type(&self, u: &mut Unstructured) -> Result { Ok(OptionType { inner_ty: self.arbitrary_component_val_type(u)?, @@ -1463,7 +1478,7 @@ impl ComponentBuilder { u: &mut Unstructured, type_fuel: &mut u32, ) -> Result { - match u.int_in_range(0..=9)? { + match u.int_in_range(0..=8)? { 0 => Ok(DefinedType::Primitive( self.arbitrary_primitive_val_type(u)?, )), @@ -1477,20 +1492,19 @@ impl ComponentBuilder { 4 => Ok(DefinedType::Tuple(self.arbitrary_tuple_type(u, type_fuel)?)), 5 => Ok(DefinedType::Flags(self.arbitrary_flags_type(u, type_fuel)?)), 6 => Ok(DefinedType::Enum(self.arbitrary_enum_type(u, type_fuel)?)), - 7 => Ok(DefinedType::Union(self.arbitrary_union_type(u, type_fuel)?)), - 8 => Ok(DefinedType::Option(self.arbitrary_option_type(u)?)), - 9 => Ok(DefinedType::Result(self.arbitrary_result_type(u)?)), + 7 => Ok(DefinedType::Option(self.arbitrary_option_type(u)?)), + 8 => Ok(DefinedType::Result(self.arbitrary_result_type(u)?)), _ => unreachable!(), } } - fn push_import(&mut self, name: String, ty: ComponentTypeRef) { + fn push_import(&mut self, name: KebabString, url: Option, ty: ComponentTypeRef) { let nth = match self.ensure_section( |sec| matches!(sec, Section::Import(_)), || Section::Import(ImportSection { imports: vec![] }), ) { Section::Import(sec) => { - sec.imports.push(Import { name, ty }); + sec.imports.push(Import { name, url, ty }); sec.imports.len() - 1 } _ => unreachable!(), @@ -1524,10 +1538,13 @@ impl ComponentBuilder { self.total_values += 1; self.component_mut().values.push(ty); } - ComponentTypeRef::Type(TypeBounds::Eq, ty_index) => { + ComponentTypeRef::Type(TypeBounds::Eq(ty_index)) => { let ty = self.current_type_scope().get(ty_index).clone(); self.current_type_scope_mut().push(ty); } + ComponentTypeRef::Type(TypeBounds::SubResource) => { + unimplemented!() + } ComponentTypeRef::Instance(ty_index) => { let instance_ty = match self.current_type_scope().get(ty_index).as_ref() { Type::Instance(ty) => ty.clone(), @@ -1615,8 +1632,17 @@ impl ComponentBuilder { match self.arbitrary_type_ref(u, true, false)? { Some(ty) => { let name = - crate::unique_string(100, &mut self.component_mut().import_names, u)?; - self.push_import(name, ty); + crate::unique_kebab_string(100, &mut self.component_mut().import_names, u)?; + let url = if u.arbitrary()? { + Some(crate::unique_url( + 100, + &mut self.component_mut().import_urls, + u, + )?) + } else { + None + }; + self.push_import(name, url, ty); Ok(true) } None => Ok(false), @@ -1828,7 +1854,7 @@ fn inverse_scalar_canonical_abi_for( .cloned(), ValType::F32 => Ok(ComponentValType::Primitive(PrimitiveValType::Float32)), ValType::F64 => Ok(ComponentValType::Primitive(PrimitiveValType::Float64)), - ValType::V128 | ValType::FuncRef | ValType::ExternRef => { + ValType::V128 | ValType::Ref(_) => { unreachable!("not used in canonical ABI") } }; @@ -1838,11 +1864,7 @@ fn inverse_scalar_canonical_abi_for( for core_ty in &core_func_ty.params { params.push(( - if core_func_ty.params.len() > 1 || u.arbitrary()? { - Some(crate::unique_non_empty_string(100, &mut names, u)?) - } else { - None - }, + crate::unique_kebab_string(100, &mut names, u)?, from_core_ty(u, *core_ty)?, )); } @@ -1853,7 +1875,7 @@ fn inverse_scalar_canonical_abi_for( 0 => Vec::new(), 1 => vec![( if u.arbitrary()? { - Some(crate::unique_non_empty_string(100, &mut names, u)?) + Some(crate::unique_kebab_string(100, &mut names, u)?) } else { None }, @@ -1974,9 +1996,6 @@ enum InstanceExportAliasKind { Instance, Func, Value, - Table, - Memory, - Global, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -1998,7 +2017,11 @@ enum ComponentTypeDef { Type(Rc), Alias(Alias), Import(Import), - Export { name: String, ty: ComponentTypeRef }, + Export { + name: KebabString, + url: Option, + ty: ComponentTypeRef, + }, } impl From for ComponentTypeDef { @@ -2006,7 +2029,7 @@ impl From for ComponentTypeDef { match def { InstanceTypeDecl::CoreType(t) => Self::CoreType(t), InstanceTypeDecl::Type(t) => Self::Type(t), - InstanceTypeDecl::Export { name, ty } => Self::Export { name, ty }, + InstanceTypeDecl::Export { name, url, ty } => Self::Export { name, url, ty }, InstanceTypeDecl::Alias(a) => Self::Alias(a), } } @@ -2022,26 +2045,20 @@ enum InstanceTypeDecl { CoreType(Rc), Type(Rc), Alias(Alias), - Export { name: String, ty: ComponentTypeRef }, + Export { + name: KebabString, + url: Option, + ty: ComponentTypeRef, + }, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct FuncType { - params: Vec<(Option, ComponentValType)>, - results: Vec<(Option, ComponentValType)>, + params: Vec<(KebabString, ComponentValType)>, + results: Vec<(Option, ComponentValType)>, } impl FuncType { - fn unnamed_param_ty(&self) -> Option { - if self.params.len() == 1 { - let (name, ty) = &self.params[0]; - if name.is_none() { - return Some(*ty); - } - } - None - } - fn unnamed_result_ty(&self) -> Option { if self.results.len() == 1 { let (name, ty) = &self.results[0]; @@ -2089,19 +2106,18 @@ enum DefinedType { Tuple(TupleType), Flags(FlagsType), Enum(EnumType), - Union(UnionType), Option(OptionType), Result(ResultType), } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct RecordType { - fields: Vec<(String, ComponentValType)>, + fields: Vec<(KebabString, ComponentValType)>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct VariantType { - cases: Vec<(String, Option, Option)>, + cases: Vec<(KebabString, Option, Option)>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -2116,17 +2132,12 @@ struct TupleType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct FlagsType { - fields: Vec, + fields: Vec, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct EnumType { - variants: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct UnionType { - variants: Vec, + variants: Vec, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -2147,7 +2158,8 @@ struct ImportSection { #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct Import { - name: String, + name: KebabString, + url: Option, ty: ComponentTypeRef, } diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs index 97c3a1c29e..c96f684a6d 100644 --- a/crates/wasm-smith/src/component/encode.rs +++ b/crates/wasm-smith/src/component/encode.rs @@ -1,4 +1,8 @@ +use std::borrow::Cow; + use super::*; +use wasm_encoder::{ComponentExportKind, ComponentOuterAliasKind, ExportKind}; +use wasmparser::names::KebabStr; impl Component { /// Encode this Wasm component into bytes. @@ -49,8 +53,8 @@ impl Section { impl CustomSection { fn encode(&self, component: &mut wasm_encoder::Component) { component.section(&wasm_encoder::CustomSection { - name: &self.name, - data: &self.data, + name: (&self.name).into(), + data: Cow::Borrowed(&self.data), }); } } @@ -69,7 +73,7 @@ impl ImportSection { fn encode(&self, component: &mut wasm_encoder::Component) { let mut sec = wasm_encoder::ComponentImportSection::new(); for imp in &self.imports { - sec.import(&imp.name, imp.ty); + sec.import(wasm_encoder::ComponentExternName::Kebab(&imp.name), imp.ty); } component.section(&sec); } @@ -159,25 +163,15 @@ impl Type { Self::Func(func_ty) => { let mut f = enc.function(); - if let Some(ty) = func_ty.unnamed_param_ty() { - f.param(ty); - } else { - f.params( - func_ty - .params - .iter() - .map(|(name, ty)| (name.as_deref().unwrap(), *ty)), - ); - } + f.params(func_ty.params.iter().map(|(name, ty)| (name.as_str(), *ty))); if let Some(ty) = func_ty.unnamed_result_ty() { f.result(ty); } else { f.results( - func_ty - .results - .iter() - .map(|(name, ty)| (name.as_deref().unwrap(), *ty)), + func_ty.results.iter().map(|(name, ty)| { + (name.as_deref().map(KebabStr::as_str).unwrap(), *ty) + }), ); } } @@ -186,7 +180,10 @@ impl Type { for def in &comp_ty.defs { match def { ComponentTypeDef::Import(imp) => { - enc_comp_ty.import(&imp.name, imp.ty); + enc_comp_ty.import( + wasm_encoder::ComponentExternName::Kebab(&imp.name), + imp.ty, + ); } ComponentTypeDef::CoreType(ty) => { ty.encode(enc_comp_ty.core_type()); @@ -194,24 +191,12 @@ impl Type { ComponentTypeDef::Type(ty) => { ty.encode(enc_comp_ty.ty()); } - ComponentTypeDef::Export { name, ty } => { - enc_comp_ty.export(name, *ty); - } - ComponentTypeDef::Alias(Alias::Outer { - count, - i, - kind: OuterAliasKind::Type(_), - }) => { - enc_comp_ty.alias_outer_type(*count, *i); + ComponentTypeDef::Export { name, url: _, ty } => { + enc_comp_ty.export(wasm_encoder::ComponentExternName::Kebab(name), *ty); } - ComponentTypeDef::Alias(Alias::Outer { - count, - i, - kind: OuterAliasKind::CoreType(_), - }) => { - enc_comp_ty.alias_outer_core_type(*count, *i); + ComponentTypeDef::Alias(a) => { + enc_comp_ty.alias(translate_alias(a)); } - ComponentTypeDef::Alias(_) => unreachable!(), } } enc.component(&enc_comp_ty); @@ -226,24 +211,12 @@ impl Type { InstanceTypeDecl::Type(ty) => { ty.encode(enc_inst_ty.ty()); } - InstanceTypeDecl::Export { name, ty } => { - enc_inst_ty.export(name, *ty); + InstanceTypeDecl::Export { name, url: _, ty } => { + enc_inst_ty.export(wasm_encoder::ComponentExternName::Kebab(name), *ty); } - InstanceTypeDecl::Alias(Alias::Outer { - count, - i, - kind: OuterAliasKind::Type(_), - }) => { - enc_inst_ty.alias_outer_type(*count, *i); + InstanceTypeDecl::Alias(a) => { + enc_inst_ty.alias(translate_alias(a)); } - InstanceTypeDecl::Alias(Alias::Outer { - count, - i, - kind: OuterAliasKind::CoreType(_), - }) => { - enc_inst_ty.alias_outer_core_type(*count, *i); - } - InstanceTypeDecl::Alias(_) => unreachable!(), } } enc.instance(&enc_inst_ty); @@ -278,9 +251,6 @@ impl DefinedType { Self::Enum(ty) => { enc.enum_type(ty.variants.iter().map(|v| v.as_str())); } - Self::Union(ty) => { - enc.union(ty.variants.iter().copied()); - } Self::Option(ty) => { enc.option(ty.inner_ty); } @@ -304,3 +274,48 @@ fn translate_canon_opt(options: &[CanonOpt]) -> Vec wasm_encoder::Alias<'_> { + match alias { + Alias::InstanceExport { + instance, + name, + kind, + } => wasm_encoder::Alias::InstanceExport { + instance: *instance, + name, + kind: match kind { + InstanceExportAliasKind::Module => ComponentExportKind::Module, + InstanceExportAliasKind::Component => ComponentExportKind::Component, + InstanceExportAliasKind::Instance => ComponentExportKind::Instance, + InstanceExportAliasKind::Func => ComponentExportKind::Func, + InstanceExportAliasKind::Value => ComponentExportKind::Value, + }, + }, + Alias::CoreInstanceExport { + instance, + name, + kind, + } => wasm_encoder::Alias::CoreInstanceExport { + instance: *instance, + name, + kind: match kind { + CoreInstanceExportAliasKind::Func => ExportKind::Func, + CoreInstanceExportAliasKind::Table => ExportKind::Table, + CoreInstanceExportAliasKind::Global => ExportKind::Global, + CoreInstanceExportAliasKind::Memory => ExportKind::Memory, + CoreInstanceExportAliasKind::Tag => ExportKind::Tag, + }, + }, + Alias::Outer { count, i, kind } => wasm_encoder::Alias::Outer { + count: *count, + index: *i, + kind: match kind { + OuterAliasKind::Module => ComponentOuterAliasKind::CoreModule, + OuterAliasKind::Component => ComponentOuterAliasKind::Component, + OuterAliasKind::Type(_) => ComponentOuterAliasKind::Type, + OuterAliasKind::CoreType(_) => ComponentOuterAliasKind::CoreType, + }, + }, + } +} diff --git a/crates/wasm-smith/src/config.rs b/crates/wasm-smith/src/config.rs index 48608f353f..ae85c6cad7 100644 --- a/crates/wasm-smith/src/config.rs +++ b/crates/wasm-smith/src/config.rs @@ -323,6 +323,14 @@ pub trait Config: 'static + std::fmt::Debug { false } + /// Determines whether the tail calls proposal is enabled for generating + /// instructions. + /// + /// Defaults to `false`. + fn tail_call_enabled(&self) -> bool { + false + } + /// Determines whether the SIMD proposal is enabled for /// generating instructions. /// @@ -467,20 +475,23 @@ pub trait Config: 'static + std::fmt::Debug { false } - /// Determines whether `call_indirect` instruction is enabled - /// in the generating module. + /// Returns whether we should avoid generating code that will possibly trap. /// - /// Defaults to `true`. - fn call_indirect_enabled(&self) -> bool { - true - } - - /// Determines whether `unreachable` instruction is enabled - /// in the generating module. + /// For some trapping instructions, this will emit extra instructions to + /// ensure they don't trap, while some instructions will simply be excluded. + /// In cases where we would run into a trap, we instead choose some + /// arbitrary non-trapping behavior. For example, if we detect that a Load + /// instruction would attempt to access out-of-bounds memory, we instead + /// pretend the load succeeded and push 0 onto the stack. /// - /// Defaults to `true`. - fn unreachable_instruction_enabled(&self) -> bool { - true + /// One type of trap that we can't currently avoid is StackOverflow. Even + /// when `disallow_traps` is set to true, wasm-smith will eventually + /// generate a program that infinitely recurses, causing the call stack to + /// be exhausted. + /// + /// Defaults to `false`. + fn disallow_traps(&self) -> bool { + false } } @@ -509,6 +520,7 @@ pub struct SwarmConfig { pub available_imports: Option>, pub bulk_memory_enabled: bool, pub canonicalize_nans: bool, + pub disallow_traps: bool, pub exceptions_enabled: bool, pub export_everything: bool, pub max_aliases: usize, @@ -548,6 +560,7 @@ pub struct SwarmConfig { pub min_uleb_size: u8, pub multi_value_enabled: bool, pub reference_types_enabled: bool, + pub tail_call_enabled: bool, pub relaxed_simd_enabled: bool, pub saturating_float_to_int_enabled: bool, pub sign_extension_enabled: bool, @@ -558,8 +571,6 @@ pub struct SwarmConfig { pub max_table_elements: u32, pub table_max_size_required: bool, pub memory_grow_enabled: bool, - pub call_indirect_enabled: bool, - pub unreachable_instruction_enabled: bool, } impl<'a> Arbitrary<'a> for SwarmConfig { @@ -606,8 +617,6 @@ impl<'a> Arbitrary<'a> for SwarmConfig { max_table_elements: u.int_in_range(0..=1_000_000)?, float_enabled: u.arbitrary()?, memory_grow_enabled: u.arbitrary()?, - call_indirect_enabled: u.arbitrary()?, - unreachable_instruction_enabled: u.arbitrary()?, // These fields, unlike the ones above, are less useful to set. // They either make weird inputs or are for features not widely @@ -638,6 +647,8 @@ impl<'a> Arbitrary<'a> for SwarmConfig { available_imports: None, threads_enabled: false, export_everything: false, + disallow_traps: false, + tail_call_enabled: false, }) } } @@ -773,6 +784,10 @@ impl Config for SwarmConfig { self.reference_types_enabled } + fn tail_call_enabled(&self) -> bool { + self.tail_call_enabled + } + fn simd_enabled(&self) -> bool { self.simd_enabled } @@ -845,11 +860,7 @@ impl Config for SwarmConfig { self.memory_grow_enabled } - fn call_indirect_enabled(&self) -> bool { - self.call_indirect_enabled - } - - fn unreachable_instruction_enabled(&self) -> bool { - self.unreachable_instruction_enabled + fn disallow_traps(&self) -> bool { + self.disallow_traps } } diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs index e18a4c5c97..83534f971e 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -2,7 +2,6 @@ mod code_builder; pub(crate) mod encode; -pub(crate) mod no_traps; mod terminate; use crate::{arbitrary_loop, limited_string, unique_string, Config, DefaultConfig}; @@ -15,7 +14,7 @@ use std::marker; use std::ops::Range; use std::rc::Rc; use std::str::{self, FromStr}; -use wasm_encoder::{BlockType, ConstExpr, ExportKind, ValType}; +use wasm_encoder::{BlockType, ConstExpr, ExportKind, HeapType, RefType, ValType}; pub(crate) use wasm_encoder::{GlobalType, MemoryType, TableType}; // NB: these constants are used to control the rate at which various events @@ -120,6 +119,9 @@ pub struct Module { /// The predicted size of the effective type of this module, based on this /// module's size of the types of imports/exports. type_size: u32, + + /// Names currently exported from this module. + export_names: HashSet, } impl<'a> Arbitrary<'a> for Module { @@ -197,6 +199,7 @@ impl Module { code: Vec::new(), data: Vec::new(), type_size: 0, + export_names: HashSet::new(), } } } @@ -240,7 +243,7 @@ pub(crate) enum Type { } /// A function signature. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) struct FuncType { /// Types of the parameter values. pub(crate) params: Vec, @@ -286,7 +289,7 @@ pub(crate) struct TagType { #[derive(Debug)] struct ElementSegment { kind: ElementKind, - ty: ValType, + ty: RefType, items: Elements, } @@ -548,19 +551,19 @@ impl Module { // index in our newly generated module. Initially the option is `None` and will become a // `Some` when we encounter an import that uses this signature in the next portion of this // function. See also the `make_func_type` closure below. - let mut available_types = Vec::<(wasmparser::Type, Option)>::new(); + let mut available_types = Vec::new(); let mut available_imports = Vec::::new(); for payload in wasmparser::Parser::new(0).parse_all(&example_module) { match payload.expect("could not parse the available import payload") { - wasmparser::Payload::TypeSection(mut type_reader) => { - for _ in 0..type_reader.get_count() { - let ty = type_reader.read().expect("could not parse type section"); + wasmparser::Payload::TypeSection(type_reader) => { + for ty in type_reader.into_iter_err_on_gc_types() { + let ty = ty.expect("could not parse type section"); available_types.push((ty, None)); } } - wasmparser::Payload::ImportSection(mut import_reader) => { - for _ in 0..import_reader.get_count() { - let im = import_reader.read().expect("could not read import"); + wasmparser::Payload::ImportSection(import_reader) => { + for im in import_reader { + let im = im.expect("could not read import"); // We can immediately filter whether this is an import we want to // use. let use_import = u.arbitrary().unwrap_or(false); @@ -588,7 +591,7 @@ impl Module { let serialized_sig_idx = match available_types.get_mut(parsed_sig_idx as usize) { None => panic!("signature index refers to a type out of bounds"), Some((_, Some(idx))) => *idx as usize, - Some((wasmparser::Type::Func(func_type), index_store)) => { + Some((func_type, index_store)) => { let multi_value_required = func_type.results().len() > 1; let new_index = first_type_index + new_types.len(); if new_index >= max_types || (multi_value_required && !multi_value_enabled) { @@ -656,7 +659,7 @@ impl Module { wasmparser::TypeRef::Table(table_ty) => { let table_ty = TableType { - element_type: convert_type(table_ty.element_type), + element_type: convert_reftype(table_ty.element_type), minimum: table_ty.initial, maximum: table_ty.maximum, }; @@ -880,14 +883,13 @@ impl Module { ValType::F32 => ConstExpr::f32_const(u.arbitrary()?), ValType::F64 => ConstExpr::f64_const(u.arbitrary()?), ValType::V128 => ConstExpr::v128_const(u.arbitrary()?), - ValType::ExternRef => ConstExpr::ref_null(ValType::ExternRef), - ValType::FuncRef => { - if num_funcs > 0 && u.arbitrary()? { + ValType::Ref(ty) => { + assert!(ty.nullable); + if ty.heap_type == HeapType::Func && num_funcs > 0 && u.arbitrary()? { let func = u.int_in_range(0..=num_funcs - 1)?; return Ok(GlobalInitExpr::FuncRef(func)); - } else { - ConstExpr::ref_null(ValType::FuncRef) } + ConstExpr::ref_null(ty.heap_type) } })) })); @@ -938,14 +940,12 @@ impl Module { .collect(), ); - let mut export_names = HashSet::new(); - // If the configuration demands exporting everything, we do so here and // early-return. if self.config.export_everything() { for choices_by_kind in choices { for (kind, idx) in choices_by_kind { - let name = unique_string(1_000, &mut export_names, u)?; + let name = unique_string(1_000, &mut self.export_names, u)?; self.add_arbitrary_export(name, kind, idx)?; } } @@ -973,7 +973,7 @@ impl Module { // Pick a name, then pick the export, and then we can record // information about the chosen export. - let name = unique_string(1_000, &mut export_names, u)?; + let name = unique_string(1_000, &mut self.export_names, u)?; let list = u.choose(&choices)?; let (kind, idx) = *u.choose(list)?; self.add_arbitrary_export(name, kind, idx)?; @@ -1022,26 +1022,39 @@ impl Module { // Create a helper closure to choose an arbitrary offset. let mut offset_global_choices = vec![]; - for (i, g) in self.globals[..self.globals.len() - self.defined_globals.len()] - .iter() - .enumerate() - { - if !g.mutable && g.val_type == ValType::I32 { - offset_global_choices.push(i as u32); + if !self.config.disallow_traps() { + for (i, g) in self.globals[..self.globals.len() - self.defined_globals.len()] + .iter() + .enumerate() + { + if !g.mutable && g.val_type == ValType::I32 { + offset_global_choices.push(i as u32); + } } } - let arbitrary_active_elem = |u: &mut Unstructured, min: u32, table: Option| { + let arbitrary_active_elem = |u: &mut Unstructured, + min_mem_size: u32, + table: Option, + disallow_traps: bool, + table_ty: &TableType| { let (offset, max_size_hint) = if !offset_global_choices.is_empty() && u.arbitrary()? { let g = u.choose(&offset_global_choices)?; (Offset::Global(*g), None) } else { - let offset = arbitrary_offset(u, min.into(), u32::MAX.into(), 0)? as u32; - let max_size_hint = - if offset <= min && u.int_in_range(0..=CHANCE_OFFSET_INBOUNDS)? != 0 { - Some(min - offset) - } else { - None - }; + let max_mem_size = if disallow_traps { + table_ty.minimum + } else { + u32::MAX + }; + let offset = + arbitrary_offset(u, min_mem_size.into(), max_mem_size.into(), 0)? as u32; + let max_size_hint = if disallow_traps + || (offset <= min_mem_size && u.int_in_range(0..=CHANCE_OFFSET_INBOUNDS)? != 0) + { + Some(min_mem_size - offset) + } else { + None + }; (Offset::Const32(offset as i32), max_size_hint) }; Ok((ElementKind::Active { table, offset }, max_size_hint)) @@ -1051,7 +1064,7 @@ impl Module { dyn Fn(&mut Unstructured) -> Result<(ElementKind, Option)> + 'a; let mut funcrefs: Vec> = Vec::new(); let mut externrefs: Vec> = Vec::new(); - + let disallow_traps = self.config().disallow_traps(); for (i, ty) in self.tables.iter().enumerate() { // If this table starts with no capacity then any non-empty element // segment placed onto it will immediately trap, which isn't too @@ -1061,7 +1074,7 @@ impl Module { continue; } - let dst = if ty.element_type == ValType::FuncRef { + let dst = if ty.element_type == RefType::FUNCREF { &mut funcrefs } else { &mut externrefs @@ -1069,12 +1082,16 @@ impl Module { let minimum = ty.minimum; // If the first table is a funcref table then it's a candidate for // the MVP encoding of element segments. - if i == 0 && ty.element_type == ValType::FuncRef { - dst.push(Box::new(move |u| arbitrary_active_elem(u, minimum, None))); + if i == 0 && ty.element_type == RefType::FUNCREF { + dst.push(Box::new(move |u| { + arbitrary_active_elem(u, minimum, None, disallow_traps, ty) + })); } if self.config.bulk_memory_enabled() { let idx = Some(i as u32); - dst.push(Box::new(move |u| arbitrary_active_elem(u, minimum, idx))); + dst.push(Box::new(move |u| { + arbitrary_active_elem(u, minimum, idx, disallow_traps, ty) + })); } } @@ -1089,10 +1106,10 @@ impl Module { let mut choices = Vec::new(); if !funcrefs.is_empty() { - choices.push((&funcrefs, ValType::FuncRef)); + choices.push((&funcrefs, RefType::FUNCREF)); } if !externrefs.is_empty() { - choices.push((&externrefs, ValType::ExternRef)); + choices.push((&externrefs, RefType::EXTERNREF)); } if choices.is_empty() { @@ -1117,13 +1134,13 @@ impl Module { // Pick whether we're going to use expression elements or // indices. Note that externrefs must use expressions, // and functions without reference types must use indices. - let items = if ty == ValType::ExternRef + let items = if ty == RefType::EXTERNREF || (self.config.reference_types_enabled() && u.arbitrary()?) { let mut init = vec![]; arbitrary_loop(u, self.config.min_elements(), max, |u| { init.push( - if ty == ValType::ExternRef || func_max == 0 || u.arbitrary()? { + if ty == RefType::EXTERNREF || func_max == 0 || u.arbitrary()? { None } else { Some(u.int_in_range(0..=func_max - 1)?) @@ -1157,6 +1174,7 @@ impl Module { let body = self.arbitrary_func_body(u, ty, &mut allocs, allow_invalid)?; self.code.push(body); } + allocs.finish(u, self)?; Ok(()) } @@ -1197,41 +1215,40 @@ impl Module { if memories == 0 && !self.config.bulk_memory_enabled() { return Ok(()); } - + let disallow_traps = self.config.disallow_traps(); let mut choices32: Vec Result>> = vec![]; choices32.push(Box::new(|u, min_size, data_len| { - Ok(Offset::Const32(arbitrary_offset( - u, - u32::try_from(min_size.saturating_mul(64 * 1024)) - .unwrap_or(u32::MAX) - .into(), - u32::MAX.into(), - data_len, - )? as i32)) + let min = u32::try_from(min_size.saturating_mul(64 * 1024)) + .unwrap_or(u32::MAX) + .into(); + let max = if disallow_traps { min } else { u32::MAX.into() }; + Ok(Offset::Const32( + arbitrary_offset(u, min, max, data_len)? as i32 + )) })); let mut choices64: Vec Result>> = vec![]; choices64.push(Box::new(|u, min_size, data_len| { - Ok(Offset::Const64(arbitrary_offset( - u, - min_size.saturating_mul(64 * 1024), - u64::MAX, - data_len, - )? as i64)) + let min = min_size.saturating_mul(64 * 1024); + let max = if disallow_traps { min } else { u64::MAX }; + Ok(Offset::Const64( + arbitrary_offset(u, min, max, data_len)? as i64 + )) })); - - for (i, g) in self.globals[..self.globals.len() - self.defined_globals.len()] - .iter() - .enumerate() - { - if g.mutable { - continue; - } - if g.val_type == ValType::I32 { - choices32.push(Box::new(move |_, _, _| Ok(Offset::Global(i as u32)))); - } else if g.val_type == ValType::I64 { - choices64.push(Box::new(move |_, _, _| Ok(Offset::Global(i as u32)))); + if !self.config().disallow_traps() { + for (i, g) in self.globals[..self.globals.len() - self.defined_globals.len()] + .iter() + .enumerate() + { + if g.mutable { + continue; + } + if g.val_type == ValType::I32 { + choices32.push(Box::new(move |_, _, _| Ok(Offset::Global(i as u32)))); + } else if g.val_type == ValType::I64 { + choices64.push(Box::new(move |_, _, _| Ok(Offset::Global(i as u32)))); + } } } @@ -1259,7 +1276,7 @@ impl Module { self.config.min_data_segments(), self.config.max_data_segments(), |u| { - let init: Vec = u.arbitrary()?; + let mut init: Vec = u.arbitrary()?; // Passive data can only be generated if bulk memory is enabled. // Otherwise if there are no memories we *only* generate passive @@ -1277,7 +1294,26 @@ impl Module { } else { u.choose(&choices32)? }; - let offset = f(u, mem.minimum, init.len())?; + let mut offset = f(u, mem.minimum, init.len())?; + + // If traps are disallowed then truncate the size of the + // data segment to the minimum size of memory to guarantee + // it will fit. Afterwards ensure that the offset of the + // data segment is in-bounds by clamping it to the + if self.config.disallow_traps() { + let max_size = (u64::MAX / 64 / 1024).min(mem.minimum) * 64 * 1024; + init.truncate(max_size as usize); + let max_offset = max_size - init.len() as u64; + match &mut offset { + Offset::Const32(x) => { + *x = (*x as u64).min(max_offset) as i32; + } + Offset::Const64(x) => { + *x = (*x as u64).min(max_offset) as i64; + } + Offset::Global(_) => unreachable!(), + } + } DataSegmentKind::Active { offset, memory_index, @@ -1303,11 +1339,18 @@ impl Module { pub(crate) fn arbitrary_limits32( u: &mut Unstructured, + min_minimum: Option, max_minimum: u32, max_required: bool, max_inbounds: u32, ) -> Result<(u32, Option)> { - let (min, max) = arbitrary_limits64(u, max_minimum.into(), max_required, max_inbounds.into())?; + let (min, max) = arbitrary_limits64( + u, + min_minimum.map(Into::into), + max_minimum.into(), + max_required, + max_inbounds.into(), + )?; Ok(( u32::try_from(min).unwrap(), max.map(|i| u32::try_from(i).unwrap()), @@ -1316,11 +1359,12 @@ pub(crate) fn arbitrary_limits32( pub(crate) fn arbitrary_limits64( u: &mut Unstructured, + min_minimum: Option, max_minimum: u64, max_required: bool, max_inbounds: u64, ) -> Result<(u64, Option)> { - let min = gradually_grow(u, 0, max_inbounds, max_minimum)?; + let min = gradually_grow(u, min_minimum.unwrap_or(0), max_inbounds, max_minimum)?; let max = if max_required || u.arbitrary().unwrap_or(false) { Some(u.int_in_range(min..=max_minimum)?) } else { @@ -1341,8 +1385,8 @@ pub(crate) fn configured_valtypes(config: &dyn Config) -> Vec { valtypes.push(ValType::V128); } if config.reference_types_enabled() { - valtypes.push(ValType::ExternRef); - valtypes.push(ValType::FuncRef); + valtypes.push(ValType::EXTERNREF); + valtypes.push(ValType::FUNCREF); } valtypes } @@ -1373,18 +1417,27 @@ pub(crate) fn arbitrary_table_type(u: &mut Unstructured, config: &dyn Config) -> // We don't want to generate tables that are too large on average, so // keep the "inbounds" limit here a bit smaller. let max_inbounds = 10_000; - let max_elements = config.max_table_elements(); + let min_elements = if config.disallow_traps() { + Some(1) + } else { + None + }; + let max_elements = min_elements.unwrap_or(0).max(config.max_table_elements()); let (minimum, maximum) = arbitrary_limits32( u, + min_elements, max_elements, config.table_max_size_required(), max_inbounds.min(max_elements), )?; + if config.disallow_traps() { + assert!(minimum > 0); + } Ok(TableType { element_type: if config.reference_types_enabled() { - *u.choose(&[ValType::FuncRef, ValType::ExternRef])? + *u.choose(&[RefType::FUNCREF, RefType::EXTERNREF])? } else { - ValType::FuncRef + RefType::FUNCREF }, minimum, maximum, @@ -1399,9 +1452,17 @@ pub(crate) fn arbitrary_memtype(u: &mut Unstructured, config: &dyn Config) -> Re // depending on the maximum number of memories. let memory64 = config.memory64_enabled() && u.arbitrary()?; let max_inbounds = 16 * 1024 / u64::try_from(config.max_memories()).unwrap(); - let max_pages = config.max_memory_pages(memory64); + let min_pages = if config.disallow_traps() { + Some(1) + } else { + None + }; + let max_pages = min_pages + .unwrap_or(0) + .max(config.max_memory_pages(memory64)); let (minimum, maximum) = arbitrary_limits64( u, + min_pages, max_pages, config.memory_max_size_required() || shared, max_inbounds.min(max_pages), @@ -1540,15 +1601,20 @@ fn gradually_grow(u: &mut Unstructured, min: u64, max_inbounds: u64, max: u64) - /// Selects a reasonable offset for an element or data segment. This favors /// having the segment being in-bounds, but it may still generate /// any offset. -fn arbitrary_offset(u: &mut Unstructured, min: u64, max: u64, size: usize) -> Result { - let size = u64::try_from(size).unwrap(); +fn arbitrary_offset( + u: &mut Unstructured, + limit_min: u64, + limit_max: u64, + segment_size: usize, +) -> Result { + let size = u64::try_from(segment_size).unwrap(); // If the segment is too big for the whole memory, just give it any // offset. - if size > min { - u.int_in_range(0..=max) + if size > limit_min { + u.int_in_range(0..=limit_max) } else { - gradually_grow(u, 0, min - size, max) + gradually_grow(u, 0, limit_min - size, limit_max) } } @@ -1572,8 +1638,26 @@ fn convert_type(parsed_type: wasmparser::ValType) -> ValType { F32 => ValType::F32, F64 => ValType::F64, V128 => ValType::V128, - FuncRef => ValType::FuncRef, - ExternRef => ValType::ExternRef, + Ref(ty) => ValType::Ref(convert_reftype(ty)), + } +} + +fn convert_reftype(ty: wasmparser::RefType) -> RefType { + wasm_encoder::RefType { + nullable: ty.is_nullable(), + heap_type: match ty.heap_type() { + wasmparser::HeapType::Func => HeapType::Func, + wasmparser::HeapType::Extern => HeapType::Extern, + wasmparser::HeapType::Any => HeapType::Any, + wasmparser::HeapType::None => HeapType::None, + wasmparser::HeapType::NoExtern => HeapType::NoExtern, + wasmparser::HeapType::NoFunc => HeapType::NoFunc, + wasmparser::HeapType::Eq => HeapType::Eq, + wasmparser::HeapType::Struct => HeapType::Struct, + wasmparser::HeapType::Array => HeapType::Array, + wasmparser::HeapType::I31 => HeapType::I31, + wasmparser::HeapType::Indexed(i) => HeapType::Indexed(i.into()), + }, } } @@ -1639,7 +1723,7 @@ flags! { /// Enumerate the categories of instructions defined in the [WebAssembly /// specification](https://webassembly.github.io/spec/core/syntax/instructions.html). #[allow(missing_docs)] - #[cfg_attr(feature = "_internal_cli", derive(serde::Deserialize))] + #[cfg_attr(feature = "_internal_cli", derive(serde_derive::Deserialize))] pub enum InstructionKind: u16 { Numeric, Vector, diff --git a/crates/wasm-smith/src/core/code_builder.rs b/crates/wasm-smith/src/core/code_builder.rs index 63bca09f0b..1fb55dbf37 100644 --- a/crates/wasm-smith/src/core/code_builder.rs +++ b/crates/wasm-smith/src/core/code_builder.rs @@ -2,10 +2,13 @@ use super::{ Elements, FuncType, GlobalInitExpr, Instruction, InstructionKind::*, InstructionKinds, Module, ValType, }; +use crate::unique_string; use arbitrary::{Result, Unstructured}; use std::collections::{BTreeMap, BTreeSet}; use std::convert::TryFrom; -use wasm_encoder::{BlockType, MemArg}; +use std::rc::Rc; +use wasm_encoder::{BlockType, ConstExpr, ExportKind, GlobalType, MemArg, RefType}; +mod no_traps; macro_rules! instructions { ( @@ -24,7 +27,7 @@ macro_rules! instructions { allowed_instructions: InstructionKinds, builder: &mut CodeBuilder, ) -> Option< - fn(&mut Unstructured<'_>, &Module, &mut CodeBuilder) -> Result + fn(&mut Unstructured<'_>, &Module, &mut CodeBuilder, &mut Vec) -> Result<()> > { builder.allocs.options.clear(); let mut cost = 0; @@ -104,6 +107,8 @@ instructions! { (Some(return_valid), r#return, Control, 900), (Some(call_valid), call, Control), (Some(call_indirect_valid), call_indirect, Control), + (Some(return_call_valid), return_call, Control), + (Some(return_call_indirect_valid), return_call_indirect, Control), (Some(throw_valid), throw, Control, 850), (Some(rethrow_valid), rethrow, Control), // Parametric instructions. @@ -313,14 +318,14 @@ instructions! { (Some(simd_have_memory_and_offset), v128_load32_zero, Vector), (Some(simd_have_memory_and_offset), v128_load64_zero, Vector), (Some(simd_v128_store_valid), v128_store, Vector), - (Some(simd_have_memory_and_offset_and_v128), v128_load8_lane, Vector), - (Some(simd_have_memory_and_offset_and_v128), v128_load16_lane, Vector), - (Some(simd_have_memory_and_offset_and_v128), v128_load32_lane, Vector), - (Some(simd_have_memory_and_offset_and_v128), v128_load64_lane, Vector), - (Some(simd_v128_store_valid), v128_store8_lane, Vector), - (Some(simd_v128_store_valid), v128_store16_lane, Vector), - (Some(simd_v128_store_valid), v128_store32_lane, Vector), - (Some(simd_v128_store_valid), v128_store64_lane, Vector), + (Some(simd_load_lane_valid), v128_load8_lane, Vector), + (Some(simd_load_lane_valid), v128_load16_lane, Vector), + (Some(simd_load_lane_valid), v128_load32_lane, Vector), + (Some(simd_load_lane_valid), v128_load64_lane, Vector), + (Some(simd_store_lane_valid), v128_store8_lane, Vector), + (Some(simd_store_lane_valid), v128_store16_lane, Vector), + (Some(simd_store_lane_valid), v128_store32_lane, Vector), + (Some(simd_store_lane_valid), v128_store64_lane, Vector), (Some(simd_enabled), v128_const, Vector), (Some(simd_v128_v128_on_stack), i8x16_shuffle, Vector), (Some(simd_v128_on_stack), i8x16_extract_lane_s, Vector), @@ -346,10 +351,10 @@ instructions! { (Some(simd_v128_v128_on_stack), i8x16_swizzle, Vector), (Some(simd_v128_v128_on_stack_relaxed), i8x16_relaxed_swizzle, Vector), (Some(simd_v128_v128_v128_on_stack), v128_bitselect, Vector), - (Some(simd_v128_v128_v128_on_stack_relaxed), i8x16_laneselect, Vector), - (Some(simd_v128_v128_v128_on_stack_relaxed), i16x8_laneselect, Vector), - (Some(simd_v128_v128_v128_on_stack_relaxed), i32x4_laneselect, Vector), - (Some(simd_v128_v128_v128_on_stack_relaxed), i64x2_laneselect, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), i8x16_relaxed_laneselect, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), i16x8_relaxed_laneselect, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), i32x4_relaxed_laneselect, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), i64x2_relaxed_laneselect, Vector), (Some(simd_v128_v128_on_stack), i8x16_eq, Vector), (Some(simd_v128_v128_on_stack), i8x16_ne, Vector), (Some(simd_v128_v128_on_stack), i8x16_lt_s, Vector), @@ -424,7 +429,7 @@ instructions! { (Some(simd_v128_v128_on_stack), i8x16_min_u, Vector), (Some(simd_v128_v128_on_stack), i8x16_max_s, Vector), (Some(simd_v128_v128_on_stack), i8x16_max_u, Vector), - (Some(simd_v128_v128_on_stack), i8x16_rounding_average_u, Vector), + (Some(simd_v128_v128_on_stack), i8x16_avgr_u, Vector), (Some(simd_v128_on_stack), i16x8_extadd_pairwise_i8x16s, Vector), (Some(simd_v128_on_stack), i16x8_extadd_pairwise_i8x16u, Vector), (Some(simd_v128_on_stack), i16x8_abs, Vector), @@ -452,7 +457,7 @@ instructions! { (Some(simd_v128_v128_on_stack), i16x8_min_u, Vector), (Some(simd_v128_v128_on_stack), i16x8_max_s, Vector), (Some(simd_v128_v128_on_stack), i16x8_max_u, Vector), - (Some(simd_v128_v128_on_stack), i16x8_rounding_average_u, Vector), + (Some(simd_v128_v128_on_stack), i16x8_avgr_u, Vector), (Some(simd_v128_v128_on_stack), i16x8_extmul_low_i8x16s, Vector), (Some(simd_v128_v128_on_stack), i16x8_extmul_high_i8x16s, Vector), (Some(simd_v128_v128_on_stack), i16x8_extmul_low_i8x16u, Vector), @@ -540,18 +545,21 @@ instructions! { (Some(simd_v128_on_stack), f64x2_convert_low_i32x4u, Vector), (Some(simd_v128_on_stack), f32x4_demote_f64x2_zero, Vector), (Some(simd_v128_on_stack), f64x2_promote_low_f32x4, Vector), - (Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_sat_f32x4s, Vector), - (Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_sat_f32x4u, Vector), - (Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_sat_f64x2s_zero, Vector), - (Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_sat_f64x2u_zero, Vector), - (Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_fma, Vector), - (Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_fms, Vector), - (Some(simd_v128_v128_v128_on_stack_relaxed), f64x2_fma, Vector), - (Some(simd_v128_v128_v128_on_stack_relaxed), f64x2_fms, Vector), + (Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_f32x4s, Vector), + (Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_f32x4u, Vector), + (Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_f64x2s_zero, Vector), + (Some(simd_v128_on_stack_relaxed), i32x4_relaxed_trunc_f64x2u_zero, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_relaxed_madd, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), f32x4_relaxed_nmadd, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), f64x2_relaxed_madd, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), f64x2_relaxed_nmadd, Vector), (Some(simd_v128_v128_on_stack_relaxed), f32x4_relaxed_min, Vector), (Some(simd_v128_v128_on_stack_relaxed), f32x4_relaxed_max, Vector), (Some(simd_v128_v128_on_stack_relaxed), f64x2_relaxed_min, Vector), (Some(simd_v128_v128_on_stack_relaxed), f64x2_relaxed_max, Vector), + (Some(simd_v128_v128_on_stack_relaxed), i16x8_relaxed_q15mulr_s, Vector), + (Some(simd_v128_v128_on_stack_relaxed), i16x8_relaxed_dot_i8x16_i7x16_s, Vector), + (Some(simd_v128_v128_v128_on_stack_relaxed), i32x4_relaxed_dot_i8x16_i7x16_add_s, Vector), } pub(crate) struct CodeBuilderAllocations { @@ -564,7 +572,7 @@ pub(crate) struct CodeBuilderAllocations { // Dynamic set of options of instruction we can generate that are known to // be valid right now. options: Vec<( - fn(&mut Unstructured, &Module, &mut CodeBuilder) -> Result, + fn(&mut Unstructured, &Module, &mut CodeBuilder, &mut Vec) -> Result<()>, u32, )>, @@ -576,7 +584,7 @@ pub(crate) struct CodeBuilderAllocations { // Like mutable globals above this is a map from function types to the list // of functions that have that function type. - functions: BTreeMap, Vec>, + functions: BTreeMap, Vec>, // Like functions above this is a map from tag types to the list of tags // have that tag type. @@ -598,6 +606,17 @@ pub(crate) struct CodeBuilderAllocations { // shouldn't ever look for i64 on the stack for `i32.load`. memory32: Vec, memory64: Vec, + + // State used when dropping operands to avoid dropping them into the ether + // but instead folding their final values into module state, at this time + // chosen to be exported globals. + globals_cnt: u32, + new_globals: Vec<(ValType, ConstExpr)>, + global_dropped_i32: Option, + global_dropped_i64: Option, + global_dropped_f32: Option, + global_dropped_f64: Option, + global_dropped_v128: Option, } pub(crate) struct CodeBuilder<'a> { @@ -677,7 +696,7 @@ impl CodeBuilderAllocations { let mut functions = BTreeMap::new(); for (idx, func) in module.funcs() { functions - .entry(func.params.to_vec()) + .entry(func.clone()) .or_insert(Vec::new()) .push(idx); } @@ -686,7 +705,7 @@ impl CodeBuilderAllocations { let mut table_tys = Vec::new(); for (i, table) in module.tables.iter().enumerate() { table_tys.push(table.element_type); - if table.element_type == ValType::FuncRef { + if table.element_type == RefType::FUNCREF { funcref_tables.push(i as u32); } } @@ -733,6 +752,14 @@ impl CodeBuilderAllocations { table_init_possible, memory32, memory64, + + global_dropped_i32: None, + global_dropped_i64: None, + global_dropped_f32: None, + global_dropped_f64: None, + global_dropped_v128: None, + globals_cnt: module.globals.len() as u32, + new_globals: Vec::new(), } } @@ -762,6 +789,27 @@ impl CodeBuilderAllocations { v128_scratch: None, } } + + pub fn finish(self, u: &mut Unstructured<'_>, module: &mut Module) -> arbitrary::Result<()> { + // Any globals injected as part of dropping operands on the stack get + // injected into the module here. Each global is then exported, most of + // the time, to ensure it's part of the "image" of this module available + // for differential execution for example. + for (ty, init) in self.new_globals { + let global_idx = module.globals.len() as u32; + module.globals.push(GlobalType { + val_type: ty, + mutable: true, + }); + let init = GlobalInitExpr::ConstExpr(init); + module.defined_globals.push((global_idx, init)); + + if u.ratio(1, 100).unwrap_or(false) { + continue; + } + } + Ok(()) + } } impl CodeBuilder<'_> { @@ -839,21 +887,28 @@ impl CodeBuilder<'_> { let keep_going = instructions.len() < max_instructions && u.arbitrary().map_or(false, |b: u8| b != 0); if !keep_going { - self.end_active_control_frames(u, &mut instructions); + self.end_active_control_frames( + u, + &mut instructions, + module.config.disallow_traps(), + )?; break; } match choose_instruction(u, module, allowed_instructions, &mut self) { Some(f) => { - let inst = f(u, module, &mut self)?; - instructions.push(inst); + f(u, module, &mut self, &mut instructions)?; } // Choosing an instruction can fail because there is not enough // underlying data, so we really cannot generate any more // instructions. In this case we swallow that error and instead // just terminate our wasm function's frames. None => { - self.end_active_control_frames(u, &mut instructions); + self.end_active_control_frames( + u, + &mut instructions, + module.config.disallow_traps(), + )?; break; } } @@ -928,25 +983,15 @@ impl CodeBuilder<'_> { // We'll need to temporarily save the top of the stack into a local, so // figure out that local here. Note that this tries to use the same // local if canonicalization happens more than once in a function. - let local = match ty { - Float::F32 => &mut self.f32_scratch, - Float::F64 => &mut self.f64_scratch, - Float::F32x4 | Float::F64x2 => &mut self.v128_scratch, + let (local, val_ty) = match ty { + Float::F32 => (&mut self.f32_scratch, ValType::F32), + Float::F64 => (&mut self.f64_scratch, ValType::F64), + Float::F32x4 | Float::F64x2 => (&mut self.v128_scratch, ValType::V128), }; let local = match *local { - Some(i) => i, - None => { - let val = self.locals.len() + self.func_ty.params.len() + self.extra_locals.len(); - *local = Some(val); - self.extra_locals.push(match ty { - Float::F32 => ValType::F32, - Float::F64 => ValType::F64, - Float::F32x4 | Float::F64x2 => ValType::V128, - }); - val - } + Some(i) => i as u32, + None => self.alloc_local(val_ty), }; - let local = local as u32; // Save the previous instruction's result into a local. This also leaves // a value on the stack as `val1` for the `select` instruction. @@ -996,15 +1041,22 @@ impl CodeBuilder<'_> { }); } + fn alloc_local(&mut self, ty: ValType) -> u32 { + let val = self.locals.len() + self.func_ty.params.len() + self.extra_locals.len(); + self.extra_locals.push(ty); + u32::try_from(val).unwrap() + } + fn end_active_control_frames( &mut self, u: &mut Unstructured<'_>, instructions: &mut Vec, - ) { + disallow_traps: bool, + ) -> Result<()> { while !self.allocs.controls.is_empty() { // Ensure that this label is valid by placing the right types onto // the operand stack for the end of the label. - self.guarantee_label_results(u, instructions); + self.guarantee_label_results(u, instructions, disallow_traps)?; // Remove the label and clear the operand stack since the label has // been removed. @@ -1020,7 +1072,7 @@ impl CodeBuilder<'_> { self.allocs .operands .extend(label.params.into_iter().map(Some)); - self.guarantee_label_results(u, instructions); + self.guarantee_label_results(u, instructions, disallow_traps)?; self.allocs.controls.pop(); self.allocs.operands.truncate(label.height); } @@ -1037,6 +1089,7 @@ impl CodeBuilder<'_> { .operands .extend(label.results.into_iter().map(Some)); } + Ok(()) } /// Modifies the instruction stream to guarantee that the current control @@ -1045,21 +1098,22 @@ impl CodeBuilder<'_> { &mut self, u: &mut Unstructured<'_>, instructions: &mut Vec, - ) { - let mut operands = self.operands(); + disallow_traps: bool, + ) -> Result<()> { + let operands = self.operands(); let label = self.allocs.controls.last().unwrap(); // Already done, yay! if label.results.len() == operands.len() && self.types_on_stack(&label.results) { - return; + return Ok(()); } // Generating an unreachable instruction is always a valid way to // generate any types for a label, but it's not too interesting, so // don't favor it. - if u.arbitrary::().unwrap_or(0) == 1 { + if !disallow_traps && u.ratio(1, u16::MAX)? { instructions.push(Instruction::Unreachable); - return; + return Ok(()); } // Arbitrarily massage the stack to get the expected results. First we @@ -1068,22 +1122,129 @@ impl CodeBuilder<'_> { // up, figuring out what matches and what doesn't. As soon as something // doesn't match we throw out that and everything else remaining, // filling in results with dummy values. - while operands.len() > label.results.len() { - instructions.push(Instruction::Drop); + let operands = operands.to_vec(); + let mut operands = operands.as_slice(); + let label_results = label.results.to_vec(); + while operands.len() > label_results.len() { + self.drop_operand(u, *operands.last().unwrap(), instructions)?; operands = &operands[..operands.len() - 1]; } - for (i, expected) in label.results.iter().enumerate() { + for (i, expected) in label_results.iter().enumerate() { if let Some(actual) = operands.get(i) { if Some(*expected) == *actual { continue; } - for _ in operands[i..].iter() { - instructions.push(Instruction::Drop); + for ty in operands[i..].iter().rev() { + self.drop_operand(u, *ty, instructions)?; } operands = &[]; } instructions.push(arbitrary_val(*expected, u)); } + Ok(()) + } + + fn drop_operand( + &mut self, + u: &mut Unstructured<'_>, + ty: Option, + instructions: &mut Vec, + ) -> Result<()> { + if !self.mix_operand_into_global(u, ty, instructions)? { + instructions.push(Instruction::Drop); + } + Ok(()) + } + + /// Attempts to drop the top operand on the stack by "mixing" it into a + /// global. + /// + /// This is done to avoid dropping values on the floor to ensure that + /// everything is part of some computation somewhere. Otherwise, for + /// example, most function results are dropped on the floor as the stack + /// won't happen to match the function type that we're generating. + /// + /// This will return `true` if the operand has been dropped, and `false` if + /// it didn't for one reason or another. + fn mix_operand_into_global( + &mut self, + u: &mut Unstructured<'_>, + ty: Option, + instructions: &mut Vec, + ) -> Result { + // If the type of this operand isn't known, for example if it's relevant + // to unreachable code, then it can't be combined, so return `false`. + let ty = match ty { + Some(ty) => ty, + None => return Ok(false), + }; + + // Use the input stream to allow a small chance of dropping the value + // without combining it. + if u.ratio(1, 100)? { + return Ok(false); + } + + // Depending on the type lookup or inject a global to place this value + // into. + let (global, combine) = match ty { + ValType::I32 => { + let global = *self.allocs.global_dropped_i32.get_or_insert_with(|| { + self.allocs.new_globals.push((ty, ConstExpr::i32_const(0))); + inc(&mut self.allocs.globals_cnt) + }); + (global, Instruction::I32Xor) + } + ValType::I64 => { + let global = *self.allocs.global_dropped_i64.get_or_insert_with(|| { + self.allocs.new_globals.push((ty, ConstExpr::i64_const(0))); + inc(&mut self.allocs.globals_cnt) + }); + (global, Instruction::I64Xor) + } + ValType::F32 => { + let global = *self.allocs.global_dropped_f32.get_or_insert_with(|| { + self.allocs + .new_globals + .push((ValType::I32, ConstExpr::i32_const(0))); + inc(&mut self.allocs.globals_cnt) + }); + instructions.push(Instruction::I32ReinterpretF32); + (global, Instruction::I32Xor) + } + ValType::F64 => { + let global = *self.allocs.global_dropped_f64.get_or_insert_with(|| { + self.allocs + .new_globals + .push((ValType::I64, ConstExpr::i64_const(0))); + inc(&mut self.allocs.globals_cnt) + }); + instructions.push(Instruction::I64ReinterpretF64); + (global, Instruction::I64Xor) + } + ValType::V128 => { + let global = *self.allocs.global_dropped_v128.get_or_insert_with(|| { + self.allocs.new_globals.push((ty, ConstExpr::v128_const(0))); + inc(&mut self.allocs.globals_cnt) + }); + (global, Instruction::V128Xor) + } + + // Don't know how to combine reference types at this time, so just + // let it get dropped. + ValType::Ref(_) => return Ok(false), + }; + instructions.push(Instruction::GlobalGet(global)); + instructions.push(combine); + instructions.push(Instruction::GlobalSet(global)); + + return Ok(true); + + fn inc(val: &mut u32) -> u32 { + let ret = *val; + *val += 1; + ret + } } } @@ -1094,25 +1255,44 @@ fn arbitrary_val(ty: ValType, u: &mut Unstructured<'_>) -> Instruction { ValType::F32 => Instruction::F32Const(u.arbitrary().unwrap_or(0.0)), ValType::F64 => Instruction::F64Const(u.arbitrary().unwrap_or(0.0)), ValType::V128 => Instruction::V128Const(u.arbitrary().unwrap_or(0)), - ValType::ExternRef => Instruction::RefNull(ValType::ExternRef), - ValType::FuncRef => Instruction::RefNull(ValType::FuncRef), + ValType::Ref(ty) => { + assert!(ty.nullable); + Instruction::RefNull(ty.heap_type) + } } } #[inline] fn unreachable_valid(module: &Module, _: &mut CodeBuilder) -> bool { - module.config.unreachable_instruction_enabled() + !module.config.disallow_traps() } -fn unreachable(_: &mut Unstructured, _: &Module, _: &mut CodeBuilder) -> Result { - Ok(Instruction::Unreachable) +fn unreachable( + _: &mut Unstructured, + _: &Module, + _: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { + instructions.push(Instruction::Unreachable); + Ok(()) } -fn nop(_: &mut Unstructured, _: &Module, _: &mut CodeBuilder) -> Result { - Ok(Instruction::Nop) +fn nop( + _: &mut Unstructured, + _: &Module, + _: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { + instructions.push(Instruction::Nop); + Ok(()) } -fn block(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Result { +fn block( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let block_ty = builder.arbitrary_block_type(u, module)?; let (params, results) = module.params_results(&block_ty); let height = builder.allocs.operands.len() - params.len(); @@ -1122,7 +1302,8 @@ fn block(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Re results, height, }); - Ok(Instruction::Block(block_ty)) + instructions.push(Instruction::Block(block_ty)); + Ok(()) } #[inline] @@ -1130,7 +1311,12 @@ fn try_valid(module: &Module, _: &mut CodeBuilder) -> bool { module.config.exceptions_enabled() } -fn r#try(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Result { +fn r#try( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let block_ty = builder.arbitrary_block_type(u, module)?; let (params, results) = module.params_results(&block_ty); let height = builder.allocs.operands.len() - params.len(); @@ -1140,7 +1326,8 @@ fn r#try(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Re results, height, }); - Ok(Instruction::Try(block_ty)) + instructions.push(Instruction::Try(block_ty)); + Ok(()) } #[inline] @@ -1152,7 +1339,12 @@ fn delegate_valid(module: &Module, builder: &mut CodeBuilder) -> bool { && end_valid(module, builder) } -fn delegate(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn delegate( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { // There will always be at least the function's return frame and try // control frame if we are emitting delegate let n = builder.allocs.controls.iter().count(); @@ -1163,7 +1355,8 @@ fn delegate(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Resu let target_relative_from_outer = target_relative_from_last - 1; // Delegate ends the try block builder.allocs.controls.pop(); - Ok(Instruction::Delegate(target_relative_from_outer as u32)) + instructions.push(Instruction::Delegate(target_relative_from_outer as u32)); + Ok(()) } #[inline] @@ -1177,7 +1370,12 @@ fn catch_valid(module: &Module, builder: &mut CodeBuilder) -> bool { && module.tags.len() > 0 } -fn catch(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Result { +fn catch( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let tag_idx = u.int_in_range(0..=(module.tags.len() - 1))?; let tag_type = &module.tags[tag_idx]; let control = builder.allocs.controls.pop().unwrap(); @@ -1189,7 +1387,8 @@ fn catch(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Re kind: ControlKind::Catch, ..control }); - Ok(Instruction::Catch(tag_idx as u32)) + instructions.push(Instruction::Catch(tag_idx as u32)); + Ok(()) } #[inline] @@ -1202,7 +1401,12 @@ fn catch_all_valid(module: &Module, builder: &mut CodeBuilder) -> bool { && end_valid(module, builder) } -fn catch_all(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn catch_all( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let control = builder.allocs.controls.pop().unwrap(); // Pop the results for the previous try or catch builder.pop_operands(&control.results); @@ -1210,10 +1414,16 @@ fn catch_all(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Res kind: ControlKind::CatchAll, ..control }); - Ok(Instruction::CatchAll) + instructions.push(Instruction::CatchAll); + Ok(()) } -fn r#loop(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Result { +fn r#loop( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let block_ty = builder.arbitrary_block_type(u, module)?; let (params, results) = module.params_results(&block_ty); let height = builder.allocs.operands.len() - params.len(); @@ -1223,7 +1433,8 @@ fn r#loop(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> R results, height, }); - Ok(Instruction::Loop(block_ty)) + instructions.push(Instruction::Loop(block_ty)); + Ok(()) } #[inline] @@ -1231,7 +1442,12 @@ fn if_valid(_: &Module, builder: &mut CodeBuilder) -> bool { builder.type_on_stack(ValType::I32) } -fn r#if(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Result { +fn r#if( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let block_ty = builder.arbitrary_block_type(u, module)?; @@ -1243,7 +1459,8 @@ fn r#if(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Res results, height, }); - Ok(Instruction::If(block_ty)) + instructions.push(Instruction::If(block_ty)); + Ok(()) } #[inline] @@ -1254,7 +1471,12 @@ fn else_valid(_: &Module, builder: &mut CodeBuilder) -> bool { && builder.types_on_stack(&last_control.results) } -fn r#else(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn r#else( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let control = builder.allocs.controls.pop().unwrap(); builder.pop_operands(&control.results); builder.push_operands(&control.params); @@ -1262,7 +1484,8 @@ fn r#else(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result kind: ControlKind::Block, ..control }); - Ok(Instruction::Else) + instructions.push(Instruction::Else); + Ok(()) } #[inline] @@ -1280,9 +1503,15 @@ fn end_valid(_: &Module, builder: &mut CodeBuilder) -> bool { && !(control.kind == ControlKind::If && control.params != control.results) } -fn end(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn end( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.allocs.controls.pop(); - Ok(Instruction::End) + instructions.push(Instruction::End); + Ok(()) } #[inline] @@ -1294,7 +1523,12 @@ fn br_valid(_: &Module, builder: &mut CodeBuilder) -> bool { .any(|l| builder.label_types_on_stack(l)) } -fn br(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn br( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let n = builder .allocs .controls @@ -1315,7 +1549,8 @@ fn br(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result bool { is_valid } -fn br_if(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn br_if( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let n = builder @@ -1353,7 +1593,8 @@ fn br_if(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result< .filter(|(_, l)| builder.label_types_on_stack(l)) .nth(i) .unwrap(); - Ok(Instruction::BrIf(target as u32)) + instructions.push(Instruction::BrIf(target as u32)); + Ok(()) } #[inline] @@ -1367,7 +1608,12 @@ fn br_table_valid(module: &Module, builder: &mut CodeBuilder) -> bool { is_valid } -fn br_table(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn br_table( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let n = builder @@ -1403,7 +1649,8 @@ fn br_table(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Resu let tys = control.label_types().to_vec(); builder.pop_operands(&tys); - Ok(Instruction::BrTable(targets, default_target as u32)) + instructions.push(Instruction::BrTable(targets, default_target as u32)); + Ok(()) } #[inline] @@ -1411,10 +1658,16 @@ fn return_valid(_: &Module, builder: &mut CodeBuilder) -> bool { builder.label_types_on_stack(&builder.allocs.controls[0]) } -fn r#return(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn r#return( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let results = builder.allocs.controls[0].results.clone(); builder.pop_operands(&results); - Ok(Instruction::Return) + instructions.push(Instruction::Return); + Ok(()) } #[inline] @@ -1423,15 +1676,20 @@ fn call_valid(_: &Module, builder: &mut CodeBuilder) -> bool { .allocs .functions .keys() - .any(|k| builder.types_on_stack(k)) + .any(|func_ty| builder.types_on_stack(&func_ty.params)) } -fn call(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Result { +fn call( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let candidates = builder .allocs .functions .iter() - .filter(|(k, _)| builder.types_on_stack(k)) + .filter(|(func_ty, _)| builder.types_on_stack(&func_ty.params)) .flat_map(|(_, v)| v.iter().copied()) .collect::>(); assert!(candidates.len() > 0); @@ -1439,18 +1697,22 @@ fn call(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Res let (func_idx, ty) = module.funcs().nth(candidates[i] as usize).unwrap(); builder.pop_operands(&ty.params); builder.push_operands(&ty.results); - Ok(Instruction::Call(func_idx as u32)) + instructions.push(Instruction::Call(func_idx as u32)); + Ok(()) } #[inline] fn call_indirect_valid(module: &Module, builder: &mut CodeBuilder) -> bool { - if !module.config.call_indirect_enabled() - || builder.allocs.funcref_tables.is_empty() - || !builder.type_on_stack(ValType::I32) - { + if builder.allocs.funcref_tables.is_empty() || !builder.type_on_stack(ValType::I32) { + return false; + } + if module.config.disallow_traps() { + // We have no way to reflect, at run time, on a `funcref` in + // the `i`th slot in a table and dynamically avoid trapping + // `call_indirect`s. Therefore, we can't emit *any* + // `call_indirect` instructions if we want to avoid traps. return false; } - let ty = builder.allocs.operands.pop().unwrap(); let is_valid = module .func_types() @@ -1463,7 +1725,8 @@ fn call_indirect( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let choices = module @@ -1474,12 +1737,99 @@ fn call_indirect( builder.pop_operands(&ty.params); builder.push_operands(&ty.results); let table = *u.choose(&builder.allocs.funcref_tables)?; - Ok(Instruction::CallIndirect { + instructions.push(Instruction::CallIndirect { ty: *type_idx as u32, table, + }); + Ok(()) +} + +#[inline] +fn return_call_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + if !module.config.tail_call_enabled() { + return false; + } + + builder.allocs.functions.keys().any(|func_ty| { + builder.types_on_stack(&func_ty.params) + && builder.allocs.controls[0].label_types() == &func_ty.results }) } +fn return_call( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { + let candidates = builder + .allocs + .functions + .iter() + .filter(|(func_ty, _)| { + builder.types_on_stack(&func_ty.params) + && builder.allocs.controls[0].label_types() == &func_ty.results + }) + .flat_map(|(_, v)| v.iter().copied()) + .collect::>(); + assert!(candidates.len() > 0); + let i = u.int_in_range(0..=candidates.len() - 1)?; + let (func_idx, ty) = module.funcs().nth(candidates[i] as usize).unwrap(); + builder.pop_operands(&ty.params); + builder.push_operands(&ty.results); + instructions.push(Instruction::ReturnCall(func_idx as u32)); + Ok(()) +} + +#[inline] +fn return_call_indirect_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + if !module.config.tail_call_enabled() + || builder.allocs.funcref_tables.is_empty() + || !builder.type_on_stack(ValType::I32) + { + return false; + } + + if module.config.disallow_traps() { + // See comment in `call_indirect_valid`; same applies here. + return false; + } + + let ty = builder.allocs.operands.pop().unwrap(); + let is_valid = module.func_types().any(|(_, ty)| { + builder.types_on_stack(&ty.params) + && builder.allocs.controls[0].label_types() == &ty.results + }); + builder.allocs.operands.push(ty); + is_valid +} + +fn return_call_indirect( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { + builder.pop_operands(&[ValType::I32]); + + let choices = module + .func_types() + .filter(|(_, ty)| { + builder.types_on_stack(&ty.params) + && builder.allocs.controls[0].label_types() == &ty.results + }) + .collect::>(); + let (type_idx, ty) = u.choose(&choices)?; + builder.pop_operands(&ty.params); + builder.push_operands(&ty.results); + let table = *u.choose(&builder.allocs.funcref_tables)?; + instructions.push(Instruction::ReturnCallIndirect { + ty: *type_idx as u32, + table, + }); + Ok(()) +} + #[inline] fn throw_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.exceptions_enabled() @@ -1490,7 +1840,12 @@ fn throw_valid(module: &Module, builder: &mut CodeBuilder) -> bool { .any(|k| builder.types_on_stack(k)) } -fn throw(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Result { +fn throw( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let candidates = builder .allocs .tags @@ -1504,7 +1859,8 @@ fn throw(u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder) -> Re // Tags have no results, throwing cannot return assert!(tag_type.func_type.results.len() == 0); builder.pop_operands(&tag_type.func_type.params); - Ok(Instruction::Throw(tag_idx as u32)) + instructions.push(Instruction::Throw(tag_idx as u32)); + Ok(()) } #[inline] @@ -1518,7 +1874,12 @@ fn rethrow_valid(module: &Module, builder: &mut CodeBuilder) -> bool { .any(|l| l.kind == ControlKind::Catch || l.kind == ControlKind::CatchAll) } -fn rethrow(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn rethrow( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let n = builder .allocs .controls @@ -1536,7 +1897,8 @@ fn rethrow(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Resul .filter(|(_, l)| l.kind == ControlKind::Catch || l.kind == ControlKind::CatchAll) .nth(i) .unwrap(); - Ok(Instruction::Rethrow(target as u32)) + instructions.push(Instruction::Rethrow(target as u32)); + Ok(()) } #[inline] @@ -1544,9 +1906,15 @@ fn drop_valid(_: &Module, builder: &mut CodeBuilder) -> bool { !builder.operands().is_empty() } -fn drop(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { - builder.allocs.operands.pop(); - Ok(Instruction::Drop) +fn drop( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { + let ty = builder.allocs.operands.pop().unwrap(); + builder.drop_operand(u, ty, instructions)?; + Ok(()) } #[inline] @@ -1559,19 +1927,23 @@ fn select_valid(_: &Module, builder: &mut CodeBuilder) -> bool { t.is_none() || u.is_none() || t == u } -fn select(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn select( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.allocs.operands.pop(); let t = builder.allocs.operands.pop().unwrap(); let u = builder.allocs.operands.pop().unwrap(); let ty = t.or(u); builder.allocs.operands.push(ty); match ty { - Some(ty @ ValType::ExternRef) | Some(ty @ ValType::FuncRef) => { - Ok(Instruction::TypedSelect(ty)) - } + Some(ty @ ValType::Ref(_)) => instructions.push(Instruction::TypedSelect(ty)), Some(ValType::I32) | Some(ValType::I64) | Some(ValType::F32) | Some(ValType::F64) - | Some(ValType::V128) | None => Ok(Instruction::Select), + | Some(ValType::V128) | None => instructions.push(Instruction::Select), } + Ok(()) } #[inline] @@ -1579,7 +1951,12 @@ fn local_get_valid(_: &Module, builder: &mut CodeBuilder) -> bool { !builder.func_ty.params.is_empty() || !builder.locals.is_empty() } -fn local_get(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn local_get( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let num_params = builder.func_ty.params.len(); let n = num_params + builder.locals.len(); debug_assert!(n > 0); @@ -1589,7 +1966,8 @@ fn local_get(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Res } else { builder.locals[i - num_params] })); - Ok(Instruction::LocalGet(i as u32)) + instructions.push(Instruction::LocalGet(i as u32)); + Ok(()) } #[inline] @@ -1602,7 +1980,12 @@ fn local_set_valid(_: &Module, builder: &mut CodeBuilder) -> bool { .any(|ty| builder.type_on_stack(*ty)) } -fn local_set(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn local_set( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let n = builder .func_ty .params @@ -1622,10 +2005,16 @@ fn local_set(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Res .nth(i) .unwrap(); builder.allocs.operands.pop(); - Ok(Instruction::LocalSet(j as u32)) + instructions.push(Instruction::LocalSet(j as u32)); + Ok(()) } -fn local_tee(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn local_tee( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let n = builder .func_ty .params @@ -1644,7 +2033,8 @@ fn local_tee(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Res .filter(|(_, ty)| builder.type_on_stack(**ty)) .nth(i) .unwrap(); - Ok(Instruction::LocalTee(j as u32)) + instructions.push(Instruction::LocalTee(j as u32)); + Ok(()) } #[inline] @@ -1656,14 +2046,16 @@ fn global_get( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { debug_assert!(module.globals.len() > 0); let global_idx = u.int_in_range(0..=module.globals.len() - 1)?; builder .allocs .operands .push(Some(module.globals[global_idx].val_type)); - Ok(Instruction::GlobalGet(global_idx as u32)) + instructions.push(Instruction::GlobalGet(global_idx as u32)); + Ok(()) } #[inline] @@ -1675,7 +2067,12 @@ fn global_set_valid(_: &Module, builder: &mut CodeBuilder) -> bool { .any(|(ty, _)| builder.type_on_stack(*ty)) } -fn global_set(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn global_set( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let candidates = builder .allocs .mutable_globals @@ -1685,7 +2082,8 @@ fn global_set(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Re .1; let i = u.int_in_range(0..=candidates.len() - 1)?; builder.allocs.operands.pop(); - Ok(Instruction::GlobalSet(candidates[i])) + instructions.push(Instruction::GlobalSet(candidates[i])); + Ok(()) } #[inline] @@ -1720,140 +2118,274 @@ fn i32_load( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1, 2])?; builder.allocs.operands.push(Some(ValType::I32)); - Ok(Instruction::I32Load(memarg)) + if module.config.disallow_traps() { + no_traps::load(Instruction::I32Load(memarg), module, builder, instructions); + } else { + instructions.push(Instruction::I32Load(memarg)); + } + Ok(()) } fn i64_load( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1, 2, 3])?; builder.allocs.operands.push(Some(ValType::I64)); - Ok(Instruction::I64Load(memarg)) + if module.config.disallow_traps() { + no_traps::load(Instruction::I64Load(memarg), module, builder, instructions); + } else { + instructions.push(Instruction::I64Load(memarg)); + } + Ok(()) } fn f32_load( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1, 2])?; builder.allocs.operands.push(Some(ValType::F32)); - Ok(Instruction::F32Load(memarg)) + if module.config.disallow_traps() { + no_traps::load(Instruction::F32Load(memarg), module, builder, instructions); + } else { + instructions.push(Instruction::F32Load(memarg)); + } + Ok(()) } fn f64_load( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1, 2, 3])?; builder.allocs.operands.push(Some(ValType::F64)); - Ok(Instruction::F64Load(memarg)) + if module.config.disallow_traps() { + no_traps::load(Instruction::F64Load(memarg), module, builder, instructions); + } else { + instructions.push(Instruction::F64Load(memarg)); + } + Ok(()) } fn i32_load_8_s( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0])?; builder.allocs.operands.push(Some(ValType::I32)); - Ok(Instruction::I32Load8_S(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I32Load8S(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I32Load8S(memarg)); + } + Ok(()) } fn i32_load_8_u( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0])?; builder.allocs.operands.push(Some(ValType::I32)); - Ok(Instruction::I32Load8_U(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I32Load8U(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I32Load8U(memarg)); + } + Ok(()) } fn i32_load_16_s( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1])?; builder.allocs.operands.push(Some(ValType::I32)); - Ok(Instruction::I32Load16_S(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I32Load16S(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I32Load16S(memarg)); + } + Ok(()) } fn i32_load_16_u( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1])?; builder.allocs.operands.push(Some(ValType::I32)); - Ok(Instruction::I32Load16_U(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I32Load16U(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I32Load16U(memarg)); + } + Ok(()) } fn i64_load_8_s( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0])?; builder.allocs.operands.push(Some(ValType::I64)); - Ok(Instruction::I64Load8_S(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I64Load8S(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Load8S(memarg)); + } + Ok(()) } fn i64_load_16_s( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1])?; builder.allocs.operands.push(Some(ValType::I64)); - Ok(Instruction::I64Load16_S(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I64Load16S(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Load16S(memarg)); + } + Ok(()) } fn i64_load_32_s( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1, 2])?; builder.allocs.operands.push(Some(ValType::I64)); - Ok(Instruction::I64Load32_S(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I64Load32S(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Load32S(memarg)); + } + Ok(()) } fn i64_load_8_u( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0])?; builder.allocs.operands.push(Some(ValType::I64)); - Ok(Instruction::I64Load8_U(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I64Load8U(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Load8U(memarg)); + } + Ok(()) } fn i64_load_16_u( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1])?; builder.allocs.operands.push(Some(ValType::I64)); - Ok(Instruction::I64Load16_U(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I64Load16U(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Load16U(memarg)); + } + Ok(()) } fn i64_load_32_u( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let memarg = mem_arg(u, module, builder, &[0, 1, 2])?; builder.allocs.operands.push(Some(ValType::I64)); - Ok(Instruction::I64Load32_U(memarg)) + if module.config.disallow_traps() { + no_traps::load( + Instruction::I64Load32U(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Load32U(memarg)); + } + Ok(()) } #[inline] @@ -1871,10 +2403,16 @@ fn i32_store( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let memarg = mem_arg(u, module, builder, &[0, 1, 2])?; - Ok(Instruction::I32Store(memarg)) + if module.config.disallow_traps() { + no_traps::store(Instruction::I32Store(memarg), module, builder, instructions); + } else { + instructions.push(Instruction::I32Store(memarg)); + } + Ok(()) } #[inline] @@ -1886,10 +2424,16 @@ fn i64_store( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); let memarg = mem_arg(u, module, builder, &[0, 1, 2, 3])?; - Ok(Instruction::I64Store(memarg)) + if module.config.disallow_traps() { + no_traps::store(Instruction::I64Store(memarg), module, builder, instructions); + } else { + instructions.push(Instruction::I64Store(memarg)); + } + Ok(()) } #[inline] @@ -1901,10 +2445,16 @@ fn f32_store( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); let memarg = mem_arg(u, module, builder, &[0, 1, 2])?; - Ok(Instruction::F32Store(memarg)) + if module.config.disallow_traps() { + no_traps::store(Instruction::F32Store(memarg), module, builder, instructions); + } else { + instructions.push(Instruction::F32Store(memarg)); + } + Ok(()) } #[inline] @@ -1916,67 +2466,129 @@ fn f64_store( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); let memarg = mem_arg(u, module, builder, &[0, 1, 2, 3])?; - Ok(Instruction::F64Store(memarg)) + if module.config.disallow_traps() { + no_traps::store(Instruction::F64Store(memarg), module, builder, instructions); + } else { + instructions.push(Instruction::F64Store(memarg)); + } + Ok(()) } fn i32_store_8( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let memarg = mem_arg(u, module, builder, &[0])?; - Ok(Instruction::I32Store8(memarg)) + if module.config.disallow_traps() { + no_traps::store( + Instruction::I32Store8(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I32Store8(memarg)); + } + Ok(()) } fn i32_store_16( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let memarg = mem_arg(u, module, builder, &[0, 1])?; - Ok(Instruction::I32Store16(memarg)) + if module.config.disallow_traps() { + no_traps::store( + Instruction::I32Store16(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I32Store16(memarg)); + } + Ok(()) } fn i64_store_8( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); let memarg = mem_arg(u, module, builder, &[0])?; - Ok(Instruction::I64Store8(memarg)) + if module.config.disallow_traps() { + no_traps::store( + Instruction::I64Store8(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Store8(memarg)); + } + Ok(()) } fn i64_store_16( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); let memarg = mem_arg(u, module, builder, &[0, 1])?; - Ok(Instruction::I64Store16(memarg)) + if module.config.disallow_traps() { + no_traps::store( + Instruction::I64Store16(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Store16(memarg)); + } + Ok(()) } fn i64_store_32( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); let memarg = mem_arg(u, module, builder, &[0, 1, 2])?; - Ok(Instruction::I64Store32(memarg)) + if module.config.disallow_traps() { + no_traps::store( + Instruction::I64Store32(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::I64Store32(memarg)); + } + Ok(()) } fn memory_size( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let i = u.int_in_range(0..=module.memories.len() - 1)?; let ty = if module.memories[i].memory64 { ValType::I64 @@ -1984,7 +2596,8 @@ fn memory_size( ValType::I32 }; builder.push_operands(&[ty]); - Ok(Instruction::MemorySize(i as u32)) + instructions.push(Instruction::MemorySize(i as u32)); + Ok(()) } #[inline] @@ -1998,7 +2611,8 @@ fn memory_grow( u: &mut Unstructured, _module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let ty = if builder.type_on_stack(ValType::I32) { ValType::I32 } else { @@ -2007,13 +2621,15 @@ fn memory_grow( let index = memory_index(u, builder, ty)?; builder.pop_operands(&[ty]); builder.push_operands(&[ty]); - Ok(Instruction::MemoryGrow(index)) + instructions.push(Instruction::MemoryGrow(index)); + Ok(()) } #[inline] fn memory_init_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.bulk_memory_enabled() && have_data(module, builder) + && !module.config.disallow_traps() // Non-trapping memory init not yet implemented && (builder.allocs.memory32.len() > 0 && builder.types_on_stack(&[ValType::I32, ValType::I32, ValType::I32]) || (builder.allocs.memory64.len() > 0 @@ -2024,7 +2640,8 @@ fn memory_init( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); let ty = if builder.type_on_stack(ValType::I32) { ValType::I32 @@ -2032,14 +2649,16 @@ fn memory_init( ValType::I64 }; let mem = memory_index(u, builder, ty)?; - let data = data_index(u, module)?; + let data_index = data_index(u, module)?; builder.pop_operands(&[ty]); - Ok(Instruction::MemoryInit { mem, data }) + instructions.push(Instruction::MemoryInit { mem, data_index }); + Ok(()) } #[inline] fn memory_fill_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.bulk_memory_enabled() + && !module.config.disallow_traps() // Non-trapping memory fill generation not yet implemented && (builder.allocs.memory32.len() > 0 && builder.types_on_stack(&[ValType::I32, ValType::I32, ValType::I32]) || (builder.allocs.memory64.len() > 0 @@ -2050,7 +2669,8 @@ fn memory_fill( u: &mut Unstructured, _module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let ty = if builder.type_on_stack(ValType::I32) { ValType::I32 } else { @@ -2058,7 +2678,8 @@ fn memory_fill( }; let mem = memory_index(u, builder, ty)?; builder.pop_operands(&[ty, ValType::I32, ty]); - Ok(Instruction::MemoryFill(mem)) + instructions.push(Instruction::MemoryFill(mem)); + Ok(()) } #[inline] @@ -2067,6 +2688,12 @@ fn memory_copy_valid(module: &Module, builder: &mut CodeBuilder) -> bool { return false; } + // The non-trapping case for memory copy has not yet been implemented, + // so we are excluding them for now + if module.config.disallow_traps() { + return false; + } + if builder.types_on_stack(&[ValType::I64, ValType::I64, ValType::I64]) && builder.allocs.memory64.len() > 0 { @@ -2096,8 +2723,10 @@ fn memory_copy( u: &mut Unstructured, _module: &Module, builder: &mut CodeBuilder, -) -> Result { - let (src, dst) = if builder.types_on_stack(&[ValType::I64, ValType::I64, ValType::I64]) { + instructions: &mut Vec, +) -> Result<()> { + let (src_mem, dst_mem) = if builder.types_on_stack(&[ValType::I64, ValType::I64, ValType::I64]) + { builder.pop_operands(&[ValType::I64, ValType::I64, ValType::I64]); ( memory_index(u, builder, ValType::I64)?, @@ -2124,7 +2753,8 @@ fn memory_copy( } else { unreachable!() }; - Ok(Instruction::MemoryCopy { dst, src }) + instructions.push(Instruction::MemoryCopy { dst_mem, src_mem }); + Ok(()) } #[inline] @@ -2136,32 +2766,58 @@ fn data_drop( u: &mut Unstructured, module: &Module, _builder: &mut CodeBuilder, -) -> Result { - Ok(Instruction::DataDrop(data_index(u, module)?)) + instructions: &mut Vec, +) -> Result<()> { + instructions.push(Instruction::DataDrop(data_index(u, module)?)); + Ok(()) } -fn i32_const(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_const( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let x = u.arbitrary()?; builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Const(x)) + instructions.push(Instruction::I32Const(x)); + Ok(()) } -fn i64_const(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_const( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let x = u.arbitrary()?; builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Const(x)) + instructions.push(Instruction::I64Const(x)); + Ok(()) } -fn f32_const(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_const( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let x = u.arbitrary()?; builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Const(x)) + instructions.push(Instruction::F32Const(x)); + Ok(()) } -fn f64_const(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { - let x = u.arbitrary()?; +fn f64_const( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { + let x = u.arbitrary()?; builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Const(x)) + instructions.push(Instruction::F64Const(x)); + Ok(()) } #[inline] @@ -2174,10 +2830,16 @@ fn i32_on_stack(_: &Module, builder: &mut CodeBuilder) -> bool { builder.type_on_stack(ValType::I32) } -fn i32_eqz(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_eqz( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Eqz) + instructions.push(Instruction::I32Eqz); + Ok(()) } #[inline] @@ -2185,64 +2847,124 @@ fn i32_i32_on_stack(_: &Module, builder: &mut CodeBuilder) -> bool { builder.types_on_stack(&[ValType::I32, ValType::I32]) } -fn i32_eq(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_eq( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Eq) + instructions.push(Instruction::I32Eq); + Ok(()) } -fn i32_ne(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_ne( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Ne) + instructions.push(Instruction::I32Ne); + Ok(()) } -fn i32_lt_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_lt_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32LtS) + instructions.push(Instruction::I32LtS); + Ok(()) } -fn i32_lt_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_lt_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32LtU) + instructions.push(Instruction::I32LtU); + Ok(()) } -fn i32_gt_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_gt_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32GtS) + instructions.push(Instruction::I32GtS); + Ok(()) } -fn i32_gt_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_gt_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32GtU) + instructions.push(Instruction::I32GtU); + Ok(()) } -fn i32_le_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_le_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32LeS) + instructions.push(Instruction::I32LeS); + Ok(()) } -fn i32_le_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_le_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32LeU) + instructions.push(Instruction::I32LeU); + Ok(()) } -fn i32_ge_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_ge_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32GeS) + instructions.push(Instruction::I32GeS); + Ok(()) } -fn i32_ge_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_ge_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32GeU) + instructions.push(Instruction::I32GeU); + Ok(()) } #[inline] @@ -2255,10 +2977,16 @@ fn i64_on_stack(_: &Module, builder: &mut CodeBuilder) -> bool { builder.types_on_stack(&[ValType::I64]) } -fn i64_eqz(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_eqz( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64Eqz) + instructions.push(Instruction::I64Eqz); + Ok(()) } #[inline] @@ -2266,360 +2994,740 @@ fn i64_i64_on_stack(_: &Module, builder: &mut CodeBuilder) -> bool { builder.types_on_stack(&[ValType::I64, ValType::I64]) } -fn i64_eq(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_eq( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64Eq) + instructions.push(Instruction::I64Eq); + Ok(()) } -fn i64_ne(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_ne( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64Ne) + instructions.push(Instruction::I64Ne); + Ok(()) } -fn i64_lt_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_lt_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64LtS) + instructions.push(Instruction::I64LtS); + Ok(()) } -fn i64_lt_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_lt_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64LtU) + instructions.push(Instruction::I64LtU); + Ok(()) } -fn i64_gt_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_gt_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64GtS) + instructions.push(Instruction::I64GtS); + Ok(()) } -fn i64_gt_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_gt_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64GtU) + instructions.push(Instruction::I64GtU); + Ok(()) } -fn i64_le_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_le_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64LeS) + instructions.push(Instruction::I64LeS); + Ok(()) } -fn i64_le_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_le_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64LeU) + instructions.push(Instruction::I64LeU); + Ok(()) } -fn i64_ge_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_ge_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64GeS) + instructions.push(Instruction::I64GeS); + Ok(()) } -fn i64_ge_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_ge_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I64GeU) + instructions.push(Instruction::I64GeU); + Ok(()) } fn f32_f32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.float_enabled() && builder.types_on_stack(&[ValType::F32, ValType::F32]) } -fn f32_eq(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_eq( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F32Eq) + instructions.push(Instruction::F32Eq); + Ok(()) } -fn f32_ne(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_ne( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F32Ne) + instructions.push(Instruction::F32Ne); + Ok(()) } -fn f32_lt(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_lt( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F32Lt) + instructions.push(Instruction::F32Lt); + Ok(()) } -fn f32_gt(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_gt( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F32Gt) + instructions.push(Instruction::F32Gt); + Ok(()) } -fn f32_le(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_le( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F32Le) + instructions.push(Instruction::F32Le); + Ok(()) } -fn f32_ge(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_ge( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F32Ge) + instructions.push(Instruction::F32Ge); + Ok(()) } fn f64_f64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.float_enabled() && builder.types_on_stack(&[ValType::F64, ValType::F64]) } -fn f64_eq(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_eq( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F64Eq) + instructions.push(Instruction::F64Eq); + Ok(()) } -fn f64_ne(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_ne( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F64Ne) + instructions.push(Instruction::F64Ne); + Ok(()) } -fn f64_lt(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_lt( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F64Lt) + instructions.push(Instruction::F64Lt); + Ok(()) } -fn f64_gt(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_gt( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F64Gt) + instructions.push(Instruction::F64Gt); + Ok(()) } -fn f64_le(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_le( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F64Le) + instructions.push(Instruction::F64Le); + Ok(()) } -fn f64_ge(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_ge( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::F64Ge) + instructions.push(Instruction::F64Ge); + Ok(()) } -fn i32_clz(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_clz( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Clz) + instructions.push(Instruction::I32Clz); + Ok(()) } -fn i32_ctz(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_ctz( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Ctz) + instructions.push(Instruction::I32Ctz); + Ok(()) } -fn i32_popcnt(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_popcnt( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Popcnt) + instructions.push(Instruction::I32Popcnt); + Ok(()) } -fn i32_add(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_add( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Add) + instructions.push(Instruction::I32Add); + Ok(()) } -fn i32_sub(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_sub( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Sub) + instructions.push(Instruction::I32Sub); + Ok(()) } -fn i32_mul(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_mul( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Mul) + instructions.push(Instruction::I32Mul); + Ok(()) } -fn i32_div_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_div_s( + _: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32DivS) + if module.config.disallow_traps() { + no_traps::signed_div_rem(Instruction::I32DivS, builder, instructions); + } else { + instructions.push(Instruction::I32DivS); + } + Ok(()) } -fn i32_div_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_div_u( + _: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32DivU) + if module.config.disallow_traps() { + no_traps::unsigned_div_rem(Instruction::I32DivU, builder, instructions); + } else { + instructions.push(Instruction::I32DivU); + } + Ok(()) } -fn i32_rem_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_rem_s( + _: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32RemS) + if module.config.disallow_traps() { + no_traps::signed_div_rem(Instruction::I32RemS, builder, instructions); + } else { + instructions.push(Instruction::I32RemS); + } + Ok(()) } -fn i32_rem_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_rem_u( + _: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32RemU) + if module.config.disallow_traps() { + no_traps::unsigned_div_rem(Instruction::I32RemU, builder, instructions); + } else { + instructions.push(Instruction::I32RemU); + } + Ok(()) } -fn i32_and(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_and( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32And) + instructions.push(Instruction::I32And); + Ok(()) } -fn i32_or(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_or( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Or) + instructions.push(Instruction::I32Or); + Ok(()) } -fn i32_xor(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_xor( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Xor) + instructions.push(Instruction::I32Xor); + Ok(()) } -fn i32_shl(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_shl( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Shl) + instructions.push(Instruction::I32Shl); + Ok(()) } -fn i32_shr_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_shr_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32ShrS) + instructions.push(Instruction::I32ShrS); + Ok(()) } -fn i32_shr_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_shr_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32ShrU) + instructions.push(Instruction::I32ShrU); + Ok(()) } -fn i32_rotl(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_rotl( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Rotl) + instructions.push(Instruction::I32Rotl); + Ok(()) } -fn i32_rotr(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i32_rotr( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Rotr) + instructions.push(Instruction::I32Rotr); + Ok(()) } -fn i64_clz(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_clz( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Clz) + instructions.push(Instruction::I64Clz); + Ok(()) } -fn i64_ctz(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_ctz( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Ctz) + instructions.push(Instruction::I64Ctz); + Ok(()) } -fn i64_popcnt(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_popcnt( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Popcnt) + instructions.push(Instruction::I64Popcnt); + Ok(()) } -fn i64_add(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_add( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Add) + instructions.push(Instruction::I64Add); + Ok(()) } -fn i64_sub(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_sub( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Sub) + instructions.push(Instruction::I64Sub); + Ok(()) } -fn i64_mul(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_mul( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Mul) + instructions.push(Instruction::I64Mul); + Ok(()) } -fn i64_div_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_div_s( + _: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64DivS) + if module.config.disallow_traps() { + no_traps::signed_div_rem(Instruction::I64DivS, builder, instructions); + } else { + instructions.push(Instruction::I64DivS); + } + Ok(()) } -fn i64_div_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_div_u( + _: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64DivU) + if module.config.disallow_traps() { + no_traps::unsigned_div_rem(Instruction::I64DivU, builder, instructions); + } else { + instructions.push(Instruction::I64DivU); + } + Ok(()) } -fn i64_rem_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_rem_s( + _: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64RemS) + if module.config.disallow_traps() { + no_traps::signed_div_rem(Instruction::I64RemS, builder, instructions); + } else { + instructions.push(Instruction::I64RemS); + } + Ok(()) } -fn i64_rem_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_rem_u( + _: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64RemU) + if module.config.disallow_traps() { + no_traps::unsigned_div_rem(Instruction::I64RemU, builder, instructions); + } else { + instructions.push(Instruction::I64RemU); + } + Ok(()) } -fn i64_and(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_and( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64And) + instructions.push(Instruction::I64And); + Ok(()) } -fn i64_or(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_or( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Or) + instructions.push(Instruction::I64Or); + Ok(()) } -fn i64_xor(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_xor( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Xor) + instructions.push(Instruction::I64Xor); + Ok(()) } -fn i64_shl(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_shl( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Shl) + instructions.push(Instruction::I64Shl); + Ok(()) } -fn i64_shr_s(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_shr_s( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64ShrS) + instructions.push(Instruction::I64ShrS); + Ok(()) } -fn i64_shr_u(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_shr_u( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64ShrU) + instructions.push(Instruction::I64ShrU); + Ok(()) } -fn i64_rotl(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_rotl( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Rotl) + instructions.push(Instruction::I64Rotl); + Ok(()) } -fn i64_rotr(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn i64_rotr( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64, ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Rotr) + instructions.push(Instruction::I64Rotr); + Ok(()) } #[inline] @@ -2627,92 +3735,172 @@ fn f32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.float_enabled() && builder.types_on_stack(&[ValType::F32]) } -fn f32_abs(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_abs( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Abs) + instructions.push(Instruction::F32Abs); + Ok(()) } -fn f32_neg(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_neg( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Neg) + instructions.push(Instruction::F32Neg); + Ok(()) } -fn f32_ceil(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_ceil( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Ceil) + instructions.push(Instruction::F32Ceil); + Ok(()) } -fn f32_floor(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_floor( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Floor) + instructions.push(Instruction::F32Floor); + Ok(()) } -fn f32_trunc(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_trunc( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Trunc) + instructions.push(Instruction::F32Trunc); + Ok(()) } -fn f32_nearest(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_nearest( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Nearest) + instructions.push(Instruction::F32Nearest); + Ok(()) } -fn f32_sqrt(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_sqrt( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Sqrt) + instructions.push(Instruction::F32Sqrt); + Ok(()) } -fn f32_add(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_add( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Add) + instructions.push(Instruction::F32Add); + Ok(()) } -fn f32_sub(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_sub( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Sub) + instructions.push(Instruction::F32Sub); + Ok(()) } -fn f32_mul(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_mul( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Mul) + instructions.push(Instruction::F32Mul); + Ok(()) } -fn f32_div(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_div( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Div) + instructions.push(Instruction::F32Div); + Ok(()) } -fn f32_min(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_min( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Min) + instructions.push(Instruction::F32Min); + Ok(()) } -fn f32_max(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f32_max( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Max) + instructions.push(Instruction::F32Max); + Ok(()) } fn f32_copysign( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32, ValType::F32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32Copysign) + instructions.push(Instruction::F32Copysign); + Ok(()) } #[inline] @@ -2720,102 +3908,184 @@ fn f64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.float_enabled() && builder.types_on_stack(&[ValType::F64]) } -fn f64_abs(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_abs( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Abs) + instructions.push(Instruction::F64Abs); + Ok(()) } -fn f64_neg(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_neg( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Neg) + instructions.push(Instruction::F64Neg); + Ok(()) } -fn f64_ceil(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_ceil( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Ceil) + instructions.push(Instruction::F64Ceil); + Ok(()) } -fn f64_floor(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_floor( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Floor) + instructions.push(Instruction::F64Floor); + Ok(()) } -fn f64_trunc(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_trunc( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Trunc) + instructions.push(Instruction::F64Trunc); + Ok(()) } -fn f64_nearest(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_nearest( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Nearest) + instructions.push(Instruction::F64Nearest); + Ok(()) } -fn f64_sqrt(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_sqrt( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Sqrt) + instructions.push(Instruction::F64Sqrt); + Ok(()) } -fn f64_add(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_add( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Add) + instructions.push(Instruction::F64Add); + Ok(()) } -fn f64_sub(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_sub( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Sub) + instructions.push(Instruction::F64Sub); + Ok(()) } -fn f64_mul(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_mul( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Mul) + instructions.push(Instruction::F64Mul); + Ok(()) } -fn f64_div(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_div( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Div) + instructions.push(Instruction::F64Div); + Ok(()) } -fn f64_min(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_min( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Min) + instructions.push(Instruction::F64Min); + Ok(()) } -fn f64_max(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn f64_max( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Max) + instructions.push(Instruction::F64Max); + Ok(()) } fn f64_copysign( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64, ValType::F64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64Copysign) + instructions.push(Instruction::F64Copysign); + Ok(()) } fn i32_wrap_i64( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32WrapI64) + instructions.push(Instruction::I32WrapI64); + Ok(()) } fn nontrapping_f32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { @@ -2826,22 +4096,34 @@ fn nontrapping_f32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool fn i32_trunc_f32_s( _: &mut Unstructured, - _: &Module, + module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32TruncF32S) + if module.config.disallow_traps() { + no_traps::trunc(Instruction::I32TruncF32S, builder, instructions); + } else { + instructions.push(Instruction::I32TruncF32S); + } + Ok(()) } fn i32_trunc_f32_u( _: &mut Unstructured, - _: &Module, + module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32TruncF32U) + if module.config.disallow_traps() { + no_traps::trunc(Instruction::I32TruncF32U, builder, instructions); + } else { + instructions.push(Instruction::I32TruncF32U); + } + Ok(()) } fn nontrapping_f64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { @@ -2852,222 +4134,290 @@ fn nontrapping_f64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool fn i32_trunc_f64_s( _: &mut Unstructured, - _: &Module, + module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32TruncF64S) + if module.config.disallow_traps() { + no_traps::trunc(Instruction::I32TruncF64S, builder, instructions); + } else { + instructions.push(Instruction::I32TruncF64S); + } + Ok(()) } fn i32_trunc_f64_u( _: &mut Unstructured, - _: &Module, + module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32TruncF64U) + if module.config.disallow_traps() { + no_traps::trunc(Instruction::I32TruncF64U, builder, instructions); + } else { + instructions.push(Instruction::I32TruncF64U); + } + Ok(()) } fn i64_extend_i32_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64ExtendI32S) + instructions.push(Instruction::I64ExtendI32S); + Ok(()) } fn i64_extend_i32_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64ExtendI32U) + instructions.push(Instruction::I64ExtendI32U); + Ok(()) } fn i64_trunc_f32_s( _: &mut Unstructured, - _: &Module, + module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64TruncF32S) + if module.config.disallow_traps() { + no_traps::trunc(Instruction::I64TruncF32S, builder, instructions); + } else { + instructions.push(Instruction::I64TruncF32S); + } + Ok(()) } fn i64_trunc_f32_u( _: &mut Unstructured, - _: &Module, + module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64TruncF32U) + if module.config.disallow_traps() { + no_traps::trunc(Instruction::I64TruncF32U, builder, instructions); + } else { + instructions.push(Instruction::I64TruncF32U); + } + Ok(()) } fn i64_trunc_f64_s( _: &mut Unstructured, - _: &Module, + module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64TruncF64S) + if module.config.disallow_traps() { + no_traps::trunc(Instruction::I64TruncF64S, builder, instructions); + } else { + instructions.push(Instruction::I64TruncF64S); + } + Ok(()) } fn i64_trunc_f64_u( _: &mut Unstructured, - _: &Module, + module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64TruncF64U) + if module.config.disallow_traps() { + no_traps::trunc(Instruction::I64TruncF64U, builder, instructions); + } else { + instructions.push(Instruction::I64TruncF64U); + } + Ok(()) } fn f32_convert_i32_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32ConvertI32S) + instructions.push(Instruction::F32ConvertI32S); + Ok(()) } fn f32_convert_i32_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32ConvertI32U) + instructions.push(Instruction::F32ConvertI32U); + Ok(()) } fn f32_convert_i64_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32ConvertI64S) + instructions.push(Instruction::F32ConvertI64S); + Ok(()) } fn f32_convert_i64_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32ConvertI64U) + instructions.push(Instruction::F32ConvertI64U); + Ok(()) } fn f32_demote_f64( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32DemoteF64) + instructions.push(Instruction::F32DemoteF64); + Ok(()) } fn f64_convert_i32_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64ConvertI32S) + instructions.push(Instruction::F64ConvertI32S); + Ok(()) } fn f64_convert_i32_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64ConvertI32U) + instructions.push(Instruction::F64ConvertI32U); + Ok(()) } fn f64_convert_i64_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64ConvertI64S) + instructions.push(Instruction::F64ConvertI64S); + Ok(()) } fn f64_convert_i64_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64ConvertI64U) + instructions.push(Instruction::F64ConvertI64U); + Ok(()) } fn f64_promote_f32( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64PromoteF32) + instructions.push(Instruction::F64PromoteF32); + Ok(()) } fn i32_reinterpret_f32( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32ReinterpretF32) + instructions.push(Instruction::I32ReinterpretF32); + Ok(()) } fn i64_reinterpret_f64( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64ReinterpretF64) + instructions.push(Instruction::I64ReinterpretF64); + Ok(()) } fn f32_reinterpret_i32( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::F32]); - Ok(Instruction::F32ReinterpretI32) + instructions.push(Instruction::F32ReinterpretI32); + Ok(()) } fn f64_reinterpret_i64( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::F64]); - Ok(Instruction::F64ReinterpretI64) + instructions.push(Instruction::F64ReinterpretI64); + Ok(()) } fn extendable_i32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { @@ -3078,20 +4428,24 @@ fn i32_extend_8_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Extend8S) + instructions.push(Instruction::I32Extend8S); + Ok(()) } fn i32_extend_16_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32Extend16S) + instructions.push(Instruction::I32Extend16S); + Ok(()) } fn extendable_i64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { @@ -3102,110 +4456,132 @@ fn i64_extend_8_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Extend8S) + instructions.push(Instruction::I64Extend8S); + Ok(()) } fn i64_extend_16_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Extend16S) + instructions.push(Instruction::I64Extend16S); + Ok(()) } fn i64_extend_32_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64Extend32S) + instructions.push(Instruction::I64Extend32S); + Ok(()) } fn i32_trunc_sat_f32_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32TruncSatF32S) + instructions.push(Instruction::I32TruncSatF32S); + Ok(()) } fn i32_trunc_sat_f32_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32TruncSatF32U) + instructions.push(Instruction::I32TruncSatF32U); + Ok(()) } fn i32_trunc_sat_f64_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32TruncSatF64S) + instructions.push(Instruction::I32TruncSatF64S); + Ok(()) } fn i32_trunc_sat_f64_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I32]); - Ok(Instruction::I32TruncSatF64U) + instructions.push(Instruction::I32TruncSatF64U); + Ok(()) } fn i64_trunc_sat_f32_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64TruncSatF32S) + instructions.push(Instruction::I64TruncSatF32S); + Ok(()) } fn i64_trunc_sat_f32_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F32]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64TruncSatF32U) + instructions.push(Instruction::I64TruncSatF32U); + Ok(()) } fn i64_trunc_sat_f64_s( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64TruncSatF64S) + instructions.push(Instruction::I64TruncSatF64S); + Ok(()) } fn i64_trunc_sat_f64_u( _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::F64]); builder.push_operands(&[ValType::I64]); - Ok(Instruction::I64TruncSatF64U) + instructions.push(Instruction::I64TruncSatF64U); + Ok(()) } fn memory_offset(u: &mut Unstructured, module: &Module, memory_index: u32) -> Result { @@ -3218,17 +4594,34 @@ fn memory_offset(u: &mut Unstructured, module: &Module, memory_index: u32) -> Re .maximum .map(|max| max.saturating_mul(65536)) .unwrap_or(u64::MAX); - let (min, max, true_max) = if memory_type.memory64 { - // 64-bit memories can use the limits calculated above as-is - (min, max, u64::MAX) - } else { - // 32-bit memories can't represent a full 4gb offset, so if that's the - // min/max sizes then we need to switch the m to `u32::MAX`. - ( - u64::from(u32::try_from(min).unwrap_or(u32::MAX)), - u64::from(u32::try_from(max).unwrap_or(u32::MAX)), - u64::from(u32::MAX), - ) + + let (min, max, true_max) = match (memory_type.memory64, module.config.disallow_traps()) { + (true, false) => { + // 64-bit memories can use the limits calculated above as-is + (min, max, u64::MAX) + } + (false, false) => { + // 32-bit memories can't represent a full 4gb offset, so if that's the + // min/max sizes then we need to switch the m to `u32::MAX`. + ( + u64::from(u32::try_from(min).unwrap_or(u32::MAX)), + u64::from(u32::try_from(max).unwrap_or(u32::MAX)), + u64::from(u32::MAX), + ) + } + // The logic for non-trapping versions of load/store involves pushing + // the offset + load/store size onto the stack as either an i32 or i64 + // value. So even though offsets can normally be as high as u32 or u64, + // we need to limit them to lower in order for our non-trapping logic to + // work. 16 is the number of bytes of the largest load type (V128). + (true, true) => { + let no_trap_max = (i64::MAX - 16) as u64; + (min.min(no_trap_max), no_trap_max, no_trap_max) + } + (false, true) => { + let no_trap_max = (i32::MAX - 16) as u64; + (min.min(no_trap_max), no_trap_max, no_trap_max) + } }; let choice = u.int_in_range(0..=a + b + c - 1)?; @@ -3286,10 +4679,16 @@ fn ref_null_valid(module: &Module, _: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() } -fn ref_null(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { - let ty = *u.choose(&[ValType::ExternRef, ValType::FuncRef])?; - builder.push_operands(&[ty]); - Ok(Instruction::RefNull(ty)) +fn ref_null( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { + let ty = *u.choose(&[RefType::EXTERNREF, RefType::FUNCREF])?; + builder.push_operands(&[ty.into()]); + instructions.push(Instruction::RefNull(ty.heap_type)); + Ok(()) } #[inline] @@ -3297,31 +4696,44 @@ fn ref_func_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() && builder.allocs.referenced_functions.len() > 0 } -fn ref_func(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn ref_func( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { let i = *u.choose(&builder.allocs.referenced_functions)?; - builder.push_operands(&[ValType::FuncRef]); - Ok(Instruction::RefFunc(i)) + builder.push_operands(&[ValType::FUNCREF]); + instructions.push(Instruction::RefFunc(i)); + Ok(()) } #[inline] fn ref_is_null_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() - && (builder.type_on_stack(ValType::ExternRef) || builder.type_on_stack(ValType::FuncRef)) + && (builder.type_on_stack(ValType::EXTERNREF) || builder.type_on_stack(ValType::FUNCREF)) } -fn ref_is_null(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn ref_is_null( + _: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { pop_reference_type(builder); builder.push_operands(&[ValType::I32]); - Ok(Instruction::RefIsNull) + instructions.push(Instruction::RefIsNull); + Ok(()) } #[inline] fn table_fill_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() && module.config.bulk_memory_enabled() - && [ValType::ExternRef, ValType::FuncRef].iter().any(|ty| { + && !module.config.disallow_traps() // Non-trapping table fill generation not yet implemented + && [ValType::EXTERNREF, ValType::FUNCREF].iter().any(|ty| { builder.types_on_stack(&[ValType::I32, *ty, ValType::I32]) - && module.tables.iter().any(|t| t.element_type == *ty) + && module.tables.iter().any(|t| *ty == t.element_type.into()) }) } @@ -3329,20 +4741,23 @@ fn table_fill( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let ty = pop_reference_type(builder); builder.pop_operands(&[ValType::I32]); let table = table_index(ty, u, module)?; - Ok(Instruction::TableFill { table }) + instructions.push(Instruction::TableFill(table)); + Ok(()) } #[inline] fn table_set_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() - && [ValType::ExternRef, ValType::FuncRef].iter().any(|ty| { + && !module.config.disallow_traps() // Non-trapping table.set generation not yet implemented + && [ValType::EXTERNREF, ValType::FUNCREF].iter().any(|ty| { builder.types_on_stack(&[ValType::I32, *ty]) - && module.tables.iter().any(|t| t.element_type == *ty) + && module.tables.iter().any(|t| *ty == t.element_type.into()) }) } @@ -3350,16 +4765,19 @@ fn table_set( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let ty = pop_reference_type(builder); builder.pop_operands(&[ValType::I32]); let table = table_index(ty, u, module)?; - Ok(Instruction::TableSet { table }) + instructions.push(Instruction::TableSet(table)); + Ok(()) } #[inline] fn table_get_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() + && !module.config.disallow_traps() // Non-trapping table.get generation not yet implemented && builder.type_on_stack(ValType::I32) && module.tables.len() > 0 } @@ -3368,12 +4786,14 @@ fn table_get( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let idx = u.int_in_range(0..=module.tables.len() - 1)?; let ty = module.tables[idx].element_type; - builder.push_operands(&[ty]); - Ok(Instruction::TableGet { table: idx as u32 }) + builder.push_operands(&[ty.into()]); + instructions.push(Instruction::TableGet(idx as u32)); + Ok(()) } #[inline] @@ -3385,18 +4805,20 @@ fn table_size( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let table = u.int_in_range(0..=module.tables.len() - 1)? as u32; builder.push_operands(&[ValType::I32]); - Ok(Instruction::TableSize { table }) + instructions.push(Instruction::TableSize(table)); + Ok(()) } #[inline] fn table_grow_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() - && [ValType::ExternRef, ValType::FuncRef].iter().any(|ty| { + && [ValType::EXTERNREF, ValType::FUNCREF].iter().any(|ty| { builder.types_on_stack(&[*ty, ValType::I32]) - && module.tables.iter().any(|t| t.element_type == *ty) + && module.tables.iter().any(|t| *ty == t.element_type.into()) }) } @@ -3404,17 +4826,20 @@ fn table_grow( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32]); let ty = pop_reference_type(builder); let table = table_index(ty, u, module)?; builder.push_operands(&[ValType::I32]); - Ok(Instruction::TableGrow { table }) + instructions.push(Instruction::TableGrow(table)); + Ok(()) } #[inline] fn table_copy_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() + && !module.config.disallow_traps() // Non-trapping table.copy generation not yet implemented && module.tables.len() > 0 && builder.types_on_stack(&[ValType::I32, ValType::I32, ValType::I32]) } @@ -3423,16 +4848,22 @@ fn table_copy( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32, ValType::I32]); - let src = u.int_in_range(0..=module.tables.len() - 1)? as u32; - let dst = table_index(module.tables[src as usize].element_type, u, module)?; - Ok(Instruction::TableCopy { src, dst }) + let src_table = u.int_in_range(0..=module.tables.len() - 1)? as u32; + let dst_table = table_index(module.tables[src_table as usize].element_type, u, module)?; + instructions.push(Instruction::TableCopy { + src_table, + dst_table, + }); + Ok(()) } #[inline] fn table_init_valid(module: &Module, builder: &mut CodeBuilder) -> bool { module.config.reference_types_enabled() + && !module.config.disallow_traps() // Non-trapping table.init generation not yet implemented. && builder.allocs.table_init_possible && builder.types_on_stack(&[ValType::I32, ValType::I32, ValType::I32]) } @@ -3441,7 +4872,8 @@ fn table_init( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::I32, ValType::I32, ValType::I32]); let segments = module .elems @@ -3452,10 +4884,11 @@ fn table_init( .collect::>(); let segment = *u.choose(&segments)?; let table = table_index(module.elems[segment].ty, u, module)?; - Ok(Instruction::TableInit { - segment: segment as u32, + instructions.push(Instruction::TableInit { + elem_index: segment as u32, table, - }) + }); + Ok(()) } #[inline] @@ -3467,22 +4900,24 @@ fn elem_drop( u: &mut Unstructured, module: &Module, _builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { let segment = u.int_in_range(0..=module.elems.len() - 1)? as u32; - Ok(Instruction::ElemDrop { segment }) + instructions.push(Instruction::ElemDrop(segment)); + Ok(()) } -fn pop_reference_type(builder: &mut CodeBuilder) -> ValType { - if builder.type_on_stack(ValType::ExternRef) { - builder.pop_operands(&[ValType::ExternRef]); - ValType::ExternRef +fn pop_reference_type(builder: &mut CodeBuilder) -> RefType { + if builder.type_on_stack(ValType::EXTERNREF) { + builder.pop_operands(&[ValType::EXTERNREF]); + RefType::EXTERNREF } else { - builder.pop_operands(&[ValType::FuncRef]); - ValType::FuncRef + builder.pop_operands(&[ValType::FUNCREF]); + RefType::FUNCREF } } -fn table_index(ty: ValType, u: &mut Unstructured, module: &Module) -> Result { +fn table_index(ty: RefType, u: &mut Unstructured, module: &Module) -> Result { let tables = module .tables .iter() @@ -3499,89 +4934,133 @@ fn lane_index(u: &mut Unstructured, number_of_lanes: u8) -> Result { #[inline] fn simd_v128_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.types_on_stack(&[ValType::V128]) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.types_on_stack(&[ValType::V128]) } #[inline] fn simd_v128_on_stack_relaxed(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.relaxed_simd_enabled() && builder.types_on_stack(&[ValType::V128]) + !module.config.disallow_traps() + && module.config.relaxed_simd_enabled() + && builder.types_on_stack(&[ValType::V128]) } #[inline] fn simd_v128_v128_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.types_on_stack(&[ValType::V128, ValType::V128]) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.types_on_stack(&[ValType::V128, ValType::V128]) } #[inline] fn simd_v128_v128_on_stack_relaxed(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.relaxed_simd_enabled() && builder.types_on_stack(&[ValType::V128, ValType::V128]) + !module.config.disallow_traps() + && module.config.relaxed_simd_enabled() + && builder.types_on_stack(&[ValType::V128, ValType::V128]) } #[inline] fn simd_v128_v128_v128_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() + !module.config.disallow_traps() + && module.config.simd_enabled() && builder.types_on_stack(&[ValType::V128, ValType::V128, ValType::V128]) } #[inline] fn simd_v128_v128_v128_on_stack_relaxed(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.relaxed_simd_enabled() + !module.config.disallow_traps() + && module.config.relaxed_simd_enabled() && builder.types_on_stack(&[ValType::V128, ValType::V128, ValType::V128]) } #[inline] fn simd_v128_i32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.types_on_stack(&[ValType::V128, ValType::I32]) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.types_on_stack(&[ValType::V128, ValType::I32]) } #[inline] fn simd_v128_i64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.types_on_stack(&[ValType::V128, ValType::I64]) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.types_on_stack(&[ValType::V128, ValType::I64]) } #[inline] fn simd_v128_f32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.types_on_stack(&[ValType::V128, ValType::F32]) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.types_on_stack(&[ValType::V128, ValType::F32]) } #[inline] fn simd_v128_f64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.types_on_stack(&[ValType::V128, ValType::F64]) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.types_on_stack(&[ValType::V128, ValType::F64]) } #[inline] fn simd_i32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.type_on_stack(ValType::I32) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.type_on_stack(ValType::I32) } #[inline] fn simd_i64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.type_on_stack(ValType::I64) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.type_on_stack(ValType::I64) } #[inline] fn simd_f32_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.type_on_stack(ValType::F32) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.type_on_stack(ValType::F32) } #[inline] fn simd_f64_on_stack(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && builder.type_on_stack(ValType::F64) + !module.config.disallow_traps() + && module.config.simd_enabled() + && builder.type_on_stack(ValType::F64) } #[inline] fn simd_have_memory_and_offset(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && have_memory_and_offset(module, builder) + !module.config.disallow_traps() + && module.config.simd_enabled() + && have_memory_and_offset(module, builder) } #[inline] fn simd_have_memory_and_offset_and_v128(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && store_valid(module, builder, || ValType::V128) + !module.config.disallow_traps() + && module.config.simd_enabled() + && store_valid(module, builder, || ValType::V128) +} + +#[inline] +fn simd_load_lane_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + // The SIMD non-trapping case is not yet implemented. + !module.config.disallow_traps() && simd_have_memory_and_offset_and_v128(module, builder) } #[inline] fn simd_v128_store_valid(module: &Module, builder: &mut CodeBuilder) -> bool { - module.config.simd_enabled() && store_valid(module, builder, || ValType::V128) + !module.config.disallow_traps() + && module.config.simd_enabled() + && store_valid(module, builder, || ValType::V128) +} + +#[inline] +fn simd_store_lane_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + // The SIMD non-trapping case is not yet implemented. + !module.config.disallow_traps() && simd_v128_store_valid(module, builder) } #[inline] @@ -3595,10 +5074,22 @@ macro_rules! simd_load { u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, - ) -> Result { + + instructions: &mut Vec, + ) -> Result<()> { let memarg = mem_arg(u, module, builder, $alignments)?; builder.push_operands(&[ValType::V128]); - Ok(Instruction::$instruction { memarg }) + if module.config.disallow_traps() { + no_traps::load( + Instruction::$instruction(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::$instruction(memarg)); + } + Ok(()) } }; } @@ -3621,10 +5112,21 @@ fn v128_store( u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::V128]); let memarg = mem_arg(u, module, builder, &[0, 1, 2, 3, 4])?; - Ok(Instruction::V128Store { memarg }) + if module.config.disallow_traps() { + no_traps::store( + Instruction::V128Store(memarg), + module, + builder, + instructions, + ); + } else { + instructions.push(Instruction::V128Store(memarg)); + } + Ok(()) } macro_rules! simd_load_lane { @@ -3633,14 +5135,16 @@ macro_rules! simd_load_lane { u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, - ) -> Result { + instructions: &mut Vec, + ) -> Result<()> { builder.pop_operands(&[ValType::V128]); let memarg = mem_arg(u, module, builder, $alignments)?; builder.push_operands(&[ValType::V128]); - Ok(Instruction::$instruction { + instructions.push(Instruction::$instruction { memarg, lane: lane_index(u, $number_of_lanes)?, - }) + }); + Ok(()) } }; } @@ -3656,13 +5160,15 @@ macro_rules! simd_store_lane { u: &mut Unstructured, module: &Module, builder: &mut CodeBuilder, - ) -> Result { + instructions: &mut Vec, + ) -> Result<()> { builder.pop_operands(&[ValType::V128]); let memarg = mem_arg(u, module, builder, $alignments)?; - Ok(Instruction::$instruction { + instructions.push(Instruction::$instruction { memarg, lane: lane_index(u, $number_of_lanes)?, - }) + }); + Ok(()) } }; } @@ -3672,24 +5178,32 @@ simd_store_lane!(V128Store16Lane, v128_store16_lane, &[0, 1], 8); simd_store_lane!(V128Store32Lane, v128_store32_lane, &[0, 1, 2], 4); simd_store_lane!(V128Store64Lane, v128_store64_lane, &[0, 1, 2, 3], 2); -fn v128_const(u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result { +fn v128_const( + u: &mut Unstructured, + _: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec, +) -> Result<()> { builder.push_operands(&[ValType::V128]); let c = i128::from_le_bytes(u.arbitrary()?); - Ok(Instruction::V128Const(c)) + instructions.push(Instruction::V128Const(c)); + Ok(()) } fn i8x16_shuffle( u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, -) -> Result { + instructions: &mut Vec, +) -> Result<()> { builder.pop_operands(&[ValType::V128, ValType::V128]); builder.push_operands(&[ValType::V128]); let mut lanes = [0; 16]; for i in 0..16 { lanes[i] = u.int_in_range(0..=31)?; } - Ok(Instruction::I8x16Shuffle { lanes }) + instructions.push(Instruction::I8x16Shuffle(lanes)); + Ok(()) } macro_rules! simd_lane_access { @@ -3698,12 +5212,12 @@ macro_rules! simd_lane_access { u: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, - ) -> Result { + instructions: &mut Vec, + ) -> Result<()> { builder.pop_operands($in_types); builder.push_operands($out_types); - Ok(Instruction::$instruction { - lane: lane_index(u, $number_of_lanes)?, - }) + instructions.push(Instruction::$instruction(lane_index(u, $number_of_lanes)?)); + Ok(()) } }; } @@ -3729,10 +5243,13 @@ macro_rules! simd_binop { _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, - ) -> Result { + + instructions: &mut Vec, + ) -> Result<()> { builder.pop_operands(&[ValType::V128, ValType::V128]); builder.push_operands(&[ValType::V128]); - Ok(Instruction::$instruction) + instructions.push(Instruction::$instruction); + Ok(()) } }; } @@ -3747,10 +5264,12 @@ macro_rules! simd_unop { _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, - ) -> Result { + + instructions: &mut Vec, ) -> Result<()> { builder.pop_operands(&[ValType::$in_type]); builder.push_operands(&[ValType::$out_type]); - Ok(Instruction::$instruction) + instructions.push(Instruction::$instruction); + Ok(()) } }; } @@ -3761,10 +5280,13 @@ macro_rules! simd_ternop { _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, - ) -> Result { + + instructions: &mut Vec, + ) -> Result<()> { builder.pop_operands(&[ValType::V128, ValType::V128, ValType::V128]); builder.push_operands(&[ValType::V128]); - Ok(Instruction::$instruction) + instructions.push(Instruction::$instruction); + Ok(()) } }; } @@ -3775,10 +5297,13 @@ macro_rules! simd_shift { _: &mut Unstructured, _: &Module, builder: &mut CodeBuilder, - ) -> Result { + + instructions: &mut Vec, + ) -> Result<()> { builder.pop_operands(&[ValType::V128, ValType::I32]); builder.push_operands(&[ValType::V128]); - Ok(Instruction::$instruction) + instructions.push(Instruction::$instruction); + Ok(()) } }; } @@ -3864,7 +5389,7 @@ simd_binop!(I8x16MinS, i8x16_min_s); simd_binop!(I8x16MinU, i8x16_min_u); simd_binop!(I8x16MaxS, i8x16_max_s); simd_binop!(I8x16MaxU, i8x16_max_u); -simd_binop!(I8x16RoundingAverageU, i8x16_rounding_average_u); +simd_binop!(I8x16AvgrU, i8x16_avgr_u); simd_unop!(I16x8ExtAddPairwiseI8x16S, i16x8_extadd_pairwise_i8x16s); simd_unop!(I16x8ExtAddPairwiseI8x16U, i16x8_extadd_pairwise_i8x16u); simd_unop!(I16x8Abs, i16x8_abs); @@ -3892,7 +5417,7 @@ simd_binop!(I16x8MinS, i16x8_min_s); simd_binop!(I16x8MinU, i16x8_min_u); simd_binop!(I16x8MaxS, i16x8_max_s); simd_binop!(I16x8MaxU, i16x8_max_u); -simd_binop!(I16x8RoundingAverageU, i16x8_rounding_average_u); +simd_binop!(I16x8AvgrU, i16x8_avgr_u); simd_binop!(I16x8ExtMulLowI8x16S, i16x8_extmul_low_i8x16s); simd_binop!(I16x8ExtMulHighI8x16S, i16x8_extmul_high_i8x16s); simd_binop!(I16x8ExtMulLowI8x16U, i16x8_extmul_low_i8x16u); @@ -3982,25 +5507,25 @@ simd_unop!(F32x4DemoteF64x2Zero, f32x4_demote_f64x2_zero); simd_unop!(F64x2PromoteLowF32x4, f64x2_promote_low_f32x4); simd_ternop!(V128Bitselect, v128_bitselect); simd_binop!(I8x16RelaxedSwizzle, i8x16_relaxed_swizzle); -simd_unop!(I32x4RelaxedTruncSatF32x4S, i32x4_relaxed_trunc_sat_f32x4s); -simd_unop!(I32x4RelaxedTruncSatF32x4U, i32x4_relaxed_trunc_sat_f32x4u); -simd_unop!( - I32x4RelaxedTruncSatF64x2SZero, - i32x4_relaxed_trunc_sat_f64x2s_zero -); -simd_unop!( - I32x4RelaxedTruncSatF64x2UZero, - i32x4_relaxed_trunc_sat_f64x2u_zero -); -simd_ternop!(F32x4Fma, f32x4_fma); -simd_ternop!(F32x4Fms, f32x4_fms); -simd_ternop!(F64x2Fma, f64x2_fma); -simd_ternop!(F64x2Fms, f64x2_fms); -simd_ternop!(I8x16LaneSelect, i8x16_laneselect); -simd_ternop!(I16x8LaneSelect, i16x8_laneselect); -simd_ternop!(I32x4LaneSelect, i32x4_laneselect); -simd_ternop!(I64x2LaneSelect, i64x2_laneselect); +simd_unop!(I32x4RelaxedTruncF32x4S, i32x4_relaxed_trunc_f32x4s); +simd_unop!(I32x4RelaxedTruncF32x4U, i32x4_relaxed_trunc_f32x4u); +simd_unop!(I32x4RelaxedTruncF64x2SZero, i32x4_relaxed_trunc_f64x2s_zero); +simd_unop!(I32x4RelaxedTruncF64x2UZero, i32x4_relaxed_trunc_f64x2u_zero); +simd_ternop!(F32x4RelaxedMadd, f32x4_relaxed_madd); +simd_ternop!(F32x4RelaxedNmadd, f32x4_relaxed_nmadd); +simd_ternop!(F64x2RelaxedMadd, f64x2_relaxed_madd); +simd_ternop!(F64x2RelaxedNmadd, f64x2_relaxed_nmadd); +simd_ternop!(I8x16RelaxedLaneselect, i8x16_relaxed_laneselect); +simd_ternop!(I16x8RelaxedLaneselect, i16x8_relaxed_laneselect); +simd_ternop!(I32x4RelaxedLaneselect, i32x4_relaxed_laneselect); +simd_ternop!(I64x2RelaxedLaneselect, i64x2_relaxed_laneselect); simd_binop!(F32x4RelaxedMin, f32x4_relaxed_min); simd_binop!(F32x4RelaxedMax, f32x4_relaxed_max); simd_binop!(F64x2RelaxedMin, f64x2_relaxed_min); simd_binop!(F64x2RelaxedMax, f64x2_relaxed_max); +simd_binop!(I16x8RelaxedQ15mulrS, i16x8_relaxed_q15mulr_s); +simd_binop!(I16x8RelaxedDotI8x16I7x16S, i16x8_relaxed_dot_i8x16_i7x16_s); +simd_ternop!( + I32x4RelaxedDotI8x16I7x16AddS, + i32x4_relaxed_dot_i8x16_i7x16_add_s +); diff --git a/crates/wasm-smith/src/core/code_builder/no_traps.rs b/crates/wasm-smith/src/core/code_builder/no_traps.rs new file mode 100644 index 0000000000..a1232b6922 --- /dev/null +++ b/crates/wasm-smith/src/core/code_builder/no_traps.rs @@ -0,0 +1,644 @@ +use crate::core::*; +use wasm_encoder::{BlockType, Instruction, ValType}; + +use super::CodeBuilder; + +// For loads, we dynamically check whether the load will +// trap, and if it will then we generate a dummy value to +// use instead. +pub(crate) fn load<'a>( + inst: Instruction<'a>, + module: &Module, + builder: &mut CodeBuilder, + insts: &mut Vec>, +) { + let memarg = get_memarg(&inst); + let memory = &module.memories[memarg.memory_index as usize]; + let address_type = if memory.memory64 { + ValType::I64 + } else { + ValType::I32 + }; + // Add a temporary local to hold this load's address. + let address_local = builder.alloc_local(address_type); + + // Add a temporary local to hold the result of this load. + let load_type = type_of_memory_access(&inst); + let result_local = builder.alloc_local(load_type); + + // [address:address_type] + insts.push(Instruction::LocalSet(address_local)); + // [] + insts.push(Instruction::Block(wasm_encoder::BlockType::Empty)); + { + // [] + insts.push(Instruction::Block(wasm_encoder::BlockType::Empty)); + { + // [] + insts.push(Instruction::MemorySize(memarg.memory_index)); + // [mem_size_in_pages:address_type] + insts.push(int_const_inst(address_type, 65_536)); + // [mem_size_in_pages:address_type wasm_page_size:address_type] + insts.push(int_mul_inst(address_type)); + // [mem_size_in_bytes:address_type] + insts.push(int_const_inst( + address_type, + (memarg.offset + size_of_type_in_memory(load_type)) as i64, + )); + // [mem_size_in_bytes:address_type offset_and_size:address_type] + insts.push(Instruction::LocalGet(address_local)); + // [mem_size_in_bytes:address_type offset_and_size:address_type address:address_type] + insts.push(int_add_inst(address_type)); + // [mem_size_in_bytes:address_type highest_byte_accessed:address_type] + insts.push(int_le_u_inst(address_type)); + // [load_will_trap:i32] + insts.push(Instruction::BrIf(0)); + // [] + insts.push(Instruction::LocalGet(address_local)); + // [address:address_type] + insts.push(int_const_inst(address_type, 0)); + // [address:address_type 0:address_type] + insts.push(int_le_s_inst(address_type)); + // [load_will_trap:i32] + insts.push(Instruction::BrIf(0)); + // [] + insts.push(Instruction::LocalGet(address_local)); + // [address:address_type] + insts.push(inst); + // [result:load_type] + insts.push(Instruction::LocalSet(result_local)); + // [] + insts.push(Instruction::Br(1)); + // + } + // [] + insts.push(Instruction::End); + // [] + insts.push(dummy_value_inst(load_type)); + // [dummy_value:load_type] + insts.push(Instruction::LocalSet(result_local)); + // [] + } + // [] + insts.push(Instruction::End); + // [] + insts.push(Instruction::LocalGet(result_local)); + // [result:load_type] +} + +// Stores are similar to loads: we check whether the store +// will trap, and if it will then we just drop the value. +pub(crate) fn store<'a>( + inst: Instruction<'a>, + module: &Module, + builder: &mut CodeBuilder, + insts: &mut Vec>, +) { + let memarg = get_memarg(&inst); + let memory = &module.memories[memarg.memory_index as usize]; + let address_type = if memory.memory64 { + ValType::I64 + } else { + ValType::I32 + }; + + // Add a temporary local to hold this store's address. + let address_local = builder.alloc_local(address_type); + + // Add a temporary local to hold the value to store. + let store_type = type_of_memory_access(&inst); + let value_local = builder.alloc_local(store_type); + + // [address:address_type value:store_type] + insts.push(Instruction::LocalSet(value_local)); + // [address:address_type] + insts.push(Instruction::LocalSet(address_local)); + // [] + insts.push(Instruction::MemorySize(memarg.memory_index)); + // [mem_size_in_pages:address_type] + insts.push(int_const_inst(address_type, 65_536)); + // [mem_size_in_pages:address_type wasm_page_size:address_type] + insts.push(int_mul_inst(address_type)); + // [mem_size_in_bytes:address_type] + insts.push(int_const_inst( + address_type, + (memarg.offset + size_of_type_in_memory(store_type)) as i64, + )); + // [mem_size_in_bytes:address_type offset_and_size:address_type] + insts.push(Instruction::LocalGet(address_local)); + // [mem_size_in_bytes:address_type offset_and_size:address_type address:address_type] + insts.push(int_add_inst(address_type)); + // [mem_size_in_bytes:address_type highest_byte_accessed:address_type] + insts.push(int_le_u_inst(address_type)); + // [store_will_trap:i32] + insts.push(Instruction::If(BlockType::Empty)); + insts.push(Instruction::Else); + { + // [] + insts.push(Instruction::LocalGet(address_local)); + // [address:address_type] + insts.push(int_const_inst(address_type, 0)); + // [address:address_type 0:address_type] + insts.push(int_le_s_inst(address_type)); + // [load_will_trap:i32] + insts.push(Instruction::If(BlockType::Empty)); + insts.push(Instruction::Else); + { + // [] + insts.push(Instruction::LocalGet(address_local)); + // [address:address_type] + insts.push(Instruction::LocalGet(value_local)); + // [address:address_type value:store_type] + insts.push(inst); + // [] + } + insts.push(Instruction::End); + } + // [] + insts.push(Instruction::End); +} + +// Unsigned integer division and remainder will trap when +// the divisor is 0. To avoid the trap, we will set any 0 +// divisors to 1 prior to the operation. +// +// The code below is equivalent to this expression: +// +// local.set $temp_divisor +// (select (i32.eqz (local.get $temp_divisor) (i32.const 1) (local.get $temp_divisor)) +pub(crate) fn unsigned_div_rem<'a>( + inst: Instruction<'a>, + builder: &mut CodeBuilder, + insts: &mut Vec>, +) { + let op_type = type_of_integer_operation(&inst); + let temp_divisor = builder.alloc_local(op_type); + + // [dividend:op_type divisor:op_type] + insts.push(Instruction::LocalSet(temp_divisor)); + // [dividend:op_type] + insts.push(int_const_inst(op_type, 1)); + // [dividend:op_type 1:op_type] + insts.push(Instruction::LocalGet(temp_divisor)); + // [dividend:op_type 1:op_type divisor:op_type] + insts.push(Instruction::LocalGet(temp_divisor)); + // [dividend:op_type 1:op_type divisor:op_type divisor:op_type] + insts.push(eqz_inst(op_type)); + // [dividend:op_type 1:op_type divisor:op_type is_zero:i32] + insts.push(Instruction::Select); + // [dividend:op_type divisor:op_type] + insts.push(inst); + // [result:op_type] +} + +pub(crate) fn trunc<'a>( + inst: Instruction<'a>, + builder: &mut CodeBuilder, + insts: &mut Vec>, +) { + // If NaN or ±inf, replace with dummy value. Our method of checking for NaN + // is to use `ne` because NaN is the only value that is not equal to itself + let conv_type = type_of_float_conversion(&inst); + let temp_float = builder.alloc_local(conv_type); + // [input:conv_type] + insts.push(Instruction::LocalTee(temp_float)); + // [input:conv_type] + insts.push(Instruction::LocalGet(temp_float)); + // [input:conv_type input:conv_type] + insts.push(ne_inst(conv_type)); + // [is_nan:i32] + insts.push(Instruction::LocalGet(temp_float)); + // [is_nan:i32 input:conv_type] + insts.push(flt_inf_const_inst(conv_type)); + // [is_nan:i32 input:conv_type inf:conv_type] + insts.push(eq_inst(conv_type)); + // [is_nan:i32 is_inf:i32] + insts.push(Instruction::LocalGet(temp_float)); + // [is_nan:i32 is_inf:i32 input:conv_type] + insts.push(flt_neg_inf_const_inst(conv_type)); + // [is_nan:i32 is_inf:i32 input:conv_type neg_inf:conv_type] + insts.push(eq_inst(conv_type)); + // [is_nan:i32 is_inf:i32 is_neg_inf:i32] + insts.push(Instruction::I32Or); + // [is_nan:i32 is_±inf:i32] + insts.push(Instruction::I32Or); + // [is_nan_or_inf:i32] + insts.push(Instruction::If(BlockType::Empty)); + { + // [] + insts.push(dummy_value_inst(conv_type)); + // [0:conv_type] + insts.push(Instruction::LocalSet(temp_float)); + // [] + } + insts.push(Instruction::End); + // [] + insts.push(Instruction::LocalGet(temp_float)); + // [input_or_0:conv_type] + + // first ensure that it is >= the min value of our target type + insts.push(min_input_const_for_trunc(&inst)); + // [input_or_0:conv_type min_value_of_target_type:conv_type] + insts.push(flt_lt_inst(conv_type)); + // [input_lt_min:i32] + insts.push(Instruction::If(BlockType::Empty)); + { + // [] + insts.push(min_input_const_for_trunc(&inst)); + // [min_value_of_target_type:conv_type] + insts.push(Instruction::LocalSet(temp_float)); + } + insts.push(Instruction::End); + // [] + insts.push(Instruction::LocalGet(temp_float)); + // [coerced_input:conv_type] + + // next ensure that it is <= the max value of our target type + insts.push(max_input_const_for_trunc(&inst)); + // [input_or_0:conv_type max_value_of_target_type:conv_type] + insts.push(flt_gt_inst(conv_type)); + // [input_gt_min:i32] + insts.push(Instruction::If(BlockType::Empty)); + { + // [] + insts.push(max_input_const_for_trunc(&inst)); + // [max_value_of_target_type:conv_type] + insts.push(Instruction::LocalSet(temp_float)); + } + insts.push(Instruction::End); + // [] + insts.push(Instruction::LocalGet(temp_float)); + // [coerced_input:conv_type] + insts.push(inst); +} + +// Signed division and remainder will trap in the following instances: +// - The divisor is 0 +// - The result of the division is 2^(n-1) +pub(crate) fn signed_div_rem<'a>( + inst: Instruction<'a>, + builder: &mut CodeBuilder, + insts: &mut Vec>, +) { + // If divisor is 0, replace with 1 + let op_type = type_of_integer_operation(&inst); + let temp_divisor = builder.alloc_local(op_type); + // [dividend:op_type divisor:op_type] + insts.push(Instruction::LocalSet(temp_divisor)); + // [dividend:op_type] + insts.push(int_const_inst(op_type, 1)); + // [dividend:op_type 1:op_type] + insts.push(Instruction::LocalGet(temp_divisor)); + // [dividend:op_type 1:op_type divisor:op_type] + insts.push(Instruction::LocalGet(temp_divisor)); + // [dividend:op_type 1:op_type divisor:op_type divisor:op_type] + insts.push(eqz_inst(op_type)); + // [dividend:op_type 1:op_type divisor:op_type is_zero:i32] + insts.push(Instruction::Select); + // [dividend:op_type divisor:op_type] + // If dividend and divisor are -int.max and -1, replace + // divisor with 1. + let temp_dividend = builder.alloc_local(op_type); + insts.push(Instruction::LocalSet(temp_divisor)); + // [dividend:op_type] + insts.push(Instruction::LocalSet(temp_dividend)); + // [] + insts.push(Instruction::Block(wasm_encoder::BlockType::Empty)); + { + insts.push(Instruction::Block(wasm_encoder::BlockType::Empty)); + { + // [] + insts.push(Instruction::LocalGet(temp_dividend)); + // [dividend:op_type] + insts.push(Instruction::LocalGet(temp_divisor)); + // [dividend:op_type divisor:op_type] + insts.push(Instruction::LocalSet(temp_divisor)); + // [dividend:op_type] + insts.push(Instruction::LocalTee(temp_dividend)); + // [dividend:op_type] + insts.push(int_min_const_inst(op_type)); + // [dividend:op_type int_min:op_type] + insts.push(ne_inst(op_type)); + // [not_int_min:i32] + insts.push(Instruction::BrIf(0)); + // [] + insts.push(Instruction::LocalGet(temp_divisor)); + // [divisor:op_type] + insts.push(int_const_inst(op_type, -1)); + // [divisor:op_type -1:op_type] + insts.push(ne_inst(op_type)); + // [not_neg_one:i32] + insts.push(Instruction::BrIf(0)); + // [] + insts.push(int_const_inst(op_type, 1)); + // [divisor:op_type] + insts.push(Instruction::LocalSet(temp_divisor)); + // [] + insts.push(Instruction::Br(1)); + } + // [] + insts.push(Instruction::End); + } + // [] + insts.push(Instruction::End); + // [] + insts.push(Instruction::LocalGet(temp_dividend)); + // [dividend:op_type] + insts.push(Instruction::LocalGet(temp_divisor)); + // [dividend:op_type divisor:op_type] + insts.push(inst); +} + +fn get_memarg(inst: &Instruction) -> wasm_encoder::MemArg { + match *inst { + Instruction::I32Load(memarg) + | Instruction::I64Load(memarg) + | Instruction::F32Load(memarg) + | Instruction::F64Load(memarg) + | Instruction::I32Load8S(memarg) + | Instruction::I32Load8U(memarg) + | Instruction::I32Load16S(memarg) + | Instruction::I32Load16U(memarg) + | Instruction::I64Load8S(memarg) + | Instruction::I64Load8U(memarg) + | Instruction::I64Load16S(memarg) + | Instruction::I64Load16U(memarg) + | Instruction::I64Load32S(memarg) + | Instruction::I64Load32U(memarg) + | Instruction::V128Load(memarg) + | Instruction::V128Load8x8S(memarg) + | Instruction::V128Load8x8U(memarg) + | Instruction::V128Load16x4S(memarg) + | Instruction::V128Load16x4U(memarg) + | Instruction::V128Load32x2S(memarg) + | Instruction::V128Load32x2U(memarg) + | Instruction::V128Load8Splat(memarg) + | Instruction::V128Load16Splat(memarg) + | Instruction::V128Load32Splat(memarg) + | Instruction::V128Load64Splat(memarg) + | Instruction::V128Load32Zero(memarg) + | Instruction::V128Load64Zero(memarg) + | Instruction::I32Store(memarg) + | Instruction::I64Store(memarg) + | Instruction::F32Store(memarg) + | Instruction::F64Store(memarg) + | Instruction::I32Store8(memarg) + | Instruction::I32Store16(memarg) + | Instruction::I64Store8(memarg) + | Instruction::I64Store16(memarg) + | Instruction::I64Store32(memarg) + | Instruction::V128Store(memarg) => memarg, + _ => unreachable!(), + } +} + +fn dummy_value_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32Const(0), + ValType::I64 => Instruction::I64Const(0), + ValType::F32 => Instruction::F32Const(0.0), + ValType::F64 => Instruction::F64Const(0.0), + ValType::V128 => Instruction::V128Const(0), + ValType::Ref(ty) => { + assert!(ty.nullable); + Instruction::RefNull(ty.heap_type) + } + } +} + +fn eq_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::F32 => Instruction::F32Eq, + ValType::F64 => Instruction::F64Eq, + ValType::I32 => Instruction::I32Eq, + ValType::I64 => Instruction::I64Eq, + _ => panic!("not a numeric type"), + } +} + +fn eqz_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32Eqz, + ValType::I64 => Instruction::I64Eqz, + _ => panic!("not an integer type"), + } +} + +fn type_of_integer_operation(inst: &Instruction) -> ValType { + match inst { + Instruction::I32DivU + | Instruction::I32DivS + | Instruction::I32RemU + | Instruction::I32RemS => ValType::I32, + Instruction::I64RemU + | Instruction::I64DivU + | Instruction::I64DivS + | Instruction::I64RemS => ValType::I64, + _ => panic!("not integer division or remainder"), + } +} + +fn type_of_float_conversion(inst: &Instruction) -> ValType { + match inst { + Instruction::I32TruncF32S + | Instruction::I32TruncF32U + | Instruction::I64TruncF32S + | Instruction::I64TruncF32U => ValType::F32, + Instruction::I32TruncF64S + | Instruction::I32TruncF64U + | Instruction::I64TruncF64S + | Instruction::I64TruncF64U => ValType::F64, + _ => panic!("not a float -> integer conversion"), + } +} + +fn min_input_const_for_trunc<'a>(inst: &Instruction) -> Instruction<'a> { + // This is the minimum float value that is representable as an i64 + let min_f64 = -9_223_372_036_854_775_000f64; + let min_f32 = -9_223_372_000_000_000_000f32; + + // This is the minimum float value that is representable as as i32 + let min_f32_as_i32 = -2_147_483_500f32; + match inst { + Instruction::I32TruncF32S => Instruction::F32Const(min_f32_as_i32), + Instruction::I32TruncF32U => Instruction::F32Const(0.0), + Instruction::I64TruncF32S => Instruction::F32Const(min_f32), + Instruction::I64TruncF32U => Instruction::F32Const(0.0), + Instruction::I32TruncF64S => Instruction::F64Const(i32::MIN as f64), + Instruction::I32TruncF64U => Instruction::F64Const(0.0), + Instruction::I64TruncF64S => Instruction::F64Const(min_f64), + Instruction::I64TruncF64U => Instruction::F64Const(0.0), + _ => panic!("not a trunc instruction"), + } +} + +fn max_input_const_for_trunc<'a>(inst: &Instruction) -> Instruction<'a> { + // This is the maximum float value that is representable as as i64 + let max_f64_as_i64 = 9_223_372_036_854_775_000f64; + let max_f32_as_i64 = 9_223_371_500_000_000_000f32; + + // This is the maximum float value that is representable as as i32 + let max_f32_as_i32 = 2_147_483_500f32; + match inst { + Instruction::I32TruncF32S | Instruction::I32TruncF32U => { + Instruction::F32Const(max_f32_as_i32) + } + Instruction::I64TruncF32S | Instruction::I64TruncF32U => { + Instruction::F32Const(max_f32_as_i64) + } + Instruction::I32TruncF64S | Instruction::I32TruncF64U => { + Instruction::F64Const(i32::MAX as f64) + } + Instruction::I64TruncF64S | Instruction::I64TruncF64U => { + Instruction::F64Const(max_f64_as_i64) + } + _ => panic!("not a trunc instruction"), + } +} + +fn type_of_memory_access(inst: &Instruction) -> ValType { + match inst { + Instruction::I32Load(_) + | Instruction::I32Load8S(_) + | Instruction::I32Load8U(_) + | Instruction::I32Load16S(_) + | Instruction::I32Load16U(_) + | Instruction::I32Store(_) + | Instruction::I32Store8(_) + | Instruction::I32Store16(_) => ValType::I32, + + Instruction::I64Load(_) + | Instruction::I64Load8S(_) + | Instruction::I64Load8U(_) + | Instruction::I64Load16S(_) + | Instruction::I64Load16U(_) + | Instruction::I64Load32S(_) + | Instruction::I64Load32U(_) + | Instruction::I64Store(_) + | Instruction::I64Store8(_) + | Instruction::I64Store16(_) + | Instruction::I64Store32(_) => ValType::I64, + + Instruction::F32Load(_) | Instruction::F32Store(_) => ValType::F32, + + Instruction::F64Load(_) | Instruction::F64Store(_) => ValType::F64, + + Instruction::V128Load { .. } + | Instruction::V128Load8x8S { .. } + | Instruction::V128Load8x8U { .. } + | Instruction::V128Load16x4S { .. } + | Instruction::V128Load16x4U { .. } + | Instruction::V128Load32x2S { .. } + | Instruction::V128Load32x2U { .. } + | Instruction::V128Load8Splat { .. } + | Instruction::V128Load16Splat { .. } + | Instruction::V128Load32Splat { .. } + | Instruction::V128Load64Splat { .. } + | Instruction::V128Load32Zero { .. } + | Instruction::V128Load64Zero { .. } + | Instruction::V128Store { .. } => ValType::V128, + + _ => panic!("not a memory access instruction"), + } +} + +fn int_min_const_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32Const(i32::MIN), + ValType::I64 => Instruction::I64Const(i64::MIN), + _ => panic!("not an int type"), + } +} + +fn int_const_inst<'a>(ty: ValType, x: i64) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32Const(x as i32), + ValType::I64 => Instruction::I64Const(x), + _ => panic!("not an int type"), + } +} + +fn int_mul_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32Mul, + ValType::I64 => Instruction::I64Mul, + _ => panic!("not an int type"), + } +} + +fn int_add_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32Add, + ValType::I64 => Instruction::I64Add, + _ => panic!("not an int type"), + } +} + +fn int_le_u_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32LeU, + ValType::I64 => Instruction::I64LeU, + _ => panic!("not an int type"), + } +} + +fn int_le_s_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32LeS, + ValType::I64 => Instruction::I64LeS, + _ => panic!("not an int type"), + } +} + +fn ne_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::I32 => Instruction::I32Ne, + ValType::I64 => Instruction::I64Ne, + ValType::F32 => Instruction::F32Ne, + ValType::F64 => Instruction::F64Ne, + _ => panic!("not a numeric type"), + } +} + +fn flt_lt_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::F32 => Instruction::F32Lt, + ValType::F64 => Instruction::F64Lt, + _ => panic!("not a float type"), + } +} + +fn flt_gt_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::F32 => Instruction::F32Gt, + ValType::F64 => Instruction::F64Gt, + _ => panic!("not a float type"), + } +} + +fn flt_inf_const_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::F32 => Instruction::F32Const(f32::INFINITY), + ValType::F64 => Instruction::F64Const(f64::INFINITY), + _ => panic!("not a float type"), + } +} + +fn flt_neg_inf_const_inst<'a>(ty: ValType) -> Instruction<'a> { + match ty { + ValType::F32 => Instruction::F32Const(f32::NEG_INFINITY), + ValType::F64 => Instruction::F64Const(f64::NEG_INFINITY), + _ => panic!("not a float type"), + } +} + +fn size_of_type_in_memory(ty: ValType) -> u64 { + match ty { + ValType::I32 => 4, + ValType::I64 => 8, + ValType::F32 => 4, + ValType::F64 => 8, + ValType::V128 => 16, + ValType::Ref(_) => panic!("not a memory type"), + } +} diff --git a/crates/wasm-smith/src/core/encode.rs b/crates/wasm-smith/src/core/encode.rs index 157277ae00..cf4cd5e199 100644 --- a/crates/wasm-smith/src/core/encode.rs +++ b/crates/wasm-smith/src/core/encode.rs @@ -152,13 +152,13 @@ impl Module { // TODO(nagisa): generate global.get of imported ref globals too. match e { Some(i) => match el.ty { - ValType::FuncRef => wasm_encoder::ConstExpr::ref_func(*i), + RefType::FUNCREF => wasm_encoder::ConstExpr::ref_func(*i), _ => unreachable!(), }, - None => wasm_encoder::ConstExpr::ref_null(el.ty), + None => wasm_encoder::ConstExpr::ref_null(el.ty.heap_type), } })); - wasm_encoder::Elements::Expressions(&exps) + wasm_encoder::Elements::Expressions(el.ty, &exps) } Elements::Functions(fs) => wasm_encoder::Elements::Functions(fs), }; @@ -169,13 +169,13 @@ impl Module { Offset::Const64(n) => ConstExpr::i64_const(n), Offset::Global(g) => ConstExpr::global_get(g), }; - elems.active(*table, &offset, el.ty, elements); + elems.active(*table, &offset, elements); } ElementKind::Passive => { - elems.passive(el.ty, elements); + elems.passive(elements); } ElementKind::Declared => { - elems.declared(el.ty, elements); + elems.declared(elements); } } } diff --git a/crates/wasm-smith/src/core/no_traps.rs b/crates/wasm-smith/src/core/no_traps.rs deleted file mode 100755 index 030b740053..0000000000 --- a/crates/wasm-smith/src/core/no_traps.rs +++ /dev/null @@ -1,818 +0,0 @@ -use crate::core::*; -use wasm_encoder::{BlockType, Instruction, ValType}; - -const WASM_PAGE_SIZE: u64 = 65_536; - -/// The OpCode is not supported -#[derive(Debug)] -pub struct NotSupported<'a> { - opcode: wasm_encoder::Instruction<'a>, -} - -impl std::error::Error for NotSupported<'_> {} -impl std::fmt::Display for NotSupported<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "Opcode not supported for no-trapping mode: {:?}", - self.opcode - ) - } -} - -impl Module { - /// Ensure that this generated module will never trap. - /// - /// This will take a number of approaches to avoid traps, such as - /// - /// * mask loads' and stores' addresses to the associated memory's size - /// - /// * mask `table.get`s' and `table.set`'s index to the associated table's size - /// - /// * ensure that a divisor is never zero - /// - /// * replace `unreachable`s with dummy-value `return`s - /// - /// * Masking data and element segments' offsets to be in bounds of their - /// associated tables or memories - pub fn no_traps(&mut self) -> std::result::Result<(), NotSupported> { - self.no_trapping_segments(); - - let import_count = self - .imports - .iter() - .filter(|imp| match imp.entity_type { - EntityType::Func(_, _) => true, - _ => false, - }) - .count(); - for (i, code) in self.code.iter_mut().enumerate() { - let this_func_ty = &self.funcs[i + import_count].1; - let mut new_insts = vec![]; - - let insts = match &mut code.instructions { - Instructions::Generated(is) => std::mem::replace(is, vec![]), - Instructions::Arbitrary(_) => unreachable!(), - }; - - for inst in insts { - match inst { - // Replace `unreachable` with an early return of dummy values. - // - // We *could* instead abstractly interpret all these - // instructions and maintain a stack of types (the way the - // validation algorithm does) and insert dummy values - // whenever an instruction expects a value of type `T` but - // there is an `unreachable` on the stack. This would allow - // us to keep executing the rest of the code following the - // `unreachable`, but also is a ton more work, and it isn't - // clear that it would pay for itself. - Instruction::Unreachable => { - for ty in &this_func_ty.results { - new_insts.push(dummy_value_inst(*ty)); - } - new_insts.push(Instruction::Return); - } - - // We have no way to reflect, at run time, on a `funcref` in - // the `i`th slot in a table and dynamically avoid trapping - // `call_indirect`s. Therefore, we can't emit *any* - // `call_indirect` instructions. Instead, we consume the - // arguments and generate dummy results. - Instruction::CallIndirect { ty, table: _ } => { - // When we can, avoid emitting `drop`s to consume the - // arguments when possible, since dead code isn't - // usually an interesting thing to give to a Wasm - // compiler. Instead, prefer writing them to the first - // page of the first memory if possible. - let callee_func_ty = match &self.types[ty as usize] { - Type::Func(f) => f, - }; - let can_store_args_to_memory = callee_func_ty.params.len() - < usize::try_from(WASM_PAGE_SIZE).unwrap() - && self.memories.get(0).map_or(false, |m| m.minimum > 0); - let memory_64 = self.memories.get(0).map_or(false, |m| m.memory64); - let address = if memory_64 { - Instruction::I64Const(0) - } else { - Instruction::I32Const(0) - }; - let memarg = wasm_encoder::MemArg { - offset: 0, - align: 0, - memory_index: 0, - }; - - // handle table index if we are able, otherwise drop it - if can_store_args_to_memory { - let val_to_store = - u32::try_from(this_func_ty.params.len() + code.locals.len()) - .unwrap(); - code.locals.push(ValType::I32); - new_insts.push(Instruction::LocalSet(val_to_store)); - new_insts.push(address.clone()); - new_insts.push(Instruction::LocalGet(val_to_store)); - new_insts.push(Instruction::I32Store(memarg)); - } else { - new_insts.push(Instruction::Drop); - } - - for ty in callee_func_ty.params.iter().rev() { - let val_to_store = - u32::try_from(this_func_ty.params.len() + code.locals.len()) - .unwrap(); - - if let ValType::I32 - | ValType::I64 - | ValType::F32 - | ValType::F64 - | ValType::V128 = ty - { - if can_store_args_to_memory { - code.locals.push(*ty); - new_insts.push(Instruction::LocalSet(val_to_store)); - } - } - match ty { - ValType::I32 if can_store_args_to_memory => { - new_insts.push(address.clone()); - new_insts.push(Instruction::LocalGet(val_to_store)); - new_insts.push(Instruction::I32Store(memarg)); - } - ValType::I64 if can_store_args_to_memory => { - new_insts.push(address.clone()); - new_insts.push(Instruction::LocalGet(val_to_store)); - new_insts.push(Instruction::I64Store(memarg)); - } - ValType::F32 if can_store_args_to_memory => { - new_insts.push(address.clone()); - new_insts.push(Instruction::LocalGet(val_to_store)); - new_insts.push(Instruction::F32Store(memarg)); - } - ValType::F64 if can_store_args_to_memory => { - new_insts.push(address.clone()); - new_insts.push(Instruction::LocalGet(val_to_store)); - new_insts.push(Instruction::F64Store(memarg)); - } - ValType::V128 if can_store_args_to_memory => { - new_insts.push(address.clone()); - new_insts.push(Instruction::LocalGet(val_to_store)); - new_insts.push(Instruction::V128Store { memarg }); - } - _ => { - new_insts.push(Instruction::Drop); - } - } - } - - for ty in &callee_func_ty.results { - new_insts.push(dummy_value_inst(*ty)); - } - } - - // For loads, we dynamically check whether the load will - // trap, and if it will then we generate a dummy value to - // use instead. - Instruction::I32Load(memarg) - | Instruction::I64Load(memarg) - | Instruction::F32Load(memarg) - | Instruction::F64Load(memarg) - | Instruction::I32Load8_S(memarg) - | Instruction::I32Load8_U(memarg) - | Instruction::I32Load16_S(memarg) - | Instruction::I32Load16_U(memarg) - | Instruction::I64Load8_S(memarg) - | Instruction::I64Load8_U(memarg) - | Instruction::I64Load16_S(memarg) - | Instruction::I64Load16_U(memarg) - | Instruction::I64Load32_S(memarg) - | Instruction::I64Load32_U(memarg) - | Instruction::V128Load { memarg } - | Instruction::V128Load8x8S { memarg } - | Instruction::V128Load8x8U { memarg } - | Instruction::V128Load16x4S { memarg } - | Instruction::V128Load16x4U { memarg } - | Instruction::V128Load32x2S { memarg } - | Instruction::V128Load32x2U { memarg } - | Instruction::V128Load8Splat { memarg } - | Instruction::V128Load16Splat { memarg } - | Instruction::V128Load32Splat { memarg } - | Instruction::V128Load64Splat { memarg } - | Instruction::V128Load32Zero { memarg } - | Instruction::V128Load64Zero { memarg } => { - let memory = &self.memories[memarg.memory_index as usize]; - let address_type = if memory.memory64 { - ValType::I64 - } else { - ValType::I32 - }; - // Add a temporary local to hold this load's address. - let address_local = - u32::try_from(this_func_ty.params.len() + code.locals.len()).unwrap(); - code.locals.push(address_type); - - // Add a temporary local to hold the result of this load. - let load_type = type_of_memory_access(&inst); - let result_local = - u32::try_from(this_func_ty.params.len() + code.locals.len()).unwrap(); - code.locals.push(load_type); - - // [address:address_type] - new_insts.push(Instruction::LocalSet(address_local)); - // [] - new_insts.push(Instruction::Block(wasm_encoder::BlockType::Empty)); - { - // [] - new_insts.push(Instruction::Block(wasm_encoder::BlockType::Empty)); - { - // [] - new_insts.push(Instruction::MemorySize(memarg.memory_index)); - // [mem_size_in_pages:address_type] - new_insts.push(int_const_inst(address_type, 65_536)); - // [mem_size_in_pages:address_type wasm_page_size:address_type] - new_insts.push(int_mul_inst(address_type)); - // [mem_size_in_bytes:address_type] - new_insts.push(int_const_inst( - address_type, - (memarg.offset + size_of_type_in_memory(load_type)) as i64, - )); - // [mem_size_in_bytes:address_type offset_and_size:address_type] - new_insts.push(Instruction::LocalGet(address_local)); - // [mem_size_in_bytes:address_type offset_and_size:address_type address:address_type] - new_insts.push(int_add_inst(address_type)); - // [mem_size_in_bytes:address_type highest_byte_accessed:address_type] - new_insts.push(int_le_u_inst(address_type)); - // [load_will_trap:i32] - new_insts.push(Instruction::BrIf(0)); - // [] - new_insts.push(Instruction::LocalGet(address_local)); - // [address:address_type] - new_insts.push(inst); - // [result:load_type] - new_insts.push(Instruction::LocalSet(result_local)); - // [] - new_insts.push(Instruction::Br(1)); - // - } - // [] - new_insts.push(Instruction::End); - // [] - new_insts.push(dummy_value_inst(load_type)); - // [dummy_value:load_type] - new_insts.push(Instruction::LocalSet(result_local)); - // [] - } - // [] - new_insts.push(Instruction::End); - // [] - new_insts.push(Instruction::LocalGet(result_local)); - // [result:load_type] - } - - // Stores are similar to loads: we check whether the store - // will trap, and if it will then we just drop the value. - Instruction::I32Store(memarg) - | Instruction::I64Store(memarg) - | Instruction::F32Store(memarg) - | Instruction::F64Store(memarg) - | Instruction::I32Store8(memarg) - | Instruction::I32Store16(memarg) - | Instruction::I64Store8(memarg) - | Instruction::I64Store16(memarg) - | Instruction::I64Store32(memarg) - | Instruction::V128Store { memarg } => { - let memory = &self.memories[memarg.memory_index as usize]; - let address_type = if memory.memory64 { - ValType::I64 - } else { - ValType::I32 - }; - - // Add a temporary local to hold this store's address. - let address_local = - u32::try_from(this_func_ty.params.len() + code.locals.len()).unwrap(); - code.locals.push(address_type); - - // Add a temporary local to hold the value to store. - let store_type = type_of_memory_access(&inst); - let value_local = - u32::try_from(this_func_ty.params.len() + code.locals.len()).unwrap(); - code.locals.push(store_type); - - // [address:address_type value:store_type] - new_insts.push(Instruction::LocalSet(value_local)); - // [address:address_type] - new_insts.push(Instruction::LocalSet(address_local)); - // [] - new_insts.push(Instruction::MemorySize(memarg.memory_index)); - // [mem_size_in_pages:address_type] - new_insts.push(int_const_inst(address_type, 65_536)); - // [mem_size_in_pages:address_type wasm_page_size:address_type] - new_insts.push(int_mul_inst(address_type)); - // [mem_size_in_bytes:address_type] - new_insts.push(int_const_inst( - address_type, - (memarg.offset + size_of_type_in_memory(store_type)) as i64, - )); - // [mem_size_in_bytes:address_type offset_and_size:address_type] - new_insts.push(Instruction::LocalGet(address_local)); - // [mem_size_in_bytes:address_type offset_and_size:address_type address:address_type] - new_insts.push(int_add_inst(address_type)); - // [mem_size_in_bytes:address_type highest_byte_accessed:address_type] - new_insts.push(int_le_u_inst(address_type)); - // [store_will_trap:i32] - new_insts.push(Instruction::If(BlockType::Empty)); - new_insts.push(Instruction::Else); - { - // [] - new_insts.push(Instruction::LocalGet(address_local)); - // [address:address_type] - new_insts.push(Instruction::LocalGet(value_local)); - // [address:address_type value:store_type] - new_insts.push(inst); - // [] - } - // [] - new_insts.push(Instruction::End); - } - - Instruction::V128Load8Lane { memarg: _, lane: _ } - | Instruction::V128Load16Lane { memarg: _, lane: _ } - | Instruction::V128Load32Lane { memarg: _, lane: _ } - | Instruction::V128Load64Lane { memarg: _, lane: _ } - | Instruction::V128Store8Lane { memarg: _, lane: _ } - | Instruction::V128Store16Lane { memarg: _, lane: _ } - | Instruction::V128Store32Lane { memarg: _, lane: _ } - | Instruction::V128Store64Lane { memarg: _, lane: _ } => { - return Err(NotSupported { opcode: inst }) - } - - Instruction::MemoryCopy { src: _, dst: _ } - | Instruction::MemoryFill(_) - | Instruction::MemoryInit { mem: _, data: _ } => { - return Err(NotSupported { opcode: inst }) - } - - // Unsigned integer division and remainder will trap when - // the divisor is 0. To avoid the trap, we will set any 0 - // divisors to 1 prior to the operation. - // - // The code below is equivalent to this expression: - // - // local.set $temp_divisor - // (select (i32.eqz (local.get $temp_divisor) (i32.const 1) (local.get $temp_divisor)) - Instruction::I32RemU - | Instruction::I64RemU - | Instruction::I64DivU - | Instruction::I32DivU => { - let op_type = type_of_integer_operation(&inst); - let temp_divisor = - u32::try_from(this_func_ty.params.len() + code.locals.len()).unwrap(); - code.locals.push(op_type); - - // [dividend:op_type divisor:op_type] - new_insts.push(Instruction::LocalSet(temp_divisor)); - // [dividend:op_type] - new_insts.push(int_const_inst(op_type, 1)); - // [dividend:op_type 1:op_type] - new_insts.push(Instruction::LocalGet(temp_divisor)); - // [dividend:op_type 1:op_type divisor:op_type] - new_insts.push(Instruction::LocalGet(temp_divisor)); - // [dividend:op_type 1:op_type divisor:op_type divisor:op_type] - new_insts.push(eqz_inst(op_type)); - // [dividend:op_type 1:op_type divisor:op_type is_zero:i32] - new_insts.push(Instruction::Select); - // [dividend:op_type divisor:op_type] - new_insts.push(inst); - // [result:op_type] - } - - // Signed division and remainder will trap in the following instances: - // - The divisor is 0 - // - The result of the division is 2^(n-1) - Instruction::I32DivS - | Instruction::I32RemS - | Instruction::I64DivS - | Instruction::I64RemS => { - // If divisor is 0, replace with 1 - let op_type = type_of_integer_operation(&inst); - let temp_divisor = - u32::try_from(this_func_ty.params.len() + code.locals.len()).unwrap(); - code.locals.push(op_type); - - // [dividend:op_type divisor:op_type] - new_insts.push(Instruction::LocalSet(temp_divisor)); - // [dividend:op_type] - new_insts.push(int_const_inst(op_type, 1)); - // [dividend:op_type 1:op_type] - new_insts.push(Instruction::LocalGet(temp_divisor)); - // [dividend:op_type 1:op_type divisor:op_type] - new_insts.push(Instruction::LocalGet(temp_divisor)); - // [dividend:op_type 1:op_type divisor:op_type divisor:op_type] - new_insts.push(eqz_inst(op_type)); - // [dividend:op_type 1:op_type divisor:op_type is_zero:i32] - new_insts.push(Instruction::Select); - // [dividend:op_type divisor:op_type] - - // If dividend and divisor are -int.max and -1, replace - // divisor with 1. - let temp_dividend = - u32::try_from(this_func_ty.params.len() + code.locals.len()).unwrap(); - code.locals.push(op_type); - new_insts.push(Instruction::LocalSet(temp_divisor)); - // [dividend:op_type] - new_insts.push(Instruction::LocalSet(temp_dividend)); - // [] - new_insts.push(Instruction::Block(wasm_encoder::BlockType::Empty)); - { - new_insts.push(Instruction::Block(wasm_encoder::BlockType::Empty)); - { - // [] - new_insts.push(Instruction::LocalGet(temp_dividend)); - // [dividend:op_type] - new_insts.push(Instruction::LocalGet(temp_divisor)); - // [dividend:op_type divisor:op_type] - new_insts.push(Instruction::LocalSet(temp_divisor)); - // [dividend:op_type] - new_insts.push(Instruction::LocalTee(temp_dividend)); - // [dividend:op_type] - new_insts.push(int_min_const_inst(op_type)); - // [dividend:op_type int_min:op_type] - new_insts.push(int_ne_inst(op_type)); - // [not_int_min:i32] - new_insts.push(Instruction::BrIf(0)); - // [] - new_insts.push(Instruction::LocalGet(temp_divisor)); - // [divisor:op_type] - new_insts.push(int_const_inst(op_type, -1)); - // [divisor:op_type -1:op_type] - new_insts.push(int_ne_inst(op_type)); - // [not_neg_one:i32] - new_insts.push(Instruction::BrIf(0)); - // [] - new_insts.push(int_const_inst(op_type, 1)); - // [divisor:op_type] - new_insts.push(Instruction::LocalSet(temp_divisor)); - // [] - new_insts.push(Instruction::Br(1)); - } - // [] - new_insts.push(Instruction::End); - } - // [] - new_insts.push(Instruction::End); - // [] - new_insts.push(Instruction::LocalGet(temp_dividend)); - // [dividend:op_type] - new_insts.push(Instruction::LocalGet(temp_divisor)); - // [dividend:op_type divisor:op_type] - new_insts.push(inst); - } - - Instruction::I32TruncF32S - | Instruction::I32TruncF32U - | Instruction::I32TruncF64S - | Instruction::I32TruncF64U - | Instruction::I64TruncF32S - | Instruction::I64TruncF32U - | Instruction::I64TruncF64S - | Instruction::I64TruncF64U => { - // If NaN or ±inf, replace with dummy value - let conv_type = type_of_float_conversion(&inst); - let temp_float = - u32::try_from(this_func_ty.params.len() + code.locals.len()).unwrap(); - code.locals.push(conv_type); - - // [input:conv_type] - new_insts.push(Instruction::LocalTee(temp_float)); - // [input:conv_type] - new_insts.push(flt_nan_const_inst(conv_type)); - // [input:conv_type NaN:conv_type] - new_insts.push(eq_inst(conv_type)); - // [is_nan:i32] - new_insts.push(Instruction::LocalGet(temp_float)); - // [is_nan:i32 input:conv_type] - new_insts.push(flt_inf_const_inst(conv_type)); - // [is_nan:i32 input:conv_type inf:conv_type] - new_insts.push(eq_inst(conv_type)); - // [is_nan:i32 is_inf:i32] - new_insts.push(Instruction::LocalGet(temp_float)); - // [is_nan:i32 is_inf:i32 input:conv_type] - new_insts.push(flt_neg_inf_const_inst(conv_type)); - // [is_nan:i32 is_inf:i32 input:conv_type neg_inf:conv_type] - new_insts.push(eq_inst(conv_type)); - // [is_nan:i32 is_inf:i32 is_neg_inf:i32] - new_insts.push(Instruction::I32Or); - // [is_nan:i32 is_±inf:i32] - new_insts.push(Instruction::I32Or); - // [is_nan_or_inf:i32] - new_insts.push(Instruction::If(BlockType::Empty)); - { - // [] - new_insts.push(dummy_value_inst(conv_type)); - // [0:conv_type] - new_insts.push(Instruction::LocalSet(temp_float)); - // [] - } - new_insts.push(Instruction::End); - // [] - new_insts.push(Instruction::LocalGet(temp_float)); - - // [input_or_0:conv_type] - new_insts.push(inst); - } - Instruction::TableFill { table: _ } - | Instruction::TableSet { table: _ } - | Instruction::TableGet { table: _ } - | Instruction::TableInit { - segment: _, - table: _, - } - | Instruction::TableCopy { src: _, dst: _ } => { - return Err(NotSupported { opcode: inst }) - } - - // None of the other instructions can trap, so just copy them over. - inst => new_insts.push(inst), - } - } - - code.instructions = Instructions::Generated(new_insts); - } - Ok(()) - } - - /// Mask data and element segments' offsets to be in bounds of their - /// associated tables and memories. - fn no_trapping_segments(&mut self) { - for data in &mut self.data { - match &mut data.kind { - DataSegmentKind::Passive => continue, - DataSegmentKind::Active { - memory_index, - offset, - } => { - let mem = &mut self.memories[usize::try_from(*memory_index).unwrap()]; - - // Ensure that all memories have at least one - // page. Otherwise, if we had a zero-minimum memory, then we - // wouldn't be able to mask the initializers to be - // definitely in-bounds. - mem.minimum = std::cmp::max(1, mem.minimum); - mem.maximum = mem.maximum.map(|n| std::cmp::max(mem.minimum, n)); - - // Make sure that the data segment can fit into the memory. - data.init - .truncate(usize::try_from(mem.minimum * WASM_PAGE_SIZE).unwrap()); - let data_len = data.init.len() as u64; - - match offset { - Offset::Const64(n) => { - let n = *n as u64; - let n = n - .checked_rem(mem.minimum * WASM_PAGE_SIZE - data_len) - .unwrap_or(0); - *offset = Offset::Const64(n as i64); - } - Offset::Const32(n) => { - let n = *n as u64; - let n = n - .checked_rem(mem.minimum * WASM_PAGE_SIZE - data_len) - .unwrap_or(0); - let n = u32::try_from(n).unwrap(); - *offset = Offset::Const32(n as i32); - } - Offset::Global(_) => *offset = Offset::Const32(0), - } - } - } - } - - for elem in &mut self.elems { - match &mut elem.kind { - ElementKind::Passive | ElementKind::Declared => continue, - ElementKind::Active { table, offset } => { - let table = table.unwrap_or(0); - let table = usize::try_from(table).unwrap(); - let table = &mut self.tables[table]; - - // Ensure that we have room for at least one element. See - // comment above. - table.minimum = std::cmp::max(1, table.minimum); - table.maximum = table.maximum.map(|n| std::cmp::max(table.minimum, n)); - - // Make sure that the element segment can fit into the - // table. - let elem_len = match &mut elem.items { - Elements::Functions(fs) => { - fs.truncate(usize::try_from(table.minimum).unwrap()); - u32::try_from(fs.len()).unwrap() - } - Elements::Expressions(es) => { - es.truncate(usize::try_from(table.minimum).unwrap()); - u32::try_from(es.len()).unwrap() - } - }; - - match offset { - Offset::Const32(n) => { - let n = *n as u32; - let n = n.checked_rem(table.minimum - elem_len).unwrap_or(0); - *offset = Offset::Const32(n as i32); - } - Offset::Global(_) => { - *offset = Offset::Const32(0); - } - _ => unreachable!(), - } - } - } - } - } -} - -fn dummy_value_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::I32 => Instruction::I32Const(0), - ValType::I64 => Instruction::I64Const(0), - ValType::F32 => Instruction::F32Const(0.0), - ValType::F64 => Instruction::F64Const(0.0), - ValType::V128 => Instruction::V128Const(0), - ValType::FuncRef | ValType::ExternRef => Instruction::RefNull(ty), - } -} - -fn eq_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::F32 => Instruction::F32Eq, - ValType::F64 => Instruction::F64Eq, - ValType::I32 => Instruction::I32Eq, - ValType::I64 => Instruction::I64Eq, - _ => panic!("not a numeric type"), - } -} - -fn eqz_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::I32 => Instruction::I32Eqz, - ValType::I64 => Instruction::I64Eqz, - _ => panic!("not an integer type"), - } -} - -fn type_of_integer_operation(inst: &Instruction) -> ValType { - match inst { - Instruction::I32DivU - | Instruction::I32DivS - | Instruction::I32RemU - | Instruction::I32RemS => ValType::I32, - Instruction::I64RemU - | Instruction::I64DivU - | Instruction::I64DivS - | Instruction::I64RemS => ValType::I64, - _ => panic!("not integer division or remainder"), - } -} - -fn type_of_float_conversion(inst: &Instruction) -> ValType { - match inst { - Instruction::I32TruncF32S - | Instruction::I32TruncF32U - | Instruction::I64TruncF32S - | Instruction::I64TruncF32U => ValType::F32, - Instruction::I32TruncF64S - | Instruction::I32TruncF64U - | Instruction::I64TruncF64S - | Instruction::I64TruncF64U => ValType::F64, - _ => panic!("not a float -> integer conversion"), - } -} - -fn type_of_memory_access(inst: &Instruction) -> ValType { - match inst { - Instruction::I32Load(_) - | Instruction::I32Load8_S(_) - | Instruction::I32Load8_U(_) - | Instruction::I32Load16_S(_) - | Instruction::I32Load16_U(_) - | Instruction::I32Store(_) - | Instruction::I32Store8(_) - | Instruction::I32Store16(_) => ValType::I32, - - Instruction::I64Load(_) - | Instruction::I64Load8_S(_) - | Instruction::I64Load8_U(_) - | Instruction::I64Load16_S(_) - | Instruction::I64Load16_U(_) - | Instruction::I64Load32_S(_) - | Instruction::I64Load32_U(_) - | Instruction::I64Store(_) - | Instruction::I64Store8(_) - | Instruction::I64Store16(_) - | Instruction::I64Store32(_) => ValType::I64, - - Instruction::F32Load(_) | Instruction::F32Store(_) => ValType::F32, - - Instruction::F64Load(_) | Instruction::F64Store(_) => ValType::F64, - - Instruction::V128Load { .. } - | Instruction::V128Load8x8S { .. } - | Instruction::V128Load8x8U { .. } - | Instruction::V128Load16x4S { .. } - | Instruction::V128Load16x4U { .. } - | Instruction::V128Load32x2S { .. } - | Instruction::V128Load32x2U { .. } - | Instruction::V128Load8Splat { .. } - | Instruction::V128Load16Splat { .. } - | Instruction::V128Load32Splat { .. } - | Instruction::V128Load64Splat { .. } - | Instruction::V128Load32Zero { .. } - | Instruction::V128Load64Zero { .. } - | Instruction::V128Store { .. } => ValType::V128, - - _ => panic!("not a memory access instruction"), - } -} - -fn int_min_const_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::I32 => Instruction::I32Const(i32::MIN), - ValType::I64 => Instruction::I64Const(i64::MIN), - _ => panic!("not an int type"), - } -} - -fn int_const_inst<'a>(ty: ValType, x: i64) -> Instruction<'a> { - match ty { - ValType::I32 => Instruction::I32Const(x as i32), - ValType::I64 => Instruction::I64Const(x), - _ => panic!("not an int type"), - } -} - -fn int_mul_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::I32 => Instruction::I32Mul, - ValType::I64 => Instruction::I64Mul, - _ => panic!("not an int type"), - } -} - -fn int_add_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::I32 => Instruction::I32Add, - ValType::I64 => Instruction::I64Add, - _ => panic!("not an int type"), - } -} - -fn int_le_u_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::I32 => Instruction::I32LeU, - ValType::I64 => Instruction::I64LeU, - _ => panic!("not an int type"), - } -} - -fn int_ne_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::I32 => Instruction::I32Ne, - ValType::I64 => Instruction::I64Ne, - _ => panic!("not an int type"), - } -} - -fn flt_inf_const_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::F32 => Instruction::F32Const(f32::INFINITY), - ValType::F64 => Instruction::F64Const(f64::INFINITY), - _ => panic!("not a float type"), - } -} - -fn flt_neg_inf_const_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::F32 => Instruction::F32Const(f32::NEG_INFINITY), - ValType::F64 => Instruction::F64Const(f64::NEG_INFINITY), - _ => panic!("not a float type"), - } -} - -fn flt_nan_const_inst<'a>(ty: ValType) -> Instruction<'a> { - match ty { - ValType::F32 => Instruction::F32Const(f32::NAN), - ValType::F64 => Instruction::F64Const(f64::NAN), - _ => panic!("not a float type"), - } -} - -fn size_of_type_in_memory(ty: ValType) -> u64 { - match ty { - ValType::I32 => 4, - ValType::I64 => 8, - ValType::F32 => 4, - ValType::F64 => 8, - ValType::V128 => 16, - ValType::FuncRef | ValType::ExternRef => panic!("not a memory type"), - } -} diff --git a/crates/wasm-smith/src/lib.rs b/crates/wasm-smith/src/lib.rs index 95a3ebd346..941843a3a0 100644 --- a/crates/wasm-smith/src/lib.rs +++ b/crates/wasm-smith/src/lib.rs @@ -11,11 +11,8 @@ //! //! Next, add `wasm-smith` to your dependencies: //! -//! ```toml -//! # fuzz/Cargo.toml -//! -//! [dependencies] -//! wasm-smith = "0.4.0" +//! ```shell +//! $ cargo add wasm-smith //! ``` //! //! Then, define your fuzz target so that it takes arbitrary @@ -62,14 +59,13 @@ mod config; mod core; pub use crate::core::{ - no_traps::NotSupported, ConfiguredModule, InstructionKind, InstructionKinds, - MaybeInvalidModule, Module, + ConfiguredModule, InstructionKind, InstructionKinds, MaybeInvalidModule, Module, }; use arbitrary::{Result, Unstructured}; pub use component::{Component, ConfiguredComponent}; pub use config::{Config, DefaultConfig, SwarmConfig}; - -use std::{collections::HashSet, str}; +use std::{collections::HashSet, fmt::Write, str}; +use wasmparser::names::{KebabStr, KebabString}; /// Do something an arbitrary number of times. /// @@ -132,22 +128,66 @@ pub(crate) fn unique_string( ) -> Result { let mut name = limited_string(max_size, u)?; while names.contains(&name) { - name.push_str(&format!("{}", names.len())); + write!(&mut name, "{}", names.len()).unwrap(); } names.insert(name.clone()); Ok(name) } -pub(crate) fn unique_non_empty_string( +pub(crate) fn unique_kebab_string( max_size: usize, - names: &mut HashSet, + names: &mut HashSet, u: &mut Unstructured, -) -> Result { - let mut s = unique_string(max_size, names, u)?; - while s.is_empty() || names.contains(&s) { - use std::fmt::Write; - write!(&mut s, "{}", names.len()).unwrap(); +) -> Result { + let size = std::cmp::min(u.arbitrary_len::()?, max_size); + let mut name = String::with_capacity(size); + let mut require_alpha = true; + for _ in 0..size { + name.push(match u.int_in_range::(0..=36)? { + x if (0..26).contains(&x) => { + require_alpha = false; + (b'a' + x) as char + } + x if (26..36).contains(&x) => { + if require_alpha { + require_alpha = false; + (b'a' + (x - 26)) as char + } else { + (b'0' + (x - 26)) as char + } + } + x if x == 36 => { + if require_alpha { + require_alpha = false; + 'a' + } else { + require_alpha = true; + '-' + } + } + _ => unreachable!(), + }); + } + + if name.is_empty() || name.ends_with('-') { + name.push('a'); + } + + while names.contains(KebabStr::new(&name).unwrap()) { + write!(&mut name, "{}", names.len()).unwrap(); } - names.insert(s.clone()); - Ok(s) + + let name = KebabString::new(name).unwrap(); + names.insert(name.clone()); + + Ok(name) +} + +pub(crate) fn unique_url( + max_size: usize, + names: &mut HashSet, + u: &mut Unstructured, +) -> Result { + let path = unique_kebab_string(max_size, names, u)?; + Ok(format!("https://example.com/{path}")) } diff --git a/crates/wasm-smith/tests/component.rs b/crates/wasm-smith/tests/component.rs index fe5d253f66..7d5a40159c 100644 --- a/crates/wasm-smith/tests/component.rs +++ b/crates/wasm-smith/tests/component.rs @@ -3,6 +3,7 @@ use rand::{rngs::SmallRng, RngCore, SeedableRng}; use wasm_smith::Component; #[test] +#[ignore] // FIXME(#1000): need to update wasm-smith's support for components fn smoke_test_component() { const NUM_RUNS: usize = 4096; diff --git a/crates/wasm-smith/tests/core.rs b/crates/wasm-smith/tests/core.rs index 97af657420..4a563566df 100644 --- a/crates/wasm-smith/tests/core.rs +++ b/crates/wasm-smith/tests/core.rs @@ -127,18 +127,17 @@ fn smoke_test_imports_config() { for payload in Parser::new(0).parse_all(&wasm_bytes) { let payload = payload.unwrap(); - if let wasmparser::Payload::TypeSection(mut rdr) = payload { + if let wasmparser::Payload::TypeSection(rdr) = payload { // Gather the signature types to later check function types against. - while let Ok(ty) = rdr.read() { - match ty { - wasmparser::Type::Func(ft) => sig_types.push(ft), - } + for ty in rdr.into_iter_err_on_gc_types() { + sig_types.push(ty.unwrap()); } - } else if let wasmparser::Payload::ImportSection(mut rdr) = payload { + } else if let wasmparser::Payload::ImportSection(rdr) = payload { // Read out imports, checking that they all are within the list of expected // imports (i.e. we don't generate arbitrary ones), and that we handle the // logic correctly (i.e. signature types are as expected) - while let Ok(import) = rdr.read() { + for import in rdr { + let import = import.unwrap(); use AvailableImportKind as I; let entry = imports_seen.get_mut(&(import.module, import.name)); match (entry, &import.ty) { @@ -150,7 +149,7 @@ fn smoke_test_imports_config() { *seen = true } (Some((seen, I::Table(t))), TypeRef::Table(tt)) - if *t == tt.element_type => + if *t == ValType::Ref(tt.element_type) => { *seen = true } @@ -203,13 +202,13 @@ fn smoke_test_no_trapping_mode() { let mut buf = vec![0; 2048]; for _ in 0..1024 { rng.fill_bytes(&mut buf); - let u = Unstructured::new(&buf); - if let Ok(mut module) = Module::arbitrary_take_rest(u) { - if module.no_traps().is_ok() { - let wasm_bytes = module.to_bytes(); - let mut validator = Validator::new_with_features(wasm_features()); - validate(&mut validator, &wasm_bytes); - } + let mut u = Unstructured::new(&buf); + let mut cfg = SwarmConfig::arbitrary(&mut u).unwrap(); + cfg.disallow_traps = true; + if let Ok(module) = Module::new(cfg, &mut u) { + let wasm_bytes = module.to_bytes(); + let mut validator = Validator::new_with_features(wasm_features()); + validate(&mut validator, &wasm_bytes); } } } @@ -220,6 +219,7 @@ fn wasm_features() -> WasmFeatures { relaxed_simd: true, memory64: true, exceptions: true, + tail_call: true, ..WasmFeatures::default() } } @@ -251,7 +251,7 @@ fn import_config( ("env", "pipo", Func(&[I32], &[I32])), ("env", "popo", Func(&[], &[I32, I32])), ("env", "mem", Memory), - ("env", "tbl", Table(FuncRef)), + ("env", "tbl", Table(ValType::FUNCREF)), ("vars", "g", Global(I64)), ("tags", "tag1", Tag(&[I32])), ] @@ -292,12 +292,16 @@ fn parser_features_from_config(config: &impl Config) -> WasmFeatures { multi_memory: config.max_memories() > 1, exceptions: config.exceptions_enabled(), memory64: config.memory64_enabled(), + tail_call: config.tail_call_enabled(), threads: false, - tail_call: false, - deterministic_only: false, + floats: true, extended_const: false, component_model: false, + function_references: false, + memory_control: false, + gc: false, + component_model_values: false, } } diff --git a/crates/wasmparser/Cargo.toml b/crates/wasmparser/Cargo.toml index 661fd8161f..d32cbd6c0d 100644 --- a/crates/wasmparser/Cargo.toml +++ b/crates/wasmparser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmparser" -version = "0.90.0" +version = "0.115.0" authors = ["Yury Delendik "] license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser" @@ -9,28 +9,24 @@ keywords = ["parser", "WebAssembly", "wasm"] description = """ A simple event-driven library for parsing WebAssembly binary files. """ -edition = "2021" +edition.workspace = true exclude = ["benches/*.wasm"] [dependencies] -indexmap = "1.8.0" +indexmap = { workspace = true } +semver = { workspace = true } [dev-dependencies] -anyhow = "1.0" -criterion = "0.3" -getopts = "0.2" +anyhow = { workspace = true } +criterion = { workspace = true } wat = { path = "../wat" } wast = { path = "../wast" } -rayon = "1.3" -wasmparser-dump = { path = "../dump" } +rayon = { workspace = true } once_cell = "1.13.0" +wasm-encoder = { workspace = true } +env_logger.workspace = true +log.workspace = true [[bench]] name = "benchmark" harness = false - -[features] -# The "deterministic" feature supports only Wasm code with "deterministic" execution -# across any hardware. This feature is very critical for many Blockchain infrastructures -# that rely on deterministic executions of smart contracts across different hardwares. -deterministic = [] diff --git a/crates/wasmparser/benches/benchmark.rs b/crates/wasmparser/benches/benchmark.rs index ad82213cae..24660923fe 100644 --- a/crates/wasmparser/benches/benchmark.rs +++ b/crates/wasmparser/benches/benchmark.rs @@ -1,16 +1,10 @@ -#[macro_use] -extern crate criterion; - use anyhow::Result; -use criterion::Criterion; +use criterion::{criterion_group, criterion_main, Criterion}; use once_cell::unsync::Lazy; use std::fs; use std::path::Path; use std::path::PathBuf; -use wasmparser::{ - BlockType, BrTable, DataKind, ElementKind, Ieee32, Ieee64, MemArg, Parser, Payload, ValType, - Validator, VisitOperator, WasmFeatures, V128, -}; +use wasmparser::{DataKind, ElementKind, Parser, Payload, Validator, VisitOperator, WasmFeatures}; /// A benchmark input. pub struct BenchmarkInput { @@ -136,8 +130,17 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> { op?; } } - for op in item.items.get_items_reader()? { - op?; + match item.items { + wasmparser::ElementItems::Functions(r) => { + for op in r { + op?; + } + } + wasmparser::ElementItems::Expressions(_, r) => { + for op in r { + op?; + } + } } } } @@ -155,7 +158,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> { let mut reader = body.get_binary_reader(); for _ in 0..reader.read_var_u32()? { reader.read_var_u32()?; - reader.read_val_type()?; + reader.read::()?; } while !reader.eof() { reader.visit_operator(&mut NopVisit)?; @@ -229,7 +232,24 @@ fn collect_benchmark_inputs() -> Vec { ret } +fn skip_validation(test: &Path) -> bool { + let broken = [ + "gc/gc-rec-sub.wat", + "proposals/gc/type-equivalence.wast", + "proposals/gc/type-subtyping.wast", + ]; + + let test_path = test.to_str().unwrap().replace("\\", "/"); // for windows paths + if broken.iter().any(|x| test_path.contains(x)) { + return true; + } + + false +} + fn define_benchmarks(c: &mut Criterion) { + let _ = env_logger::try_init(); + fn validator() -> Validator { Validator::new_with_features(WasmFeatures { reference_types: true, @@ -244,10 +264,14 @@ fn define_benchmarks(c: &mut Criterion) { multi_memory: true, memory64: true, extended_const: true, - deterministic_only: false, + floats: true, mutable_global: true, saturating_float_to_int: true, sign_extension: true, + function_references: true, + memory_control: true, + gc: true, + component_model_values: true, }) } @@ -274,6 +298,10 @@ fn define_benchmarks(c: &mut Criterion) { let validate_inputs = once_cell::unsync::Lazy::new(|| { let mut list = Vec::new(); for input in test_inputs.iter() { + if skip_validation(&input.path) { + continue; + } + log::debug!("Validating {}", input.path.display()); if validator().validate_all(&input.wasm).is_ok() { list.push(&input.wasm); } @@ -320,7 +348,7 @@ struct NopVisit; macro_rules! define_visit_operator { ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { $( - fn $visit(&mut self, _offset: usize $($(,$arg: $argty)*)?) { + fn $visit(&mut self $($(,$arg: $argty)*)?) { define_visit_operator!(@visit $op $( $($arg)* )?); } )* diff --git a/crates/wasmparser/benches/lots-of-types.wasm b/crates/wasmparser/benches/lots-of-types.wasm new file mode 100644 index 0000000000..8769b0a976 Binary files /dev/null and b/crates/wasmparser/benches/lots-of-types.wasm differ diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 88c04b7213..6e5354913d 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -17,18 +17,11 @@ use crate::{limits::*, *}; use std::convert::TryInto; use std::error::Error; use std::fmt; +use std::marker; use std::ops::Range; use std::str; -fn is_name(name: &str, expected: &'static str) -> bool { - name == expected -} - -fn is_name_prefix(name: &str, prefix: &'static str) -> bool { - name.starts_with(prefix) -} - -const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm"; +pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm"; /// A binary reader for WebAssembly modules. #[derive(Debug, Clone)] @@ -99,6 +92,11 @@ impl BinaryReaderError { pub fn offset(&self) -> usize { self.inner.offset } + + pub(crate) fn add_context(&mut self, mut context: String) { + context.push_str("\n"); + self.inner.message.insert_str(0, &context); + } } /// A binary reader of the WebAssembly structures and types. @@ -106,7 +104,7 @@ impl BinaryReaderError { pub struct BinaryReader<'a> { pub(crate) buffer: &'a [u8], pub(crate) position: usize, - pub(crate) original_offset: usize, + original_offset: usize, allow_memarg64: bool, } @@ -181,6 +179,16 @@ impl<'a> BinaryReader<'a> { } } + /// Reads a value of type `T` from this binary reader, advancing the + /// internal position in this reader forward as data is read. + #[inline] + pub fn read(&mut self) -> Result + where + T: FromReader<'a>, + { + T::from_reader(self) + } + pub(crate) fn read_u7(&mut self) -> Result { let b = self.read_u8()?; if (b & 0x80) != 0 { @@ -192,33 +200,7 @@ impl<'a> BinaryReader<'a> { Ok(b) } - /// Reads a core WebAssembly value type from the binary reader. - pub fn read_val_type(&mut self) -> Result { - match Self::val_type_from_byte(self.peek()?) { - Some(ty) => { - self.position += 1; - Ok(ty) - } - None => Err(BinaryReaderError::new( - "invalid value type", - self.original_position(), - )), - } - } - - pub(crate) fn read_component_start(&mut self) -> Result { - let func_index = self.read_var_u32()?; - let size = self.read_size(MAX_WASM_START_ARGS, "start function arguments")?; - Ok(ComponentStartFunction { - func_index, - arguments: (0..size) - .map(|_| self.read_var_u32()) - .collect::>()?, - results: self.read_size(MAX_WASM_FUNCTION_RETURNS, "start function results")? as u32, - }) - } - - fn external_kind_from_byte(byte: u8, offset: usize) -> Result { + pub(crate) fn external_kind_from_byte(byte: u8, offset: usize) -> Result { match byte { 0x00 => Ok(ExternalKind::Func), 0x01 => Ok(ExternalKind::Table), @@ -229,640 +211,47 @@ impl<'a> BinaryReader<'a> { } } - pub(crate) fn read_external_kind(&mut self) -> Result { - let offset = self.original_position(); - Self::external_kind_from_byte(self.read_u8()?, offset) - } - - fn component_external_kind_from_bytes( - byte1: u8, - byte2: Option, - offset: usize, - ) -> Result { - Ok(match byte1 { - 0x00 => match byte2.unwrap() { - 0x11 => ComponentExternalKind::Module, - x => { - return Err(Self::invalid_leading_byte_error( - x, - "component external kind", - offset + 1, - )) - } - }, - 0x01 => ComponentExternalKind::Func, - 0x02 => ComponentExternalKind::Value, - 0x03 => ComponentExternalKind::Type, - 0x04 => ComponentExternalKind::Component, - 0x05 => ComponentExternalKind::Instance, - x => { - return Err(Self::invalid_leading_byte_error( - x, - "component external kind", - offset, - )) - } - }) - } - - pub(crate) fn read_component_external_kind(&mut self) -> Result { - let offset = self.original_position(); - let byte1 = self.read_u8()?; - let byte2 = if byte1 == 0x00 { - Some(self.read_u8()?) - } else { - None - }; - - Self::component_external_kind_from_bytes(byte1, byte2, offset) - } - - pub(crate) fn read_func_type(&mut self) -> Result { - let len_params = self.read_size(MAX_WASM_FUNCTION_PARAMS, "function params")?; - let mut params_results = Vec::with_capacity(len_params); - for _ in 0..len_params { - params_results.push(self.read_val_type()?); - } - let len_results = self.read_size(MAX_WASM_FUNCTION_RETURNS, "function returns")?; - params_results.reserve(len_results); - for _ in 0..len_results { - params_results.push(self.read_val_type()?); - } - Ok(FuncType::from_raw_parts(params_results.into(), len_params)) - } - - pub(crate) fn read_type(&mut self) -> Result { - Ok(match self.read_u8()? { - 0x60 => Type::Func(self.read_func_type()?), - x => return self.invalid_leading_byte(x, "type"), - }) - } - - pub(crate) fn read_core_type(&mut self) -> Result> { - Ok(match self.read_u8()? { - 0x60 => CoreType::Func(self.read_func_type()?), - 0x50 => { - let size = self.read_size(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")?; - CoreType::Module( - (0..size) - .map(|_| self.read_module_type_decl()) - .collect::>()?, - ) - } - x => return self.invalid_leading_byte(x, "core type"), - }) - } - - pub(crate) fn read_component_type(&mut self) -> Result> { - Ok(match self.read_u8()? { - 0x40 => ComponentType::Func(ComponentFuncType { - params: self - .read_type_vec(MAX_WASM_FUNCTION_PARAMS, "component function parameters")?, - results: self - .read_type_vec(MAX_WASM_FUNCTION_RETURNS, "component function results")?, - }), - 0x41 => { - let size = - self.read_size(MAX_WASM_COMPONENT_TYPE_DECLS, "component type declaration")?; - ComponentType::Component( - (0..size) - .map(|_| self.read_component_type_decl()) - .collect::>()?, - ) - } - 0x42 => { - let size = - self.read_size(MAX_WASM_INSTANCE_TYPE_DECLS, "instance type declaration")?; - ComponentType::Instance( - (0..size) - .map(|_| self.read_instance_type_decl()) - .collect::>()?, - ) - } - x => { - if let Some(ty) = Self::primitive_val_type_from_byte(x) { - ComponentType::Defined(ComponentDefinedType::Primitive(ty)) - } else { - ComponentType::Defined(self.read_component_defined_type(x)?) - } - } - }) - } - - pub(crate) fn read_type_vec(&mut self, max: usize, desc: &str) -> Result> { - Ok(match self.read_u8()? { - 0x00 => TypeVec::Unnamed(self.read_component_val_type()?), - 0x01 => { - let size = self.read_size(max, desc)?; - TypeVec::Named( - (0..size) - .map(|_| Ok((self.read_string()?, self.read_component_val_type()?))) - .collect::>()?, - ) - } - x => return self.invalid_leading_byte(x, desc), - }) - } - - pub(crate) fn read_module_type_decl(&mut self) -> Result> { - Ok(match self.read_u8()? { - 0x00 => ModuleTypeDeclaration::Import(self.read_import()?), - 0x01 => ModuleTypeDeclaration::Type(self.read_type()?), - 0x02 => { - let kind = match self.read_u8()? { - 0x10 => OuterAliasKind::Type, - x => { - return self.invalid_leading_byte(x, "outer alias kind"); - } - }; - match self.read_u8()? { - 0x01 => ModuleTypeDeclaration::OuterAlias { - kind, - count: self.read_var_u32()?, - index: self.read_var_u32()?, - }, - x => { - return self.invalid_leading_byte(x, "outer alias target"); - } - } - } - 0x03 => ModuleTypeDeclaration::Export { - name: self.read_string()?, - ty: self.read_type_ref()?, - }, - x => return self.invalid_leading_byte(x, "type definition"), - }) - } - - pub(crate) fn read_component_type_decl(&mut self) -> Result> { - // Component types are effectively instance types with the additional - // variant of imports; check for imports here or delegate to - // `read_instance_type_decl` with the appropriate conversions. - if self.peek()? == 0x03 { - self.position += 1; - return Ok(ComponentTypeDeclaration::Import( - self.read_component_import()?, - )); - } - - Ok(match self.read_instance_type_decl()? { - InstanceTypeDeclaration::CoreType(t) => ComponentTypeDeclaration::CoreType(t), - InstanceTypeDeclaration::Type(t) => ComponentTypeDeclaration::Type(t), - InstanceTypeDeclaration::Alias(a) => ComponentTypeDeclaration::Alias(a), - InstanceTypeDeclaration::Export { name, ty } => { - ComponentTypeDeclaration::Export { name, ty } - } - }) - } - - pub(crate) fn read_instance_type_decl(&mut self) -> Result> { - Ok(match self.read_u8()? { - 0x00 => InstanceTypeDeclaration::CoreType(self.read_core_type()?), - 0x01 => InstanceTypeDeclaration::Type(self.read_component_type()?), - 0x02 => InstanceTypeDeclaration::Alias(self.read_component_alias()?), - 0x04 => InstanceTypeDeclaration::Export { - name: self.read_string()?, - ty: self.read_component_type_ref()?, - }, - x => return self.invalid_leading_byte(x, "component or instance type declaration"), - }) - } - - fn primitive_val_type_from_byte(byte: u8) -> Option { - Some(match byte { - 0x7f => PrimitiveValType::Bool, - 0x7e => PrimitiveValType::S8, - 0x7d => PrimitiveValType::U8, - 0x7c => PrimitiveValType::S16, - 0x7b => PrimitiveValType::U16, - 0x7a => PrimitiveValType::S32, - 0x79 => PrimitiveValType::U32, - 0x78 => PrimitiveValType::S64, - 0x77 => PrimitiveValType::U64, - 0x76 => PrimitiveValType::Float32, - 0x75 => PrimitiveValType::Float64, - 0x74 => PrimitiveValType::Char, - 0x73 => PrimitiveValType::String, - _ => return None, - }) - } - - fn read_variant_case(&mut self) -> Result> { - Ok(VariantCase { - name: self.read_string()?, - ty: self.read_optional_val_type()?, - refines: match self.read_u8()? { - 0x0 => None, - 0x1 => Some(self.read_var_u32()?), - x => return self.invalid_leading_byte(x, "variant case refines"), - }, - }) - } - - fn read_component_val_type(&mut self) -> Result { - if let Some(ty) = Self::primitive_val_type_from_byte(self.peek()?) { - self.position += 1; - return Ok(ComponentValType::Primitive(ty)); - } - - Ok(ComponentValType::Type(self.read_var_s33()? as u32)) - } - - fn read_component_defined_type(&mut self, byte: u8) -> Result> { - Ok(match byte { - 0x72 => { - let size = self.read_size(MAX_WASM_RECORD_FIELDS, "record field")?; - ComponentDefinedType::Record( - (0..size) - .map(|_| Ok((self.read_string()?, self.read_component_val_type()?))) - .collect::>()?, - ) - } - 0x71 => { - let size = self.read_size(MAX_WASM_VARIANT_CASES, "variant cases")?; - ComponentDefinedType::Variant( - (0..size) - .map(|_| self.read_variant_case()) - .collect::>()?, - ) - } - 0x70 => ComponentDefinedType::List(self.read_component_val_type()?), - 0x6f => { - let size = self.read_size(MAX_WASM_TUPLE_TYPES, "tuple types")?; - ComponentDefinedType::Tuple( - (0..size) - .map(|_| self.read_component_val_type()) - .collect::>()?, - ) - } - 0x6e => { - let size = self.read_size(MAX_WASM_FLAG_NAMES, "flag names")?; - ComponentDefinedType::Flags( - (0..size) - .map(|_| self.read_string()) - .collect::>()?, - ) - } - 0x6d => { - let size = self.read_size(MAX_WASM_ENUM_CASES, "enum cases")?; - ComponentDefinedType::Enum( - (0..size) - .map(|_| self.read_string()) - .collect::>()?, - ) - } - 0x6c => { - let size = self.read_size(MAX_WASM_UNION_TYPES, "union types")?; - ComponentDefinedType::Union( - (0..size) - .map(|_| self.read_component_val_type()) - .collect::>()?, - ) - } - 0x6b => ComponentDefinedType::Option(self.read_component_val_type()?), - 0x6a => ComponentDefinedType::Result { - ok: self.read_optional_val_type()?, - err: self.read_optional_val_type()?, - }, - x => return self.invalid_leading_byte(x, "component defined type"), - }) - } - - pub(crate) fn read_export(&mut self) -> Result> { - Ok(Export { - name: self.read_string()?, - kind: self.read_external_kind()?, - index: self.read_var_u32()?, - }) - } - - pub(crate) fn read_component_export(&mut self) -> Result> { - Ok(ComponentExport { - name: self.read_string()?, - kind: self.read_component_external_kind()?, - index: self.read_var_u32()?, - }) - } - - pub(crate) fn read_import(&mut self) -> Result> { - Ok(Import { - module: self.read_string()?, - name: self.read_string()?, - ty: self.read_type_ref()?, - }) - } - - pub(crate) fn read_component_import(&mut self) -> Result> { - Ok(ComponentImport { - name: self.read_string()?, - ty: self.read_component_type_ref()?, - }) - } - - pub(crate) fn read_component_type_ref(&mut self) -> Result { - Ok(match self.read_component_external_kind()? { - ComponentExternalKind::Module => ComponentTypeRef::Module(self.read_var_u32()?), - ComponentExternalKind::Func => ComponentTypeRef::Func(self.read_var_u32()?), - ComponentExternalKind::Value => { - ComponentTypeRef::Value(self.read_component_val_type()?) - } - ComponentExternalKind::Type => { - ComponentTypeRef::Type(self.read_type_bounds()?, self.read_var_u32()?) - } - ComponentExternalKind::Instance => ComponentTypeRef::Instance(self.read_var_u32()?), - ComponentExternalKind::Component => ComponentTypeRef::Component(self.read_var_u32()?), - }) - } - - pub(crate) fn read_type_bounds(&mut self) -> Result { - Ok(match self.read_u8()? { - 0x00 => TypeBounds::Eq, - x => return self.invalid_leading_byte(x, "type bound"), - }) - } - - pub(crate) fn read_canonical_func(&mut self) -> Result { - Ok(match self.read_u8()? { - 0x00 => match self.read_u8()? { - 0x00 => CanonicalFunction::Lift { - core_func_index: self.read_var_u32()?, - options: (0..self - .read_size(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?) - .map(|_| self.read_canonical_option()) - .collect::>()?, - type_index: self.read_var_u32()?, - }, - x => return self.invalid_leading_byte(x, "canonical function lift"), - }, - 0x01 => match self.read_u8()? { - 0x00 => CanonicalFunction::Lower { - func_index: self.read_var_u32()?, - options: (0..self - .read_size(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?) - .map(|_| self.read_canonical_option()) - .collect::>()?, - }, - x => return self.invalid_leading_byte(x, "canonical function lower"), - }, - x => return self.invalid_leading_byte(x, "canonical function"), - }) - } - - pub(crate) fn read_canonical_option(&mut self) -> Result { - Ok(match self.read_u8()? { - 0x00 => CanonicalOption::UTF8, - 0x01 => CanonicalOption::UTF16, - 0x02 => CanonicalOption::CompactUTF16, - 0x03 => CanonicalOption::Memory(self.read_var_u32()?), - 0x04 => CanonicalOption::Realloc(self.read_var_u32()?), - 0x05 => CanonicalOption::PostReturn(self.read_var_u32()?), - x => return self.invalid_leading_byte(x, "canonical option"), - }) - } - - pub(crate) fn read_instance(&mut self) -> Result> { - Ok(match self.read_u8()? { - 0x00 => Instance::Instantiate { - module_index: self.read_var_u32()?, - args: (0..self - .read_size(MAX_WASM_INSTANTIATION_ARGS, "core instantiation arguments")?) - .map(|_| self.read_instantiation_arg()) - .collect::>()?, - }, - 0x01 => Instance::FromExports( - (0..self - .read_size(MAX_WASM_INSTANTIATION_EXPORTS, "core instantiation exports")?) - .map(|_| self.read_export()) - .collect::>()?, - ), - x => return self.invalid_leading_byte(x, "core instance"), - }) - } - - pub(crate) fn read_component_instance(&mut self) -> Result> { - Ok(match self.read_u8()? { - 0x00 => ComponentInstance::Instantiate { - component_index: self.read_var_u32()?, - args: (0..self - .read_size(MAX_WASM_INSTANTIATION_ARGS, "instantiation arguments")?) - .map(|_| self.read_component_instantiation_arg()) - .collect::>()?, - }, - 0x01 => ComponentInstance::FromExports( - (0..self.read_size(MAX_WASM_INSTANTIATION_EXPORTS, "instantiation exports")?) - .map(|_| self.read_component_export()) - .collect::>()?, - ), - x => return self.invalid_leading_byte(x, "instance"), - }) - } - - pub(crate) fn read_instantiation_arg_kind(&mut self) -> Result { - Ok(match self.read_u8()? { - 0x12 => InstantiationArgKind::Instance, - x => return self.invalid_leading_byte(x, "instantiation arg kind"), - }) - } - - pub(crate) fn read_instantiation_arg(&mut self) -> Result> { - Ok(InstantiationArg { - name: self.read_string()?, - kind: self.read_instantiation_arg_kind()?, - index: self.read_var_u32()?, - }) - } - - pub(crate) fn read_component_instantiation_arg( - &mut self, - ) -> Result> { - Ok(ComponentInstantiationArg { - name: self.read_string()?, - kind: self.read_component_external_kind()?, - index: self.read_var_u32()?, - }) - } - - fn component_outer_alias_kind_from_bytes( - byte1: u8, - byte2: Option, - offset: usize, - ) -> Result { - Ok(match byte1 { - 0x00 => match byte2.unwrap() { - 0x10 => ComponentOuterAliasKind::CoreType, - 0x11 => ComponentOuterAliasKind::CoreModule, - x => { - return Err(Self::invalid_leading_byte_error( - x, - "component outer alias kind", - offset + 1, - )) - } - }, - 0x03 => ComponentOuterAliasKind::Type, - 0x04 => ComponentOuterAliasKind::Component, - x => { - return Err(Self::invalid_leading_byte_error( - x, - "component outer alias kind", - offset, - )) - } - }) - } - - pub(crate) fn read_component_alias(&mut self) -> Result> { - // We don't know what type of alias it is yet, so just read the sort bytes - let offset = self.original_position(); - let byte1 = self.read_u8()?; - let byte2 = if byte1 == 0x00 { - Some(self.read_u8()?) - } else { - None - }; - - Ok(match self.read_u8()? { - 0x00 => ComponentAlias::InstanceExport { - kind: Self::component_external_kind_from_bytes(byte1, byte2, offset)?, - instance_index: self.read_var_u32()?, - name: self.read_string()?, - }, - 0x01 => ComponentAlias::CoreInstanceExport { - kind: Self::external_kind_from_byte( - byte2.ok_or_else(|| { - Self::invalid_leading_byte_error(byte1, "core instance export kind", offset) - })?, - offset, - )?, - instance_index: self.read_var_u32()?, - name: self.read_string()?, - }, - 0x02 => ComponentAlias::Outer { - kind: Self::component_outer_alias_kind_from_bytes(byte1, byte2, offset)?, - count: self.read_var_u32()?, - index: self.read_var_u32()?, - }, - x => return self.invalid_leading_byte(x, "alias"), - }) - } - - pub(crate) fn read_type_ref(&mut self) -> Result { - Ok(match self.read_external_kind()? { - ExternalKind::Func => TypeRef::Func(self.read_var_u32()?), - ExternalKind::Table => TypeRef::Table(self.read_table_type()?), - ExternalKind::Memory => TypeRef::Memory(self.read_memory_type()?), - ExternalKind::Global => TypeRef::Global(self.read_global_type()?), - ExternalKind::Tag => TypeRef::Tag(self.read_tag_type()?), - }) - } - - pub(crate) fn read_table_type(&mut self) -> Result { - let element_type = self.read_val_type()?; - let has_max = match self.read_u8()? { - 0x00 => false, - 0x01 => true, - _ => { - return Err(BinaryReaderError::new( - "invalid table resizable limits flags", - self.original_position() - 1, - )) - } - }; - let initial = self.read_var_u32()?; - let maximum = if has_max { - Some(self.read_var_u32()?) - } else { - None - }; - Ok(TableType { - element_type, - initial, - maximum, - }) - } - - pub(crate) fn read_memory_type(&mut self) -> Result { + /// Reads a variable-length 32-bit size from the byte stream while checking + /// against a limit. + pub fn read_size(&mut self, limit: usize, desc: &str) -> Result { let pos = self.original_position(); - let flags = self.read_u8()?; - if (flags & !0b111) != 0 { - return Err(BinaryReaderError::new("invalid memory limits flags", pos)); - } - - let memory64 = flags & 0b100 != 0; - let shared = flags & 0b010 != 0; - let has_max = flags & 0b001 != 0; - Ok(MemoryType { - memory64, - shared, - // FIXME(WebAssembly/memory64#21) as currently specified if the - // `shared` flag is set we should be reading a 32-bit limits field - // here. That seems a bit odd to me at the time of this writing so - // I've taken the liberty of reading a 64-bit limits field in those - // situations. I suspect that this is a typo in the spec, but if not - // we'll need to update this to read a 32-bit limits field when the - // shared flag is set. - initial: if memory64 { - self.read_var_u64()? - } else { - self.read_var_u32()?.into() - }, - maximum: if !has_max { - None - } else if memory64 { - Some(self.read_var_u64()?) - } else { - Some(self.read_var_u32()?.into()) - }, - }) - } - - pub(crate) fn read_tag_type(&mut self) -> Result { - let attribute = self.read_u8()?; - if attribute != 0 { - return Err(BinaryReaderError::new( - "invalid tag attributes", - self.original_position() - 1, - )); - } - Ok(TagType { - kind: TagKind::Exception, - func_type_idx: self.read_var_u32()?, - }) - } - - pub(crate) fn read_global_type(&mut self) -> Result { - Ok(GlobalType { - content_type: self.read_val_type()?, - mutable: match self.read_u8()? { - 0x00 => false, - 0x01 => true, - _ => { - return Err(BinaryReaderError::new( - "malformed mutability", - self.original_position() - 1, - )) - } - }, - }) - } - - // Reads a variable-length 32-bit size from the byte stream while checking - // against a limit. - fn read_size(&mut self, limit: usize, desc: &str) -> Result { let size = self.read_var_u32()? as usize; if size > limit { - bail!(self.original_position() - 4, "{desc} size is out of bounds",); + bail!(pos, "{desc} size is out of bounds"); } Ok(size) } + /// Reads a variable-length 32-bit size from the byte stream while checking + /// against a limit. + /// + /// Then reads that many values of type `T` and returns them as an iterator. + /// + /// Note that regardless of how many items are read from the returned + /// iterator the items will still be parsed from this reader. + pub fn read_iter<'me, T>( + &'me mut self, + limit: usize, + desc: &str, + ) -> Result> + where + T: FromReader<'a>, + { + let size = self.read_size(limit, desc)?; + Ok(BinaryReaderIter { + remaining: size, + reader: self, + _marker: marker::PhantomData, + }) + } + fn read_first_byte_and_var_u32(&mut self) -> Result<(u8, u32)> { let pos = self.position; let val = self.read_var_u32()?; Ok((self.buffer[pos], val)) } - fn read_memarg(&mut self) -> Result { + fn read_memarg(&mut self, max_align: u8) -> Result { let flags_pos = self.original_position(); let mut flags = self.read_var_u32()?; let memory = if flags & (1 << 6) != 0 { @@ -883,47 +272,12 @@ impl<'a> BinaryReader<'a> { }; Ok(MemArg { align, + max_align, offset, memory, }) } - pub(crate) fn read_section_code(&mut self, id: u8, offset: usize) -> Result> { - match id { - 0 => { - let name = self.read_string()?; - let kind = if is_name(name, "name") { - CustomSectionKind::Name - } else if is_name(name, "producers") { - CustomSectionKind::Producers - } else if is_name(name, "sourceMappingURL") { - CustomSectionKind::SourceMappingURL - } else if is_name_prefix(name, "reloc.") { - CustomSectionKind::Reloc - } else if is_name(name, "linking") { - CustomSectionKind::Linking - } else { - CustomSectionKind::Unknown - }; - Ok(SectionCode::Custom { name, kind }) - } - 1 => Ok(SectionCode::Type), - 2 => Ok(SectionCode::Import), - 3 => Ok(SectionCode::Function), - 4 => Ok(SectionCode::Table), - 5 => Ok(SectionCode::Memory), - 6 => Ok(SectionCode::Global), - 7 => Ok(SectionCode::Export), - 8 => Ok(SectionCode::Start), - 9 => Ok(SectionCode::Element), - 10 => Ok(SectionCode::Code), - 11 => Ok(SectionCode::Data), - 12 => Ok(SectionCode::DataCount), - 13 => Ok(SectionCode::Tag), - _ => Err(BinaryReaderError::new("invalid section code", offset)), - } - } - fn read_br_table(&mut self) -> Result> { let cnt = self.read_size(MAX_WASM_BR_TABLE_SIZE, "br_table")?; let start = self.position; @@ -969,6 +323,29 @@ impl<'a> BinaryReader<'a> { Ok(&self.buffer[start..self.position]) } + /// Reads a length-prefixed list of bytes from this reader and returns a + /// new `BinaryReader` to read that list of bytes. + /// + /// Advances the position of this reader by the number of bytes read. + pub fn read_reader(&mut self, err: &str) -> Result> { + let size = self.read_var_u32()? as usize; + let body_start = self.position; + let buffer = match self.buffer.get(self.position..).and_then(|s| s.get(..size)) { + Some(buf) => buf, + None => { + return Err(BinaryReaderError::new( + err, + self.original_offset + self.buffer.len(), + )) + } + }; + self.position += size; + Ok(BinaryReader::new_with_offset( + buffer, + self.original_offset + body_start, + )) + } + /// Advances the `BinaryReader` four bytes and returns a `u32`. /// # Errors /// If `BinaryReader` has less than four bytes remaining. @@ -1099,13 +476,15 @@ impl<'a> BinaryReader<'a> { Ok(result) } - /// Advances the `BinaryReader` `len` bytes, skipping the result. - /// # Errors - /// If `BinaryReader` has less than `len` bytes remaining. - pub fn skip_bytes(&mut self, len: usize) -> Result<()> { - self.ensure_has_bytes(len)?; - self.position += len; - Ok(()) + /// Executes `f` to skip some data in this binary reader and then returns a + /// reader which will read the skipped data. + pub fn skip(&mut self, f: impl FnOnce(&mut Self) -> Result<()>) -> Result { + let start = self.position; + f(self)?; + Ok(BinaryReader::new_with_offset( + &self.buffer[start..self.position], + self.original_offset + start, + )) } /// Advances the `BinaryReader` past a WebAssembly string. This method does @@ -1122,15 +501,9 @@ impl<'a> BinaryReader<'a> { self.original_position() - 1, )); } - self.skip_bytes(len) - } - - pub(crate) fn skip_to(&mut self, position: usize) { - assert!( - self.position <= position && position <= self.buffer.len(), - "skip_to allowed only into region past current position" - ); - self.position = position; + self.ensure_has_bytes(len)?; + self.position += len; + Ok(()) } /// Advances the `BinaryReader` up to four bytes to parse a variable @@ -1286,28 +659,8 @@ impl<'a> BinaryReader<'a> { }) } - fn read_optional_val_type(&mut self) -> Result> { - match self.read_u8()? { - 0x0 => Ok(None), - 0x1 => Ok(Some(self.read_component_val_type()?)), - x => self.invalid_leading_byte(x, "optional component value type"), - } - } - - fn read_memarg_of_align(&mut self, max_align: u8) -> Result { - let align_pos = self.original_position(); - let imm = self.read_memarg()?; - if imm.align > max_align { - return Err(BinaryReaderError::new( - "alignment must not be larger than natural", - align_pos, - )); - } - Ok(imm) - } - #[cold] - fn invalid_leading_byte(&self, byte: u8, desc: &str) -> Result { + pub(crate) fn invalid_leading_byte(&self, byte: u8, desc: &str) -> Result { Err(Self::invalid_leading_byte_error( byte, desc, @@ -1315,28 +668,19 @@ impl<'a> BinaryReader<'a> { )) } - fn invalid_leading_byte_error(byte: u8, desc: &str, offset: usize) -> BinaryReaderError { + pub(crate) fn invalid_leading_byte_error( + byte: u8, + desc: &str, + offset: usize, + ) -> BinaryReaderError { format_err!(offset, "invalid leading byte (0x{byte:x}) for {desc}") } - fn peek(&self) -> Result { + pub(crate) fn peek(&self) -> Result { self.ensure_has_byte()?; Ok(self.buffer[self.position]) } - fn val_type_from_byte(byte: u8) -> Option { - match byte { - 0x7F => Some(ValType::I32), - 0x7E => Some(ValType::I64), - 0x7D => Some(ValType::F32), - 0x7C => Some(ValType::F64), - 0x7B => Some(ValType::V128), - 0x70 => Some(ValType::FuncRef), - 0x6F => Some(ValType::ExternRef), - _ => None, - } - } - fn read_block_type(&mut self) -> Result { let b = self.peek()?; @@ -1347,29 +691,68 @@ impl<'a> BinaryReader<'a> { } // Check for a block type of form [] -> [t]. - if let Some(ty) = Self::val_type_from_byte(b) { - self.position += 1; - return Ok(BlockType::Type(ty)); + if ValType::is_valtype_byte(b) { + return Ok(BlockType::Type(self.read()?)); } // Not empty or a singular type, so read the function type index let idx = self.read_var_s33()?; - if idx < 0 || idx > (std::u32::MAX as i64) { - return Err(BinaryReaderError::new( - "invalid function type", - self.original_position(), - )); + match u32::try_from(idx) { + Ok(idx) => Ok(BlockType::FuncType(idx)), + Err(_) => { + return Err(BinaryReaderError::new( + "invalid function type", + self.original_position(), + )); + } } - - Ok(BlockType::FuncType(idx as u32)) } - /// Reads the next available `Operator` and calls the respective visit method. + /// Visit the next available operator with the specified [`VisitOperator`] instance. + /// + /// Note that this does not implicitly propagate any additional information such as instruction + /// offsets. In order to do so, consider storing such data within the visitor before visiting. /// /// # Errors /// - /// If `BinaryReader` has less bytes remaining than required to parse - /// the `Operator`. + /// If `BinaryReader` has less bytes remaining than required to parse the `Operator`. + /// + /// # Examples + /// + /// Store an offset for use in diagnostics or any other purposes: + /// + /// ``` + /// # use wasmparser::{BinaryReader, VisitOperator, Result, for_each_operator}; + /// + /// pub fn dump(mut reader: BinaryReader) -> Result<()> { + /// let mut visitor = Dumper { offset: 0 }; + /// while !reader.eof() { + /// visitor.offset = reader.original_position(); + /// reader.visit_operator(&mut visitor)?; + /// } + /// Ok(()) + /// } + /// + /// struct Dumper { + /// offset: usize + /// } + /// + /// macro_rules! define_visit_operator { + /// ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + /// $( + /// fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { + /// println!("{}: {}", self.offset, stringify!($visit)); + /// } + /// )* + /// } + /// } + /// + /// impl<'a> VisitOperator<'a> for Dumper { + /// type Output = (); + /// for_each_operator!(define_visit_operator); + /// } + /// + /// ``` pub fn visit_operator(&mut self, visitor: &mut T) -> Result<>::Output> where T: VisitOperator<'a>, @@ -1377,35 +760,35 @@ impl<'a> BinaryReader<'a> { let pos = self.original_position(); let code = self.read_u8()? as u8; Ok(match code { - 0x00 => visitor.visit_unreachable(pos), - 0x01 => visitor.visit_nop(pos), - 0x02 => visitor.visit_block(pos, self.read_block_type()?), - 0x03 => visitor.visit_loop(pos, self.read_block_type()?), - 0x04 => visitor.visit_if(pos, self.read_block_type()?), - 0x05 => visitor.visit_else(pos), - 0x06 => visitor.visit_try(pos, self.read_block_type()?), - 0x07 => visitor.visit_catch(pos, self.read_var_u32()?), - 0x08 => visitor.visit_throw(pos, self.read_var_u32()?), - 0x09 => visitor.visit_rethrow(pos, self.read_var_u32()?), - 0x0b => visitor.visit_end(pos), - 0x0c => visitor.visit_br(pos, self.read_var_u32()?), - 0x0d => visitor.visit_br_if(pos, self.read_var_u32()?), - 0x0e => visitor.visit_br_table(pos, self.read_br_table()?), - 0x0f => visitor.visit_return(pos), - 0x10 => visitor.visit_call(pos, self.read_var_u32()?), + 0x00 => visitor.visit_unreachable(), + 0x01 => visitor.visit_nop(), + 0x02 => visitor.visit_block(self.read_block_type()?), + 0x03 => visitor.visit_loop(self.read_block_type()?), + 0x04 => visitor.visit_if(self.read_block_type()?), + 0x05 => visitor.visit_else(), + 0x06 => visitor.visit_try(self.read_block_type()?), + 0x07 => visitor.visit_catch(self.read_var_u32()?), + 0x08 => visitor.visit_throw(self.read_var_u32()?), + 0x09 => visitor.visit_rethrow(self.read_var_u32()?), + 0x0b => visitor.visit_end(), + 0x0c => visitor.visit_br(self.read_var_u32()?), + 0x0d => visitor.visit_br_if(self.read_var_u32()?), + 0x0e => visitor.visit_br_table(self.read_br_table()?), + 0x0f => visitor.visit_return(), + 0x10 => visitor.visit_call(self.read_var_u32()?), 0x11 => { let index = self.read_var_u32()?; let (table_byte, table_index) = self.read_first_byte_and_var_u32()?; - visitor.visit_call_indirect(pos, index, table_index, table_byte) + visitor.visit_call_indirect(index, table_index, table_byte) } - 0x12 => visitor.visit_return_call(pos, self.read_var_u32()?), - 0x13 => { - visitor.visit_return_call_indirect(pos, self.read_var_u32()?, self.read_var_u32()?) - } - 0x18 => visitor.visit_delegate(pos, self.read_var_u32()?), - 0x19 => visitor.visit_catch_all(pos), - 0x1a => visitor.visit_drop(pos), - 0x1b => visitor.visit_select(pos), + 0x12 => visitor.visit_return_call(self.read_var_u32()?), + 0x13 => visitor.visit_return_call_indirect(self.read_var_u32()?, self.read_var_u32()?), + 0x14 => visitor.visit_call_ref(self.read()?), + 0x15 => visitor.visit_return_call_ref(self.read()?), + 0x18 => visitor.visit_delegate(self.read_var_u32()?), + 0x19 => visitor.visit_catch_all(), + 0x1a => visitor.visit_drop(), + 0x1b => visitor.visit_select(), 0x1c => { let results = self.read_var_u32()?; if results != 1 { @@ -1414,188 +797,192 @@ impl<'a> BinaryReader<'a> { self.position, )); } - visitor.visit_typed_select(pos, self.read_val_type()?) + visitor.visit_typed_select(self.read()?) } - 0x20 => visitor.visit_local_get(pos, self.read_var_u32()?), - 0x21 => visitor.visit_local_set(pos, self.read_var_u32()?), - 0x22 => visitor.visit_local_tee(pos, self.read_var_u32()?), - 0x23 => visitor.visit_global_get(pos, self.read_var_u32()?), - 0x24 => visitor.visit_global_set(pos, self.read_var_u32()?), - 0x25 => visitor.visit_table_get(pos, self.read_var_u32()?), - 0x26 => visitor.visit_table_set(pos, self.read_var_u32()?), - - 0x28 => visitor.visit_i32_load(pos, self.read_memarg()?), - 0x29 => visitor.visit_i64_load(pos, self.read_memarg()?), - 0x2a => visitor.visit_f32_load(pos, self.read_memarg()?), - 0x2b => visitor.visit_f64_load(pos, self.read_memarg()?), - 0x2c => visitor.visit_i32_load8_s(pos, self.read_memarg()?), - 0x2d => visitor.visit_i32_load8_u(pos, self.read_memarg()?), - 0x2e => visitor.visit_i32_load16_s(pos, self.read_memarg()?), - 0x2f => visitor.visit_i32_load16_u(pos, self.read_memarg()?), - 0x30 => visitor.visit_i64_load8_s(pos, self.read_memarg()?), - 0x31 => visitor.visit_i64_load8_u(pos, self.read_memarg()?), - 0x32 => visitor.visit_i64_load16_s(pos, self.read_memarg()?), - 0x33 => visitor.visit_i64_load16_u(pos, self.read_memarg()?), - 0x34 => visitor.visit_i64_load32_s(pos, self.read_memarg()?), - 0x35 => visitor.visit_i64_load32_u(pos, self.read_memarg()?), - 0x36 => visitor.visit_i32_store(pos, self.read_memarg()?), - 0x37 => visitor.visit_i64_store(pos, self.read_memarg()?), - 0x38 => visitor.visit_f32_store(pos, self.read_memarg()?), - 0x39 => visitor.visit_f64_store(pos, self.read_memarg()?), - 0x3a => visitor.visit_i32_store8(pos, self.read_memarg()?), - 0x3b => visitor.visit_i32_store16(pos, self.read_memarg()?), - 0x3c => visitor.visit_i64_store8(pos, self.read_memarg()?), - 0x3d => visitor.visit_i64_store16(pos, self.read_memarg()?), - 0x3e => visitor.visit_i64_store32(pos, self.read_memarg()?), + 0x20 => visitor.visit_local_get(self.read_var_u32()?), + 0x21 => visitor.visit_local_set(self.read_var_u32()?), + 0x22 => visitor.visit_local_tee(self.read_var_u32()?), + 0x23 => visitor.visit_global_get(self.read_var_u32()?), + 0x24 => visitor.visit_global_set(self.read_var_u32()?), + 0x25 => visitor.visit_table_get(self.read_var_u32()?), + 0x26 => visitor.visit_table_set(self.read_var_u32()?), + + 0x28 => visitor.visit_i32_load(self.read_memarg(2)?), + 0x29 => visitor.visit_i64_load(self.read_memarg(3)?), + 0x2a => visitor.visit_f32_load(self.read_memarg(2)?), + 0x2b => visitor.visit_f64_load(self.read_memarg(3)?), + 0x2c => visitor.visit_i32_load8_s(self.read_memarg(0)?), + 0x2d => visitor.visit_i32_load8_u(self.read_memarg(0)?), + 0x2e => visitor.visit_i32_load16_s(self.read_memarg(1)?), + 0x2f => visitor.visit_i32_load16_u(self.read_memarg(1)?), + 0x30 => visitor.visit_i64_load8_s(self.read_memarg(0)?), + 0x31 => visitor.visit_i64_load8_u(self.read_memarg(0)?), + 0x32 => visitor.visit_i64_load16_s(self.read_memarg(1)?), + 0x33 => visitor.visit_i64_load16_u(self.read_memarg(1)?), + 0x34 => visitor.visit_i64_load32_s(self.read_memarg(2)?), + 0x35 => visitor.visit_i64_load32_u(self.read_memarg(2)?), + 0x36 => visitor.visit_i32_store(self.read_memarg(2)?), + 0x37 => visitor.visit_i64_store(self.read_memarg(3)?), + 0x38 => visitor.visit_f32_store(self.read_memarg(2)?), + 0x39 => visitor.visit_f64_store(self.read_memarg(3)?), + 0x3a => visitor.visit_i32_store8(self.read_memarg(0)?), + 0x3b => visitor.visit_i32_store16(self.read_memarg(1)?), + 0x3c => visitor.visit_i64_store8(self.read_memarg(0)?), + 0x3d => visitor.visit_i64_store16(self.read_memarg(1)?), + 0x3e => visitor.visit_i64_store32(self.read_memarg(2)?), 0x3f => { let (mem_byte, mem) = self.read_first_byte_and_var_u32()?; - visitor.visit_memory_size(pos, mem, mem_byte) + visitor.visit_memory_size(mem, mem_byte) } 0x40 => { let (mem_byte, mem) = self.read_first_byte_and_var_u32()?; - visitor.visit_memory_grow(pos, mem, mem_byte) + visitor.visit_memory_grow(mem, mem_byte) } - 0x41 => visitor.visit_i32_const(pos, self.read_var_i32()?), - 0x42 => visitor.visit_i64_const(pos, self.read_var_i64()?), - 0x43 => visitor.visit_f32_const(pos, self.read_f32()?), - 0x44 => visitor.visit_f64_const(pos, self.read_f64()?), - - 0x45 => visitor.visit_i32_eqz(pos), - 0x46 => visitor.visit_i32_eq(pos), - 0x47 => visitor.visit_i32_ne(pos), - 0x48 => visitor.visit_i32_lt_s(pos), - 0x49 => visitor.visit_i32_lt_u(pos), - 0x4a => visitor.visit_i32_gt_s(pos), - 0x4b => visitor.visit_i32_gt_u(pos), - 0x4c => visitor.visit_i32_le_s(pos), - 0x4d => visitor.visit_i32_le_u(pos), - 0x4e => visitor.visit_i32_ge_s(pos), - 0x4f => visitor.visit_i32_ge_u(pos), - 0x50 => visitor.visit_i64_eqz(pos), - 0x51 => visitor.visit_i64_eq(pos), - 0x52 => visitor.visit_i64_ne(pos), - 0x53 => visitor.visit_i64_lt_s(pos), - 0x54 => visitor.visit_i64_lt_u(pos), - 0x55 => visitor.visit_i64_gt_s(pos), - 0x56 => visitor.visit_i64_gt_u(pos), - 0x57 => visitor.visit_i64_le_s(pos), - 0x58 => visitor.visit_i64_le_u(pos), - 0x59 => visitor.visit_i64_ge_s(pos), - 0x5a => visitor.visit_i64_ge_u(pos), - 0x5b => visitor.visit_f32_eq(pos), - 0x5c => visitor.visit_f32_ne(pos), - 0x5d => visitor.visit_f32_lt(pos), - 0x5e => visitor.visit_f32_gt(pos), - 0x5f => visitor.visit_f32_le(pos), - 0x60 => visitor.visit_f32_ge(pos), - 0x61 => visitor.visit_f64_eq(pos), - 0x62 => visitor.visit_f64_ne(pos), - 0x63 => visitor.visit_f64_lt(pos), - 0x64 => visitor.visit_f64_gt(pos), - 0x65 => visitor.visit_f64_le(pos), - 0x66 => visitor.visit_f64_ge(pos), - 0x67 => visitor.visit_i32_clz(pos), - 0x68 => visitor.visit_i32_ctz(pos), - 0x69 => visitor.visit_i32_popcnt(pos), - 0x6a => visitor.visit_i32_add(pos), - 0x6b => visitor.visit_i32_sub(pos), - 0x6c => visitor.visit_i32_mul(pos), - 0x6d => visitor.visit_i32_div_s(pos), - 0x6e => visitor.visit_i32_div_u(pos), - 0x6f => visitor.visit_i32_rem_s(pos), - 0x70 => visitor.visit_i32_rem_u(pos), - 0x71 => visitor.visit_i32_and(pos), - 0x72 => visitor.visit_i32_or(pos), - 0x73 => visitor.visit_i32_xor(pos), - 0x74 => visitor.visit_i32_shl(pos), - 0x75 => visitor.visit_i32_shr_s(pos), - 0x76 => visitor.visit_i32_shr_u(pos), - 0x77 => visitor.visit_i32_rotl(pos), - 0x78 => visitor.visit_i32_rotr(pos), - 0x79 => visitor.visit_i64_clz(pos), - 0x7a => visitor.visit_i64_ctz(pos), - 0x7b => visitor.visit_i64_popcnt(pos), - 0x7c => visitor.visit_i64_add(pos), - 0x7d => visitor.visit_i64_sub(pos), - 0x7e => visitor.visit_i64_mul(pos), - 0x7f => visitor.visit_i64_div_s(pos), - 0x80 => visitor.visit_i64_div_u(pos), - 0x81 => visitor.visit_i64_rem_s(pos), - 0x82 => visitor.visit_i64_rem_u(pos), - 0x83 => visitor.visit_i64_and(pos), - 0x84 => visitor.visit_i64_or(pos), - 0x85 => visitor.visit_i64_xor(pos), - 0x86 => visitor.visit_i64_shl(pos), - 0x87 => visitor.visit_i64_shr_s(pos), - 0x88 => visitor.visit_i64_shr_u(pos), - 0x89 => visitor.visit_i64_rotl(pos), - 0x8a => visitor.visit_i64_rotr(pos), - 0x8b => visitor.visit_f32_abs(pos), - 0x8c => visitor.visit_f32_neg(pos), - 0x8d => visitor.visit_f32_ceil(pos), - 0x8e => visitor.visit_f32_floor(pos), - 0x8f => visitor.visit_f32_trunc(pos), - 0x90 => visitor.visit_f32_nearest(pos), - 0x91 => visitor.visit_f32_sqrt(pos), - 0x92 => visitor.visit_f32_add(pos), - 0x93 => visitor.visit_f32_sub(pos), - 0x94 => visitor.visit_f32_mul(pos), - 0x95 => visitor.visit_f32_div(pos), - 0x96 => visitor.visit_f32_min(pos), - 0x97 => visitor.visit_f32_max(pos), - 0x98 => visitor.visit_f32_copysign(pos), - 0x99 => visitor.visit_f64_abs(pos), - 0x9a => visitor.visit_f64_neg(pos), - 0x9b => visitor.visit_f64_ceil(pos), - 0x9c => visitor.visit_f64_floor(pos), - 0x9d => visitor.visit_f64_trunc(pos), - 0x9e => visitor.visit_f64_nearest(pos), - 0x9f => visitor.visit_f64_sqrt(pos), - 0xa0 => visitor.visit_f64_add(pos), - 0xa1 => visitor.visit_f64_sub(pos), - 0xa2 => visitor.visit_f64_mul(pos), - 0xa3 => visitor.visit_f64_div(pos), - 0xa4 => visitor.visit_f64_min(pos), - 0xa5 => visitor.visit_f64_max(pos), - 0xa6 => visitor.visit_f64_copysign(pos), - 0xa7 => visitor.visit_i32_wrap_i64(pos), - 0xa8 => visitor.visit_i32_trunc_f32_s(pos), - 0xa9 => visitor.visit_i32_trunc_f32_u(pos), - 0xaa => visitor.visit_i32_trunc_f64_s(pos), - 0xab => visitor.visit_i32_trunc_f64_u(pos), - 0xac => visitor.visit_i64_extend_i32_s(pos), - 0xad => visitor.visit_i64_extend_i32_u(pos), - 0xae => visitor.visit_i64_trunc_f32_s(pos), - 0xaf => visitor.visit_i64_trunc_f32_u(pos), - 0xb0 => visitor.visit_i64_trunc_f64_s(pos), - 0xb1 => visitor.visit_i64_trunc_f64_u(pos), - 0xb2 => visitor.visit_f32_convert_i32_s(pos), - 0xb3 => visitor.visit_f32_convert_i32_u(pos), - 0xb4 => visitor.visit_f32_convert_i64_s(pos), - 0xb5 => visitor.visit_f32_convert_i64_u(pos), - 0xb6 => visitor.visit_f32_demote_f64(pos), - 0xb7 => visitor.visit_f64_convert_i32_s(pos), - 0xb8 => visitor.visit_f64_convert_i32_u(pos), - 0xb9 => visitor.visit_f64_convert_i64_s(pos), - 0xba => visitor.visit_f64_convert_i64_u(pos), - 0xbb => visitor.visit_f64_promote_f32(pos), - 0xbc => visitor.visit_i32_reinterpret_f32(pos), - 0xbd => visitor.visit_i64_reinterpret_f64(pos), - 0xbe => visitor.visit_f32_reinterpret_i32(pos), - 0xbf => visitor.visit_f64_reinterpret_i64(pos), - - 0xc0 => visitor.visit_i32_extend8_s(pos), - 0xc1 => visitor.visit_i32_extend16_s(pos), - 0xc2 => visitor.visit_i64_extend8_s(pos), - 0xc3 => visitor.visit_i64_extend16_s(pos), - 0xc4 => visitor.visit_i64_extend32_s(pos), - - 0xd0 => visitor.visit_ref_null(pos, self.read_val_type()?), - 0xd1 => visitor.visit_ref_is_null(pos), - 0xd2 => visitor.visit_ref_func(pos, self.read_var_u32()?), - + 0x41 => visitor.visit_i32_const(self.read_var_i32()?), + 0x42 => visitor.visit_i64_const(self.read_var_i64()?), + 0x43 => visitor.visit_f32_const(self.read_f32()?), + 0x44 => visitor.visit_f64_const(self.read_f64()?), + + 0x45 => visitor.visit_i32_eqz(), + 0x46 => visitor.visit_i32_eq(), + 0x47 => visitor.visit_i32_ne(), + 0x48 => visitor.visit_i32_lt_s(), + 0x49 => visitor.visit_i32_lt_u(), + 0x4a => visitor.visit_i32_gt_s(), + 0x4b => visitor.visit_i32_gt_u(), + 0x4c => visitor.visit_i32_le_s(), + 0x4d => visitor.visit_i32_le_u(), + 0x4e => visitor.visit_i32_ge_s(), + 0x4f => visitor.visit_i32_ge_u(), + 0x50 => visitor.visit_i64_eqz(), + 0x51 => visitor.visit_i64_eq(), + 0x52 => visitor.visit_i64_ne(), + 0x53 => visitor.visit_i64_lt_s(), + 0x54 => visitor.visit_i64_lt_u(), + 0x55 => visitor.visit_i64_gt_s(), + 0x56 => visitor.visit_i64_gt_u(), + 0x57 => visitor.visit_i64_le_s(), + 0x58 => visitor.visit_i64_le_u(), + 0x59 => visitor.visit_i64_ge_s(), + 0x5a => visitor.visit_i64_ge_u(), + 0x5b => visitor.visit_f32_eq(), + 0x5c => visitor.visit_f32_ne(), + 0x5d => visitor.visit_f32_lt(), + 0x5e => visitor.visit_f32_gt(), + 0x5f => visitor.visit_f32_le(), + 0x60 => visitor.visit_f32_ge(), + 0x61 => visitor.visit_f64_eq(), + 0x62 => visitor.visit_f64_ne(), + 0x63 => visitor.visit_f64_lt(), + 0x64 => visitor.visit_f64_gt(), + 0x65 => visitor.visit_f64_le(), + 0x66 => visitor.visit_f64_ge(), + 0x67 => visitor.visit_i32_clz(), + 0x68 => visitor.visit_i32_ctz(), + 0x69 => visitor.visit_i32_popcnt(), + 0x6a => visitor.visit_i32_add(), + 0x6b => visitor.visit_i32_sub(), + 0x6c => visitor.visit_i32_mul(), + 0x6d => visitor.visit_i32_div_s(), + 0x6e => visitor.visit_i32_div_u(), + 0x6f => visitor.visit_i32_rem_s(), + 0x70 => visitor.visit_i32_rem_u(), + 0x71 => visitor.visit_i32_and(), + 0x72 => visitor.visit_i32_or(), + 0x73 => visitor.visit_i32_xor(), + 0x74 => visitor.visit_i32_shl(), + 0x75 => visitor.visit_i32_shr_s(), + 0x76 => visitor.visit_i32_shr_u(), + 0x77 => visitor.visit_i32_rotl(), + 0x78 => visitor.visit_i32_rotr(), + 0x79 => visitor.visit_i64_clz(), + 0x7a => visitor.visit_i64_ctz(), + 0x7b => visitor.visit_i64_popcnt(), + 0x7c => visitor.visit_i64_add(), + 0x7d => visitor.visit_i64_sub(), + 0x7e => visitor.visit_i64_mul(), + 0x7f => visitor.visit_i64_div_s(), + 0x80 => visitor.visit_i64_div_u(), + 0x81 => visitor.visit_i64_rem_s(), + 0x82 => visitor.visit_i64_rem_u(), + 0x83 => visitor.visit_i64_and(), + 0x84 => visitor.visit_i64_or(), + 0x85 => visitor.visit_i64_xor(), + 0x86 => visitor.visit_i64_shl(), + 0x87 => visitor.visit_i64_shr_s(), + 0x88 => visitor.visit_i64_shr_u(), + 0x89 => visitor.visit_i64_rotl(), + 0x8a => visitor.visit_i64_rotr(), + 0x8b => visitor.visit_f32_abs(), + 0x8c => visitor.visit_f32_neg(), + 0x8d => visitor.visit_f32_ceil(), + 0x8e => visitor.visit_f32_floor(), + 0x8f => visitor.visit_f32_trunc(), + 0x90 => visitor.visit_f32_nearest(), + 0x91 => visitor.visit_f32_sqrt(), + 0x92 => visitor.visit_f32_add(), + 0x93 => visitor.visit_f32_sub(), + 0x94 => visitor.visit_f32_mul(), + 0x95 => visitor.visit_f32_div(), + 0x96 => visitor.visit_f32_min(), + 0x97 => visitor.visit_f32_max(), + 0x98 => visitor.visit_f32_copysign(), + 0x99 => visitor.visit_f64_abs(), + 0x9a => visitor.visit_f64_neg(), + 0x9b => visitor.visit_f64_ceil(), + 0x9c => visitor.visit_f64_floor(), + 0x9d => visitor.visit_f64_trunc(), + 0x9e => visitor.visit_f64_nearest(), + 0x9f => visitor.visit_f64_sqrt(), + 0xa0 => visitor.visit_f64_add(), + 0xa1 => visitor.visit_f64_sub(), + 0xa2 => visitor.visit_f64_mul(), + 0xa3 => visitor.visit_f64_div(), + 0xa4 => visitor.visit_f64_min(), + 0xa5 => visitor.visit_f64_max(), + 0xa6 => visitor.visit_f64_copysign(), + 0xa7 => visitor.visit_i32_wrap_i64(), + 0xa8 => visitor.visit_i32_trunc_f32_s(), + 0xa9 => visitor.visit_i32_trunc_f32_u(), + 0xaa => visitor.visit_i32_trunc_f64_s(), + 0xab => visitor.visit_i32_trunc_f64_u(), + 0xac => visitor.visit_i64_extend_i32_s(), + 0xad => visitor.visit_i64_extend_i32_u(), + 0xae => visitor.visit_i64_trunc_f32_s(), + 0xaf => visitor.visit_i64_trunc_f32_u(), + 0xb0 => visitor.visit_i64_trunc_f64_s(), + 0xb1 => visitor.visit_i64_trunc_f64_u(), + 0xb2 => visitor.visit_f32_convert_i32_s(), + 0xb3 => visitor.visit_f32_convert_i32_u(), + 0xb4 => visitor.visit_f32_convert_i64_s(), + 0xb5 => visitor.visit_f32_convert_i64_u(), + 0xb6 => visitor.visit_f32_demote_f64(), + 0xb7 => visitor.visit_f64_convert_i32_s(), + 0xb8 => visitor.visit_f64_convert_i32_u(), + 0xb9 => visitor.visit_f64_convert_i64_s(), + 0xba => visitor.visit_f64_convert_i64_u(), + 0xbb => visitor.visit_f64_promote_f32(), + 0xbc => visitor.visit_i32_reinterpret_f32(), + 0xbd => visitor.visit_i64_reinterpret_f64(), + 0xbe => visitor.visit_f32_reinterpret_i32(), + 0xbf => visitor.visit_f64_reinterpret_i64(), + + 0xc0 => visitor.visit_i32_extend8_s(), + 0xc1 => visitor.visit_i32_extend16_s(), + 0xc2 => visitor.visit_i64_extend8_s(), + 0xc3 => visitor.visit_i64_extend16_s(), + 0xc4 => visitor.visit_i64_extend32_s(), + + 0xd0 => visitor.visit_ref_null(self.read()?), + 0xd1 => visitor.visit_ref_is_null(), + 0xd2 => visitor.visit_ref_func(self.read_var_u32()?), + 0xd4 => visitor.visit_ref_as_non_null(), + 0xd5 => visitor.visit_br_on_null(self.read_var_u32()?), + 0xd6 => visitor.visit_br_on_non_null(self.read_var_u32()?), + + 0xfb => self.visit_0xfb_operator(pos, visitor)?, 0xfc => self.visit_0xfc_operator(pos, visitor)?, 0xfd => self.visit_0xfd_operator(pos, visitor)?, 0xfe => self.visit_0xfe_operator(pos, visitor)?, @@ -1604,6 +991,24 @@ impl<'a> BinaryReader<'a> { }) } + fn visit_0xfb_operator( + &mut self, + pos: usize, + visitor: &mut T, + ) -> Result<>::Output> + where + T: VisitOperator<'a>, + { + let code = self.read_var_u32()?; + Ok(match code { + 0x1c => visitor.visit_ref_i31(), + 0x1d => visitor.visit_i31_get_s(), + 0x1e => visitor.visit_i31_get_u(), + + _ => bail!(pos, "unknown 0xfb subopcode: 0x{code:x}"), + }) + } + fn visit_0xfc_operator( &mut self, pos: usize, @@ -1614,60 +1019,65 @@ impl<'a> BinaryReader<'a> { { let code = self.read_var_u32()?; Ok(match code { - 0x00 => visitor.visit_i32_trunc_sat_f32_s(pos), - 0x01 => visitor.visit_i32_trunc_sat_f32_u(pos), - 0x02 => visitor.visit_i32_trunc_sat_f64_s(pos), - 0x03 => visitor.visit_i32_trunc_sat_f64_u(pos), - 0x04 => visitor.visit_i64_trunc_sat_f32_s(pos), - 0x05 => visitor.visit_i64_trunc_sat_f32_u(pos), - 0x06 => visitor.visit_i64_trunc_sat_f64_s(pos), - 0x07 => visitor.visit_i64_trunc_sat_f64_u(pos), + 0x00 => visitor.visit_i32_trunc_sat_f32_s(), + 0x01 => visitor.visit_i32_trunc_sat_f32_u(), + 0x02 => visitor.visit_i32_trunc_sat_f64_s(), + 0x03 => visitor.visit_i32_trunc_sat_f64_u(), + 0x04 => visitor.visit_i64_trunc_sat_f32_s(), + 0x05 => visitor.visit_i64_trunc_sat_f32_u(), + 0x06 => visitor.visit_i64_trunc_sat_f64_s(), + 0x07 => visitor.visit_i64_trunc_sat_f64_u(), 0x08 => { let segment = self.read_var_u32()?; let mem = self.read_var_u32()?; - visitor.visit_memory_init(pos, segment, mem) + visitor.visit_memory_init(segment, mem) } 0x09 => { let segment = self.read_var_u32()?; - visitor.visit_data_drop(pos, segment) + visitor.visit_data_drop(segment) } 0x0a => { let dst = self.read_var_u32()?; let src = self.read_var_u32()?; - visitor.visit_memory_copy(pos, dst, src) + visitor.visit_memory_copy(dst, src) } 0x0b => { let mem = self.read_var_u32()?; - visitor.visit_memory_fill(pos, mem) + visitor.visit_memory_fill(mem) } 0x0c => { let segment = self.read_var_u32()?; let table = self.read_var_u32()?; - visitor.visit_table_init(pos, segment, table) + visitor.visit_table_init(segment, table) } 0x0d => { let segment = self.read_var_u32()?; - visitor.visit_elem_drop(pos, segment) + visitor.visit_elem_drop(segment) } 0x0e => { let dst_table = self.read_var_u32()?; let src_table = self.read_var_u32()?; - visitor.visit_table_copy(pos, dst_table, src_table) + visitor.visit_table_copy(dst_table, src_table) } 0x0f => { let table = self.read_var_u32()?; - visitor.visit_table_grow(pos, table) + visitor.visit_table_grow(table) } 0x10 => { let table = self.read_var_u32()?; - visitor.visit_table_size(pos, table) + visitor.visit_table_size(table) } 0x11 => { let table = self.read_var_u32()?; - visitor.visit_table_fill(pos, table) + visitor.visit_table_fill(table) + } + + 0x12 => { + let mem = self.read_var_u32()?; + visitor.visit_memory_discard(mem) } _ => bail!(pos, "unknown 0xfc subopcode: 0x{code:x}"), @@ -1684,304 +1094,307 @@ impl<'a> BinaryReader<'a> { { let code = self.read_var_u32()?; Ok(match code { - 0x00 => visitor.visit_v128_load(pos, self.read_memarg()?), - 0x01 => visitor.visit_v128_load8x8_s(pos, self.read_memarg_of_align(3)?), - 0x02 => visitor.visit_v128_load8x8_u(pos, self.read_memarg_of_align(3)?), - 0x03 => visitor.visit_v128_load16x4_s(pos, self.read_memarg_of_align(3)?), - 0x04 => visitor.visit_v128_load16x4_u(pos, self.read_memarg_of_align(3)?), - 0x05 => visitor.visit_v128_load32x2_s(pos, self.read_memarg_of_align(3)?), - 0x06 => visitor.visit_v128_load32x2_u(pos, self.read_memarg_of_align(3)?), - 0x07 => visitor.visit_v128_load8_splat(pos, self.read_memarg_of_align(0)?), - 0x08 => visitor.visit_v128_load16_splat(pos, self.read_memarg_of_align(1)?), - 0x09 => visitor.visit_v128_load32_splat(pos, self.read_memarg_of_align(2)?), - 0x0a => visitor.visit_v128_load64_splat(pos, self.read_memarg_of_align(3)?), - - 0x0b => visitor.visit_v128_store(pos, self.read_memarg()?), - 0x0c => visitor.visit_v128_const(pos, self.read_v128()?), + 0x00 => visitor.visit_v128_load(self.read_memarg(4)?), + 0x01 => visitor.visit_v128_load8x8_s(self.read_memarg(3)?), + 0x02 => visitor.visit_v128_load8x8_u(self.read_memarg(3)?), + 0x03 => visitor.visit_v128_load16x4_s(self.read_memarg(3)?), + 0x04 => visitor.visit_v128_load16x4_u(self.read_memarg(3)?), + 0x05 => visitor.visit_v128_load32x2_s(self.read_memarg(3)?), + 0x06 => visitor.visit_v128_load32x2_u(self.read_memarg(3)?), + 0x07 => visitor.visit_v128_load8_splat(self.read_memarg(0)?), + 0x08 => visitor.visit_v128_load16_splat(self.read_memarg(1)?), + 0x09 => visitor.visit_v128_load32_splat(self.read_memarg(2)?), + 0x0a => visitor.visit_v128_load64_splat(self.read_memarg(3)?), + + 0x0b => visitor.visit_v128_store(self.read_memarg(4)?), + 0x0c => visitor.visit_v128_const(self.read_v128()?), 0x0d => { let mut lanes: [u8; 16] = [0; 16]; for lane in &mut lanes { *lane = self.read_lane_index(32)? } - visitor.visit_i8x16_shuffle(pos, lanes) + visitor.visit_i8x16_shuffle(lanes) } - 0x0e => visitor.visit_i8x16_swizzle(pos), - 0x0f => visitor.visit_i8x16_splat(pos), - 0x10 => visitor.visit_i16x8_splat(pos), - 0x11 => visitor.visit_i32x4_splat(pos), - 0x12 => visitor.visit_i64x2_splat(pos), - 0x13 => visitor.visit_f32x4_splat(pos), - 0x14 => visitor.visit_f64x2_splat(pos), - - 0x15 => visitor.visit_i8x16_extract_lane_s(pos, self.read_lane_index(16)?), - 0x16 => visitor.visit_i8x16_extract_lane_u(pos, self.read_lane_index(16)?), - 0x17 => visitor.visit_i8x16_replace_lane(pos, self.read_lane_index(16)?), - 0x18 => visitor.visit_i16x8_extract_lane_s(pos, self.read_lane_index(8)?), - 0x19 => visitor.visit_i16x8_extract_lane_u(pos, self.read_lane_index(8)?), - 0x1a => visitor.visit_i16x8_replace_lane(pos, self.read_lane_index(8)?), - 0x1b => visitor.visit_i32x4_extract_lane(pos, self.read_lane_index(4)?), - - 0x1c => visitor.visit_i32x4_replace_lane(pos, self.read_lane_index(4)?), - 0x1d => visitor.visit_i64x2_extract_lane(pos, self.read_lane_index(2)?), - 0x1e => visitor.visit_i64x2_replace_lane(pos, self.read_lane_index(2)?), - 0x1f => visitor.visit_f32x4_extract_lane(pos, self.read_lane_index(4)?), - 0x20 => visitor.visit_f32x4_replace_lane(pos, self.read_lane_index(4)?), - 0x21 => visitor.visit_f64x2_extract_lane(pos, self.read_lane_index(2)?), - 0x22 => visitor.visit_f64x2_replace_lane(pos, self.read_lane_index(2)?), - - 0x23 => visitor.visit_i8x16_eq(pos), - 0x24 => visitor.visit_i8x16_ne(pos), - 0x25 => visitor.visit_i8x16_lt_s(pos), - 0x26 => visitor.visit_i8x16_lt_u(pos), - 0x27 => visitor.visit_i8x16_gt_s(pos), - 0x28 => visitor.visit_i8x16_gt_u(pos), - 0x29 => visitor.visit_i8x16_le_s(pos), - 0x2a => visitor.visit_i8x16_le_u(pos), - 0x2b => visitor.visit_i8x16_ge_s(pos), - 0x2c => visitor.visit_i8x16_ge_u(pos), - 0x2d => visitor.visit_i16x8_eq(pos), - 0x2e => visitor.visit_i16x8_ne(pos), - 0x2f => visitor.visit_i16x8_lt_s(pos), - 0x30 => visitor.visit_i16x8_lt_u(pos), - 0x31 => visitor.visit_i16x8_gt_s(pos), - 0x32 => visitor.visit_i16x8_gt_u(pos), - 0x33 => visitor.visit_i16x8_le_s(pos), - 0x34 => visitor.visit_i16x8_le_u(pos), - 0x35 => visitor.visit_i16x8_ge_s(pos), - 0x36 => visitor.visit_i16x8_ge_u(pos), - 0x37 => visitor.visit_i32x4_eq(pos), - 0x38 => visitor.visit_i32x4_ne(pos), - 0x39 => visitor.visit_i32x4_lt_s(pos), - 0x3a => visitor.visit_i32x4_lt_u(pos), - 0x3b => visitor.visit_i32x4_gt_s(pos), - 0x3c => visitor.visit_i32x4_gt_u(pos), - 0x3d => visitor.visit_i32x4_le_s(pos), - 0x3e => visitor.visit_i32x4_le_u(pos), - 0x3f => visitor.visit_i32x4_ge_s(pos), - 0x40 => visitor.visit_i32x4_ge_u(pos), - 0x41 => visitor.visit_f32x4_eq(pos), - 0x42 => visitor.visit_f32x4_ne(pos), - 0x43 => visitor.visit_f32x4_lt(pos), - 0x44 => visitor.visit_f32x4_gt(pos), - 0x45 => visitor.visit_f32x4_le(pos), - 0x46 => visitor.visit_f32x4_ge(pos), - 0x47 => visitor.visit_f64x2_eq(pos), - 0x48 => visitor.visit_f64x2_ne(pos), - 0x49 => visitor.visit_f64x2_lt(pos), - 0x4a => visitor.visit_f64x2_gt(pos), - 0x4b => visitor.visit_f64x2_le(pos), - 0x4c => visitor.visit_f64x2_ge(pos), - 0x4d => visitor.visit_v128_not(pos), - 0x4e => visitor.visit_v128_and(pos), - 0x4f => visitor.visit_v128_andnot(pos), - 0x50 => visitor.visit_v128_or(pos), - 0x51 => visitor.visit_v128_xor(pos), - 0x52 => visitor.visit_v128_bitselect(pos), - 0x53 => visitor.visit_v128_any_true(pos), + 0x0e => visitor.visit_i8x16_swizzle(), + 0x0f => visitor.visit_i8x16_splat(), + 0x10 => visitor.visit_i16x8_splat(), + 0x11 => visitor.visit_i32x4_splat(), + 0x12 => visitor.visit_i64x2_splat(), + 0x13 => visitor.visit_f32x4_splat(), + 0x14 => visitor.visit_f64x2_splat(), + + 0x15 => visitor.visit_i8x16_extract_lane_s(self.read_lane_index(16)?), + 0x16 => visitor.visit_i8x16_extract_lane_u(self.read_lane_index(16)?), + 0x17 => visitor.visit_i8x16_replace_lane(self.read_lane_index(16)?), + 0x18 => visitor.visit_i16x8_extract_lane_s(self.read_lane_index(8)?), + 0x19 => visitor.visit_i16x8_extract_lane_u(self.read_lane_index(8)?), + 0x1a => visitor.visit_i16x8_replace_lane(self.read_lane_index(8)?), + 0x1b => visitor.visit_i32x4_extract_lane(self.read_lane_index(4)?), + + 0x1c => visitor.visit_i32x4_replace_lane(self.read_lane_index(4)?), + 0x1d => visitor.visit_i64x2_extract_lane(self.read_lane_index(2)?), + 0x1e => visitor.visit_i64x2_replace_lane(self.read_lane_index(2)?), + 0x1f => visitor.visit_f32x4_extract_lane(self.read_lane_index(4)?), + 0x20 => visitor.visit_f32x4_replace_lane(self.read_lane_index(4)?), + 0x21 => visitor.visit_f64x2_extract_lane(self.read_lane_index(2)?), + 0x22 => visitor.visit_f64x2_replace_lane(self.read_lane_index(2)?), + + 0x23 => visitor.visit_i8x16_eq(), + 0x24 => visitor.visit_i8x16_ne(), + 0x25 => visitor.visit_i8x16_lt_s(), + 0x26 => visitor.visit_i8x16_lt_u(), + 0x27 => visitor.visit_i8x16_gt_s(), + 0x28 => visitor.visit_i8x16_gt_u(), + 0x29 => visitor.visit_i8x16_le_s(), + 0x2a => visitor.visit_i8x16_le_u(), + 0x2b => visitor.visit_i8x16_ge_s(), + 0x2c => visitor.visit_i8x16_ge_u(), + 0x2d => visitor.visit_i16x8_eq(), + 0x2e => visitor.visit_i16x8_ne(), + 0x2f => visitor.visit_i16x8_lt_s(), + 0x30 => visitor.visit_i16x8_lt_u(), + 0x31 => visitor.visit_i16x8_gt_s(), + 0x32 => visitor.visit_i16x8_gt_u(), + 0x33 => visitor.visit_i16x8_le_s(), + 0x34 => visitor.visit_i16x8_le_u(), + 0x35 => visitor.visit_i16x8_ge_s(), + 0x36 => visitor.visit_i16x8_ge_u(), + 0x37 => visitor.visit_i32x4_eq(), + 0x38 => visitor.visit_i32x4_ne(), + 0x39 => visitor.visit_i32x4_lt_s(), + 0x3a => visitor.visit_i32x4_lt_u(), + 0x3b => visitor.visit_i32x4_gt_s(), + 0x3c => visitor.visit_i32x4_gt_u(), + 0x3d => visitor.visit_i32x4_le_s(), + 0x3e => visitor.visit_i32x4_le_u(), + 0x3f => visitor.visit_i32x4_ge_s(), + 0x40 => visitor.visit_i32x4_ge_u(), + 0x41 => visitor.visit_f32x4_eq(), + 0x42 => visitor.visit_f32x4_ne(), + 0x43 => visitor.visit_f32x4_lt(), + 0x44 => visitor.visit_f32x4_gt(), + 0x45 => visitor.visit_f32x4_le(), + 0x46 => visitor.visit_f32x4_ge(), + 0x47 => visitor.visit_f64x2_eq(), + 0x48 => visitor.visit_f64x2_ne(), + 0x49 => visitor.visit_f64x2_lt(), + 0x4a => visitor.visit_f64x2_gt(), + 0x4b => visitor.visit_f64x2_le(), + 0x4c => visitor.visit_f64x2_ge(), + 0x4d => visitor.visit_v128_not(), + 0x4e => visitor.visit_v128_and(), + 0x4f => visitor.visit_v128_andnot(), + 0x50 => visitor.visit_v128_or(), + 0x51 => visitor.visit_v128_xor(), + 0x52 => visitor.visit_v128_bitselect(), + 0x53 => visitor.visit_v128_any_true(), 0x54 => { - let memarg = self.read_memarg()?; + let memarg = self.read_memarg(0)?; let lane = self.read_lane_index(16)?; - visitor.visit_v128_load8_lane(pos, memarg, lane) + visitor.visit_v128_load8_lane(memarg, lane) } 0x55 => { - let memarg = self.read_memarg()?; + let memarg = self.read_memarg(1)?; let lane = self.read_lane_index(8)?; - visitor.visit_v128_load16_lane(pos, memarg, lane) + visitor.visit_v128_load16_lane(memarg, lane) } 0x56 => { - let memarg = self.read_memarg()?; + let memarg = self.read_memarg(2)?; let lane = self.read_lane_index(4)?; - visitor.visit_v128_load32_lane(pos, memarg, lane) + visitor.visit_v128_load32_lane(memarg, lane) } 0x57 => { - let memarg = self.read_memarg()?; + let memarg = self.read_memarg(3)?; let lane = self.read_lane_index(2)?; - visitor.visit_v128_load64_lane(pos, memarg, lane) + visitor.visit_v128_load64_lane(memarg, lane) } 0x58 => { - let memarg = self.read_memarg()?; + let memarg = self.read_memarg(0)?; let lane = self.read_lane_index(16)?; - visitor.visit_v128_store8_lane(pos, memarg, lane) + visitor.visit_v128_store8_lane(memarg, lane) } 0x59 => { - let memarg = self.read_memarg()?; + let memarg = self.read_memarg(1)?; let lane = self.read_lane_index(8)?; - visitor.visit_v128_store16_lane(pos, memarg, lane) + visitor.visit_v128_store16_lane(memarg, lane) } 0x5a => { - let memarg = self.read_memarg()?; + let memarg = self.read_memarg(2)?; let lane = self.read_lane_index(4)?; - visitor.visit_v128_store32_lane(pos, memarg, lane) + visitor.visit_v128_store32_lane(memarg, lane) } 0x5b => { - let memarg = self.read_memarg()?; + let memarg = self.read_memarg(3)?; let lane = self.read_lane_index(2)?; - visitor.visit_v128_store64_lane(pos, memarg, lane) + visitor.visit_v128_store64_lane(memarg, lane) } - 0x5c => visitor.visit_v128_load32_zero(pos, self.read_memarg_of_align(2)?), - 0x5d => visitor.visit_v128_load64_zero(pos, self.read_memarg_of_align(3)?), - 0x5e => visitor.visit_f32x4_demote_f64x2_zero(pos), - 0x5f => visitor.visit_f64x2_promote_low_f32x4(pos), - 0x60 => visitor.visit_i8x16_abs(pos), - 0x61 => visitor.visit_i8x16_neg(pos), - 0x62 => visitor.visit_i8x16_popcnt(pos), - 0x63 => visitor.visit_i8x16_all_true(pos), - 0x64 => visitor.visit_i8x16_bitmask(pos), - 0x65 => visitor.visit_i8x16_narrow_i16x8_s(pos), - 0x66 => visitor.visit_i8x16_narrow_i16x8_u(pos), - 0x67 => visitor.visit_f32x4_ceil(pos), - 0x68 => visitor.visit_f32x4_floor(pos), - 0x69 => visitor.visit_f32x4_trunc(pos), - 0x6a => visitor.visit_f32x4_nearest(pos), - 0x6b => visitor.visit_i8x16_shl(pos), - 0x6c => visitor.visit_i8x16_shr_s(pos), - 0x6d => visitor.visit_i8x16_shr_u(pos), - 0x6e => visitor.visit_i8x16_add(pos), - 0x6f => visitor.visit_i8x16_add_sat_s(pos), - 0x70 => visitor.visit_i8x16_add_sat_u(pos), - 0x71 => visitor.visit_i8x16_sub(pos), - 0x72 => visitor.visit_i8x16_sub_sat_s(pos), - 0x73 => visitor.visit_i8x16_sub_sat_u(pos), - 0x74 => visitor.visit_f64x2_ceil(pos), - 0x75 => visitor.visit_f64x2_floor(pos), - 0x76 => visitor.visit_i8x16_min_s(pos), - 0x77 => visitor.visit_i8x16_min_u(pos), - 0x78 => visitor.visit_i8x16_max_s(pos), - 0x79 => visitor.visit_i8x16_max_u(pos), - 0x7a => visitor.visit_f64x2_trunc(pos), - 0x7b => visitor.visit_i8x16_avgr_u(pos), - 0x7c => visitor.visit_i16x8_extadd_pairwise_i8x16_s(pos), - 0x7d => visitor.visit_i16x8_extadd_pairwise_i8x16_u(pos), - 0x7e => visitor.visit_i32x4_extadd_pairwise_i16x8_s(pos), - 0x7f => visitor.visit_i32x4_extadd_pairwise_i16x8_u(pos), - 0x80 => visitor.visit_i16x8_abs(pos), - 0x81 => visitor.visit_i16x8_neg(pos), - 0x82 => visitor.visit_i16x8_q15mulr_sat_s(pos), - 0x83 => visitor.visit_i16x8_all_true(pos), - 0x84 => visitor.visit_i16x8_bitmask(pos), - 0x85 => visitor.visit_i16x8_narrow_i32x4_s(pos), - 0x86 => visitor.visit_i16x8_narrow_i32x4_u(pos), - 0x87 => visitor.visit_i16x8_extend_low_i8x16_s(pos), - 0x88 => visitor.visit_i16x8_extend_high_i8x16_s(pos), - 0x89 => visitor.visit_i16x8_extend_low_i8x16_u(pos), - 0x8a => visitor.visit_i16x8_extend_high_i8x16_u(pos), - 0x8b => visitor.visit_i16x8_shl(pos), - 0x8c => visitor.visit_i16x8_shr_s(pos), - 0x8d => visitor.visit_i16x8_shr_u(pos), - 0x8e => visitor.visit_i16x8_add(pos), - 0x8f => visitor.visit_i16x8_add_sat_s(pos), - 0x90 => visitor.visit_i16x8_add_sat_u(pos), - 0x91 => visitor.visit_i16x8_sub(pos), - 0x92 => visitor.visit_i16x8_sub_sat_s(pos), - 0x93 => visitor.visit_i16x8_sub_sat_u(pos), - 0x94 => visitor.visit_f64x2_nearest(pos), - 0x95 => visitor.visit_i16x8_mul(pos), - 0x96 => visitor.visit_i16x8_min_s(pos), - 0x97 => visitor.visit_i16x8_min_u(pos), - 0x98 => visitor.visit_i16x8_max_s(pos), - 0x99 => visitor.visit_i16x8_max_u(pos), - 0x9b => visitor.visit_i16x8_avgr_u(pos), - 0x9c => visitor.visit_i16x8_extmul_low_i8x16_s(pos), - 0x9d => visitor.visit_i16x8_extmul_high_i8x16_s(pos), - 0x9e => visitor.visit_i16x8_extmul_low_i8x16_u(pos), - 0x9f => visitor.visit_i16x8_extmul_high_i8x16_u(pos), - 0xa0 => visitor.visit_i32x4_abs(pos), - 0xa2 => visitor.visit_i8x16_relaxed_swizzle(pos), - 0xa1 => visitor.visit_i32x4_neg(pos), - 0xa3 => visitor.visit_i32x4_all_true(pos), - 0xa4 => visitor.visit_i32x4_bitmask(pos), - 0xa5 => visitor.visit_i32x4_relaxed_trunc_sat_f32x4_s(pos), - 0xa6 => visitor.visit_i32x4_relaxed_trunc_sat_f32x4_u(pos), - 0xa7 => visitor.visit_i32x4_extend_low_i16x8_s(pos), - 0xa8 => visitor.visit_i32x4_extend_high_i16x8_s(pos), - 0xa9 => visitor.visit_i32x4_extend_low_i16x8_u(pos), - 0xaa => visitor.visit_i32x4_extend_high_i16x8_u(pos), - 0xab => visitor.visit_i32x4_shl(pos), - 0xac => visitor.visit_i32x4_shr_s(pos), - 0xad => visitor.visit_i32x4_shr_u(pos), - 0xae => visitor.visit_i32x4_add(pos), - 0xaf => visitor.visit_f32x4_fma(pos), - 0xb0 => visitor.visit_f32x4_fms(pos), - 0xb1 => visitor.visit_i32x4_sub(pos), - 0xb2 => visitor.visit_i8x16_laneselect(pos), - 0xb3 => visitor.visit_i16x8_laneselect(pos), - 0xb4 => visitor.visit_f32x4_relaxed_min(pos), - 0xb5 => visitor.visit_i32x4_mul(pos), - 0xb6 => visitor.visit_i32x4_min_s(pos), - 0xb7 => visitor.visit_i32x4_min_u(pos), - 0xb8 => visitor.visit_i32x4_max_s(pos), - 0xb9 => visitor.visit_i32x4_max_u(pos), - 0xba => visitor.visit_i32x4_dot_i16x8_s(pos), - 0xbc => visitor.visit_i32x4_extmul_low_i16x8_s(pos), - 0xbd => visitor.visit_i32x4_extmul_high_i16x8_s(pos), - 0xbe => visitor.visit_i32x4_extmul_low_i16x8_u(pos), - 0xbf => visitor.visit_i32x4_extmul_high_i16x8_u(pos), - 0xc0 => visitor.visit_i64x2_abs(pos), - 0xc1 => visitor.visit_i64x2_neg(pos), - 0xc3 => visitor.visit_i64x2_all_true(pos), - 0xc4 => visitor.visit_i64x2_bitmask(pos), - 0xc5 => visitor.visit_i32x4_relaxed_trunc_sat_f64x2_s_zero(pos), - 0xc6 => visitor.visit_i32x4_relaxed_trunc_sat_f64x2_u_zero(pos), - 0xc7 => visitor.visit_i64x2_extend_low_i32x4_s(pos), - 0xc8 => visitor.visit_i64x2_extend_high_i32x4_s(pos), - 0xc9 => visitor.visit_i64x2_extend_low_i32x4_u(pos), - 0xca => visitor.visit_i64x2_extend_high_i32x4_u(pos), - 0xcb => visitor.visit_i64x2_shl(pos), - 0xcc => visitor.visit_i64x2_shr_s(pos), - 0xcd => visitor.visit_i64x2_shr_u(pos), - 0xce => visitor.visit_i64x2_add(pos), - 0xcf => visitor.visit_f64x2_fma(pos), - 0xd0 => visitor.visit_f64x2_fms(pos), - 0xd1 => visitor.visit_i64x2_sub(pos), - 0xd2 => visitor.visit_i32x4_laneselect(pos), - 0xd3 => visitor.visit_i64x2_laneselect(pos), - 0xd4 => visitor.visit_f64x2_relaxed_min(pos), - 0xd5 => visitor.visit_i64x2_mul(pos), - 0xd6 => visitor.visit_i64x2_eq(pos), - 0xd7 => visitor.visit_i64x2_ne(pos), - 0xd8 => visitor.visit_i64x2_lt_s(pos), - 0xd9 => visitor.visit_i64x2_gt_s(pos), - 0xda => visitor.visit_i64x2_le_s(pos), - 0xdb => visitor.visit_i64x2_ge_s(pos), - 0xdc => visitor.visit_i64x2_extmul_low_i32x4_s(pos), - 0xdd => visitor.visit_i64x2_extmul_high_i32x4_s(pos), - 0xde => visitor.visit_i64x2_extmul_low_i32x4_u(pos), - 0xdf => visitor.visit_i64x2_extmul_high_i32x4_u(pos), - 0xe0 => visitor.visit_f32x4_abs(pos), - 0xe1 => visitor.visit_f32x4_neg(pos), - 0xe2 => visitor.visit_f32x4_relaxed_max(pos), - 0xe3 => visitor.visit_f32x4_sqrt(pos), - 0xe4 => visitor.visit_f32x4_add(pos), - 0xe5 => visitor.visit_f32x4_sub(pos), - 0xe6 => visitor.visit_f32x4_mul(pos), - 0xe7 => visitor.visit_f32x4_div(pos), - 0xe8 => visitor.visit_f32x4_min(pos), - 0xe9 => visitor.visit_f32x4_max(pos), - 0xea => visitor.visit_f32x4_pmin(pos), - 0xeb => visitor.visit_f32x4_pmax(pos), - 0xec => visitor.visit_f64x2_abs(pos), - 0xed => visitor.visit_f64x2_neg(pos), - 0xee => visitor.visit_f64x2_relaxed_max(pos), - 0xef => visitor.visit_f64x2_sqrt(pos), - 0xf0 => visitor.visit_f64x2_add(pos), - 0xf1 => visitor.visit_f64x2_sub(pos), - 0xf2 => visitor.visit_f64x2_mul(pos), - 0xf3 => visitor.visit_f64x2_div(pos), - 0xf4 => visitor.visit_f64x2_min(pos), - 0xf5 => visitor.visit_f64x2_max(pos), - 0xf6 => visitor.visit_f64x2_pmin(pos), - 0xf7 => visitor.visit_f64x2_pmax(pos), - 0xf8 => visitor.visit_i32x4_trunc_sat_f32x4_s(pos), - 0xf9 => visitor.visit_i32x4_trunc_sat_f32x4_u(pos), - 0xfa => visitor.visit_f32x4_convert_i32x4_s(pos), - 0xfb => visitor.visit_f32x4_convert_i32x4_u(pos), - 0xfc => visitor.visit_i32x4_trunc_sat_f64x2_s_zero(pos), - 0xfd => visitor.visit_i32x4_trunc_sat_f64x2_u_zero(pos), - 0xfe => visitor.visit_f64x2_convert_low_i32x4_s(pos), - 0xff => visitor.visit_f64x2_convert_low_i32x4_u(pos), + 0x5c => visitor.visit_v128_load32_zero(self.read_memarg(2)?), + 0x5d => visitor.visit_v128_load64_zero(self.read_memarg(3)?), + 0x5e => visitor.visit_f32x4_demote_f64x2_zero(), + 0x5f => visitor.visit_f64x2_promote_low_f32x4(), + 0x60 => visitor.visit_i8x16_abs(), + 0x61 => visitor.visit_i8x16_neg(), + 0x62 => visitor.visit_i8x16_popcnt(), + 0x63 => visitor.visit_i8x16_all_true(), + 0x64 => visitor.visit_i8x16_bitmask(), + 0x65 => visitor.visit_i8x16_narrow_i16x8_s(), + 0x66 => visitor.visit_i8x16_narrow_i16x8_u(), + 0x67 => visitor.visit_f32x4_ceil(), + 0x68 => visitor.visit_f32x4_floor(), + 0x69 => visitor.visit_f32x4_trunc(), + 0x6a => visitor.visit_f32x4_nearest(), + 0x6b => visitor.visit_i8x16_shl(), + 0x6c => visitor.visit_i8x16_shr_s(), + 0x6d => visitor.visit_i8x16_shr_u(), + 0x6e => visitor.visit_i8x16_add(), + 0x6f => visitor.visit_i8x16_add_sat_s(), + 0x70 => visitor.visit_i8x16_add_sat_u(), + 0x71 => visitor.visit_i8x16_sub(), + 0x72 => visitor.visit_i8x16_sub_sat_s(), + 0x73 => visitor.visit_i8x16_sub_sat_u(), + 0x74 => visitor.visit_f64x2_ceil(), + 0x75 => visitor.visit_f64x2_floor(), + 0x76 => visitor.visit_i8x16_min_s(), + 0x77 => visitor.visit_i8x16_min_u(), + 0x78 => visitor.visit_i8x16_max_s(), + 0x79 => visitor.visit_i8x16_max_u(), + 0x7a => visitor.visit_f64x2_trunc(), + 0x7b => visitor.visit_i8x16_avgr_u(), + 0x7c => visitor.visit_i16x8_extadd_pairwise_i8x16_s(), + 0x7d => visitor.visit_i16x8_extadd_pairwise_i8x16_u(), + 0x7e => visitor.visit_i32x4_extadd_pairwise_i16x8_s(), + 0x7f => visitor.visit_i32x4_extadd_pairwise_i16x8_u(), + 0x80 => visitor.visit_i16x8_abs(), + 0x81 => visitor.visit_i16x8_neg(), + 0x82 => visitor.visit_i16x8_q15mulr_sat_s(), + 0x83 => visitor.visit_i16x8_all_true(), + 0x84 => visitor.visit_i16x8_bitmask(), + 0x85 => visitor.visit_i16x8_narrow_i32x4_s(), + 0x86 => visitor.visit_i16x8_narrow_i32x4_u(), + 0x87 => visitor.visit_i16x8_extend_low_i8x16_s(), + 0x88 => visitor.visit_i16x8_extend_high_i8x16_s(), + 0x89 => visitor.visit_i16x8_extend_low_i8x16_u(), + 0x8a => visitor.visit_i16x8_extend_high_i8x16_u(), + 0x8b => visitor.visit_i16x8_shl(), + 0x8c => visitor.visit_i16x8_shr_s(), + 0x8d => visitor.visit_i16x8_shr_u(), + 0x8e => visitor.visit_i16x8_add(), + 0x8f => visitor.visit_i16x8_add_sat_s(), + 0x90 => visitor.visit_i16x8_add_sat_u(), + 0x91 => visitor.visit_i16x8_sub(), + 0x92 => visitor.visit_i16x8_sub_sat_s(), + 0x93 => visitor.visit_i16x8_sub_sat_u(), + 0x94 => visitor.visit_f64x2_nearest(), + 0x95 => visitor.visit_i16x8_mul(), + 0x96 => visitor.visit_i16x8_min_s(), + 0x97 => visitor.visit_i16x8_min_u(), + 0x98 => visitor.visit_i16x8_max_s(), + 0x99 => visitor.visit_i16x8_max_u(), + 0x9b => visitor.visit_i16x8_avgr_u(), + 0x9c => visitor.visit_i16x8_extmul_low_i8x16_s(), + 0x9d => visitor.visit_i16x8_extmul_high_i8x16_s(), + 0x9e => visitor.visit_i16x8_extmul_low_i8x16_u(), + 0x9f => visitor.visit_i16x8_extmul_high_i8x16_u(), + 0xa0 => visitor.visit_i32x4_abs(), + 0xa1 => visitor.visit_i32x4_neg(), + 0xa3 => visitor.visit_i32x4_all_true(), + 0xa4 => visitor.visit_i32x4_bitmask(), + 0xa7 => visitor.visit_i32x4_extend_low_i16x8_s(), + 0xa8 => visitor.visit_i32x4_extend_high_i16x8_s(), + 0xa9 => visitor.visit_i32x4_extend_low_i16x8_u(), + 0xaa => visitor.visit_i32x4_extend_high_i16x8_u(), + 0xab => visitor.visit_i32x4_shl(), + 0xac => visitor.visit_i32x4_shr_s(), + 0xad => visitor.visit_i32x4_shr_u(), + 0xae => visitor.visit_i32x4_add(), + 0xb1 => visitor.visit_i32x4_sub(), + 0xb5 => visitor.visit_i32x4_mul(), + 0xb6 => visitor.visit_i32x4_min_s(), + 0xb7 => visitor.visit_i32x4_min_u(), + 0xb8 => visitor.visit_i32x4_max_s(), + 0xb9 => visitor.visit_i32x4_max_u(), + 0xba => visitor.visit_i32x4_dot_i16x8_s(), + 0xbc => visitor.visit_i32x4_extmul_low_i16x8_s(), + 0xbd => visitor.visit_i32x4_extmul_high_i16x8_s(), + 0xbe => visitor.visit_i32x4_extmul_low_i16x8_u(), + 0xbf => visitor.visit_i32x4_extmul_high_i16x8_u(), + 0xc0 => visitor.visit_i64x2_abs(), + 0xc1 => visitor.visit_i64x2_neg(), + 0xc3 => visitor.visit_i64x2_all_true(), + 0xc4 => visitor.visit_i64x2_bitmask(), + 0xc7 => visitor.visit_i64x2_extend_low_i32x4_s(), + 0xc8 => visitor.visit_i64x2_extend_high_i32x4_s(), + 0xc9 => visitor.visit_i64x2_extend_low_i32x4_u(), + 0xca => visitor.visit_i64x2_extend_high_i32x4_u(), + 0xcb => visitor.visit_i64x2_shl(), + 0xcc => visitor.visit_i64x2_shr_s(), + 0xcd => visitor.visit_i64x2_shr_u(), + 0xce => visitor.visit_i64x2_add(), + 0xd1 => visitor.visit_i64x2_sub(), + 0xd5 => visitor.visit_i64x2_mul(), + 0xd6 => visitor.visit_i64x2_eq(), + 0xd7 => visitor.visit_i64x2_ne(), + 0xd8 => visitor.visit_i64x2_lt_s(), + 0xd9 => visitor.visit_i64x2_gt_s(), + 0xda => visitor.visit_i64x2_le_s(), + 0xdb => visitor.visit_i64x2_ge_s(), + 0xdc => visitor.visit_i64x2_extmul_low_i32x4_s(), + 0xdd => visitor.visit_i64x2_extmul_high_i32x4_s(), + 0xde => visitor.visit_i64x2_extmul_low_i32x4_u(), + 0xdf => visitor.visit_i64x2_extmul_high_i32x4_u(), + 0xe0 => visitor.visit_f32x4_abs(), + 0xe1 => visitor.visit_f32x4_neg(), + 0xe3 => visitor.visit_f32x4_sqrt(), + 0xe4 => visitor.visit_f32x4_add(), + 0xe5 => visitor.visit_f32x4_sub(), + 0xe6 => visitor.visit_f32x4_mul(), + 0xe7 => visitor.visit_f32x4_div(), + 0xe8 => visitor.visit_f32x4_min(), + 0xe9 => visitor.visit_f32x4_max(), + 0xea => visitor.visit_f32x4_pmin(), + 0xeb => visitor.visit_f32x4_pmax(), + 0xec => visitor.visit_f64x2_abs(), + 0xed => visitor.visit_f64x2_neg(), + 0xef => visitor.visit_f64x2_sqrt(), + 0xf0 => visitor.visit_f64x2_add(), + 0xf1 => visitor.visit_f64x2_sub(), + 0xf2 => visitor.visit_f64x2_mul(), + 0xf3 => visitor.visit_f64x2_div(), + 0xf4 => visitor.visit_f64x2_min(), + 0xf5 => visitor.visit_f64x2_max(), + 0xf6 => visitor.visit_f64x2_pmin(), + 0xf7 => visitor.visit_f64x2_pmax(), + 0xf8 => visitor.visit_i32x4_trunc_sat_f32x4_s(), + 0xf9 => visitor.visit_i32x4_trunc_sat_f32x4_u(), + 0xfa => visitor.visit_f32x4_convert_i32x4_s(), + 0xfb => visitor.visit_f32x4_convert_i32x4_u(), + 0xfc => visitor.visit_i32x4_trunc_sat_f64x2_s_zero(), + 0xfd => visitor.visit_i32x4_trunc_sat_f64x2_u_zero(), + 0xfe => visitor.visit_f64x2_convert_low_i32x4_s(), + 0xff => visitor.visit_f64x2_convert_low_i32x4_u(), + 0x100 => visitor.visit_i8x16_relaxed_swizzle(), + 0x101 => visitor.visit_i32x4_relaxed_trunc_f32x4_s(), + 0x102 => visitor.visit_i32x4_relaxed_trunc_f32x4_u(), + 0x103 => visitor.visit_i32x4_relaxed_trunc_f64x2_s_zero(), + 0x104 => visitor.visit_i32x4_relaxed_trunc_f64x2_u_zero(), + 0x105 => visitor.visit_f32x4_relaxed_madd(), + 0x106 => visitor.visit_f32x4_relaxed_nmadd(), + 0x107 => visitor.visit_f64x2_relaxed_madd(), + 0x108 => visitor.visit_f64x2_relaxed_nmadd(), + 0x109 => visitor.visit_i8x16_relaxed_laneselect(), + 0x10a => visitor.visit_i16x8_relaxed_laneselect(), + 0x10b => visitor.visit_i32x4_relaxed_laneselect(), + 0x10c => visitor.visit_i64x2_relaxed_laneselect(), + 0x10d => visitor.visit_f32x4_relaxed_min(), + 0x10e => visitor.visit_f32x4_relaxed_max(), + 0x10f => visitor.visit_f64x2_relaxed_min(), + 0x110 => visitor.visit_f64x2_relaxed_max(), + 0x111 => visitor.visit_i16x8_relaxed_q15mulr_s(), + 0x112 => visitor.visit_i16x8_relaxed_dot_i8x16_i7x16_s(), + 0x113 => visitor.visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(), _ => bail!(pos, "unknown 0xfd subopcode: 0x{code:x}"), }) @@ -1997,73 +1410,78 @@ impl<'a> BinaryReader<'a> { { let code = self.read_var_u32()?; Ok(match code { - 0x00 => visitor.visit_memory_atomic_notify(pos, self.read_memarg_of_align(2)?), - 0x01 => visitor.visit_memory_atomic_wait32(pos, self.read_memarg_of_align(2)?), - 0x02 => visitor.visit_memory_atomic_wait64(pos, self.read_memarg_of_align(3)?), - 0x03 => visitor.visit_atomic_fence(pos, self.read_u8()? as u8), - 0x10 => visitor.visit_i32_atomic_load(pos, self.read_memarg_of_align(2)?), - 0x11 => visitor.visit_i64_atomic_load(pos, self.read_memarg_of_align(3)?), - 0x12 => visitor.visit_i32_atomic_load8_u(pos, self.read_memarg_of_align(0)?), - 0x13 => visitor.visit_i32_atomic_load16_u(pos, self.read_memarg_of_align(1)?), - 0x14 => visitor.visit_i64_atomic_load8_u(pos, self.read_memarg_of_align(0)?), - 0x15 => visitor.visit_i64_atomic_load16_u(pos, self.read_memarg_of_align(1)?), - 0x16 => visitor.visit_i64_atomic_load32_u(pos, self.read_memarg_of_align(2)?), - 0x17 => visitor.visit_i32_atomic_store(pos, self.read_memarg_of_align(2)?), - 0x18 => visitor.visit_i64_atomic_store(pos, self.read_memarg_of_align(3)?), - 0x19 => visitor.visit_i32_atomic_store8(pos, self.read_memarg_of_align(0)?), - 0x1a => visitor.visit_i32_atomic_store16(pos, self.read_memarg_of_align(1)?), - 0x1b => visitor.visit_i64_atomic_store8(pos, self.read_memarg_of_align(0)?), - 0x1c => visitor.visit_i64_atomic_store16(pos, self.read_memarg_of_align(1)?), - 0x1d => visitor.visit_i64_atomic_store32(pos, self.read_memarg_of_align(2)?), - 0x1e => visitor.visit_i32_atomic_rmw_add(pos, self.read_memarg_of_align(2)?), - 0x1f => visitor.visit_i64_atomic_rmw_add(pos, self.read_memarg_of_align(3)?), - 0x20 => visitor.visit_i32_atomic_rmw8_add_u(pos, self.read_memarg_of_align(0)?), - 0x21 => visitor.visit_i32_atomic_rmw16_add_u(pos, self.read_memarg_of_align(1)?), - 0x22 => visitor.visit_i64_atomic_rmw8_add_u(pos, self.read_memarg_of_align(0)?), - 0x23 => visitor.visit_i64_atomic_rmw16_add_u(pos, self.read_memarg_of_align(1)?), - 0x24 => visitor.visit_i64_atomic_rmw32_add_u(pos, self.read_memarg_of_align(2)?), - 0x25 => visitor.visit_i32_atomic_rmw_sub(pos, self.read_memarg_of_align(2)?), - 0x26 => visitor.visit_i64_atomic_rmw_sub(pos, self.read_memarg_of_align(3)?), - 0x27 => visitor.visit_i32_atomic_rmw8_sub_u(pos, self.read_memarg_of_align(0)?), - 0x28 => visitor.visit_i32_atomic_rmw16_sub_u(pos, self.read_memarg_of_align(1)?), - 0x29 => visitor.visit_i64_atomic_rmw8_sub_u(pos, self.read_memarg_of_align(0)?), - 0x2a => visitor.visit_i64_atomic_rmw16_sub_u(pos, self.read_memarg_of_align(1)?), - 0x2b => visitor.visit_i64_atomic_rmw32_sub_u(pos, self.read_memarg_of_align(2)?), - 0x2c => visitor.visit_i32_atomic_rmw_and(pos, self.read_memarg_of_align(2)?), - 0x2d => visitor.visit_i64_atomic_rmw_and(pos, self.read_memarg_of_align(3)?), - 0x2e => visitor.visit_i32_atomic_rmw8_and_u(pos, self.read_memarg_of_align(0)?), - 0x2f => visitor.visit_i32_atomic_rmw16_and_u(pos, self.read_memarg_of_align(1)?), - 0x30 => visitor.visit_i64_atomic_rmw8_and_u(pos, self.read_memarg_of_align(0)?), - 0x31 => visitor.visit_i64_atomic_rmw16_and_u(pos, self.read_memarg_of_align(1)?), - 0x32 => visitor.visit_i64_atomic_rmw32_and_u(pos, self.read_memarg_of_align(2)?), - 0x33 => visitor.visit_i32_atomic_rmw_or(pos, self.read_memarg_of_align(2)?), - 0x34 => visitor.visit_i64_atomic_rmw_or(pos, self.read_memarg_of_align(3)?), - 0x35 => visitor.visit_i32_atomic_rmw8_or_u(pos, self.read_memarg_of_align(0)?), - 0x36 => visitor.visit_i32_atomic_rmw16_or_u(pos, self.read_memarg_of_align(1)?), - 0x37 => visitor.visit_i64_atomic_rmw8_or_u(pos, self.read_memarg_of_align(0)?), - 0x38 => visitor.visit_i64_atomic_rmw16_or_u(pos, self.read_memarg_of_align(1)?), - 0x39 => visitor.visit_i64_atomic_rmw32_or_u(pos, self.read_memarg_of_align(2)?), - 0x3a => visitor.visit_i32_atomic_rmw_xor(pos, self.read_memarg_of_align(2)?), - 0x3b => visitor.visit_i64_atomic_rmw_xor(pos, self.read_memarg_of_align(3)?), - 0x3c => visitor.visit_i32_atomic_rmw8_xor_u(pos, self.read_memarg_of_align(0)?), - 0x3d => visitor.visit_i32_atomic_rmw16_xor_u(pos, self.read_memarg_of_align(1)?), - 0x3e => visitor.visit_i64_atomic_rmw8_xor_u(pos, self.read_memarg_of_align(0)?), - 0x3f => visitor.visit_i64_atomic_rmw16_xor_u(pos, self.read_memarg_of_align(1)?), - 0x40 => visitor.visit_i64_atomic_rmw32_xor_u(pos, self.read_memarg_of_align(2)?), - 0x41 => visitor.visit_i32_atomic_rmw_xchg(pos, self.read_memarg_of_align(2)?), - 0x42 => visitor.visit_i64_atomic_rmw_xchg(pos, self.read_memarg_of_align(3)?), - 0x43 => visitor.visit_i32_atomic_rmw8_xchg_u(pos, self.read_memarg_of_align(0)?), - 0x44 => visitor.visit_i32_atomic_rmw16_xchg_u(pos, self.read_memarg_of_align(1)?), - 0x45 => visitor.visit_i64_atomic_rmw8_xchg_u(pos, self.read_memarg_of_align(0)?), - 0x46 => visitor.visit_i64_atomic_rmw16_xchg_u(pos, self.read_memarg_of_align(1)?), - 0x47 => visitor.visit_i64_atomic_rmw32_xchg_u(pos, self.read_memarg_of_align(2)?), - 0x48 => visitor.visit_i32_atomic_rmw_cmpxchg(pos, self.read_memarg_of_align(2)?), - 0x49 => visitor.visit_i64_atomic_rmw_cmpxchg(pos, self.read_memarg_of_align(3)?), - 0x4a => visitor.visit_i32_atomic_rmw8_cmpxchg_u(pos, self.read_memarg_of_align(0)?), - 0x4b => visitor.visit_i32_atomic_rmw16_cmpxchg_u(pos, self.read_memarg_of_align(1)?), - 0x4c => visitor.visit_i64_atomic_rmw8_cmpxchg_u(pos, self.read_memarg_of_align(0)?), - 0x4d => visitor.visit_i64_atomic_rmw16_cmpxchg_u(pos, self.read_memarg_of_align(1)?), - 0x4e => visitor.visit_i64_atomic_rmw32_cmpxchg_u(pos, self.read_memarg_of_align(2)?), + 0x00 => visitor.visit_memory_atomic_notify(self.read_memarg(2)?), + 0x01 => visitor.visit_memory_atomic_wait32(self.read_memarg(2)?), + 0x02 => visitor.visit_memory_atomic_wait64(self.read_memarg(3)?), + 0x03 => { + if self.read_u8()? != 0 { + bail!(pos, "nonzero byte after `atomic.fence`"); + } + visitor.visit_atomic_fence() + } + 0x10 => visitor.visit_i32_atomic_load(self.read_memarg(2)?), + 0x11 => visitor.visit_i64_atomic_load(self.read_memarg(3)?), + 0x12 => visitor.visit_i32_atomic_load8_u(self.read_memarg(0)?), + 0x13 => visitor.visit_i32_atomic_load16_u(self.read_memarg(1)?), + 0x14 => visitor.visit_i64_atomic_load8_u(self.read_memarg(0)?), + 0x15 => visitor.visit_i64_atomic_load16_u(self.read_memarg(1)?), + 0x16 => visitor.visit_i64_atomic_load32_u(self.read_memarg(2)?), + 0x17 => visitor.visit_i32_atomic_store(self.read_memarg(2)?), + 0x18 => visitor.visit_i64_atomic_store(self.read_memarg(3)?), + 0x19 => visitor.visit_i32_atomic_store8(self.read_memarg(0)?), + 0x1a => visitor.visit_i32_atomic_store16(self.read_memarg(1)?), + 0x1b => visitor.visit_i64_atomic_store8(self.read_memarg(0)?), + 0x1c => visitor.visit_i64_atomic_store16(self.read_memarg(1)?), + 0x1d => visitor.visit_i64_atomic_store32(self.read_memarg(2)?), + 0x1e => visitor.visit_i32_atomic_rmw_add(self.read_memarg(2)?), + 0x1f => visitor.visit_i64_atomic_rmw_add(self.read_memarg(3)?), + 0x20 => visitor.visit_i32_atomic_rmw8_add_u(self.read_memarg(0)?), + 0x21 => visitor.visit_i32_atomic_rmw16_add_u(self.read_memarg(1)?), + 0x22 => visitor.visit_i64_atomic_rmw8_add_u(self.read_memarg(0)?), + 0x23 => visitor.visit_i64_atomic_rmw16_add_u(self.read_memarg(1)?), + 0x24 => visitor.visit_i64_atomic_rmw32_add_u(self.read_memarg(2)?), + 0x25 => visitor.visit_i32_atomic_rmw_sub(self.read_memarg(2)?), + 0x26 => visitor.visit_i64_atomic_rmw_sub(self.read_memarg(3)?), + 0x27 => visitor.visit_i32_atomic_rmw8_sub_u(self.read_memarg(0)?), + 0x28 => visitor.visit_i32_atomic_rmw16_sub_u(self.read_memarg(1)?), + 0x29 => visitor.visit_i64_atomic_rmw8_sub_u(self.read_memarg(0)?), + 0x2a => visitor.visit_i64_atomic_rmw16_sub_u(self.read_memarg(1)?), + 0x2b => visitor.visit_i64_atomic_rmw32_sub_u(self.read_memarg(2)?), + 0x2c => visitor.visit_i32_atomic_rmw_and(self.read_memarg(2)?), + 0x2d => visitor.visit_i64_atomic_rmw_and(self.read_memarg(3)?), + 0x2e => visitor.visit_i32_atomic_rmw8_and_u(self.read_memarg(0)?), + 0x2f => visitor.visit_i32_atomic_rmw16_and_u(self.read_memarg(1)?), + 0x30 => visitor.visit_i64_atomic_rmw8_and_u(self.read_memarg(0)?), + 0x31 => visitor.visit_i64_atomic_rmw16_and_u(self.read_memarg(1)?), + 0x32 => visitor.visit_i64_atomic_rmw32_and_u(self.read_memarg(2)?), + 0x33 => visitor.visit_i32_atomic_rmw_or(self.read_memarg(2)?), + 0x34 => visitor.visit_i64_atomic_rmw_or(self.read_memarg(3)?), + 0x35 => visitor.visit_i32_atomic_rmw8_or_u(self.read_memarg(0)?), + 0x36 => visitor.visit_i32_atomic_rmw16_or_u(self.read_memarg(1)?), + 0x37 => visitor.visit_i64_atomic_rmw8_or_u(self.read_memarg(0)?), + 0x38 => visitor.visit_i64_atomic_rmw16_or_u(self.read_memarg(1)?), + 0x39 => visitor.visit_i64_atomic_rmw32_or_u(self.read_memarg(2)?), + 0x3a => visitor.visit_i32_atomic_rmw_xor(self.read_memarg(2)?), + 0x3b => visitor.visit_i64_atomic_rmw_xor(self.read_memarg(3)?), + 0x3c => visitor.visit_i32_atomic_rmw8_xor_u(self.read_memarg(0)?), + 0x3d => visitor.visit_i32_atomic_rmw16_xor_u(self.read_memarg(1)?), + 0x3e => visitor.visit_i64_atomic_rmw8_xor_u(self.read_memarg(0)?), + 0x3f => visitor.visit_i64_atomic_rmw16_xor_u(self.read_memarg(1)?), + 0x40 => visitor.visit_i64_atomic_rmw32_xor_u(self.read_memarg(2)?), + 0x41 => visitor.visit_i32_atomic_rmw_xchg(self.read_memarg(2)?), + 0x42 => visitor.visit_i64_atomic_rmw_xchg(self.read_memarg(3)?), + 0x43 => visitor.visit_i32_atomic_rmw8_xchg_u(self.read_memarg(0)?), + 0x44 => visitor.visit_i32_atomic_rmw16_xchg_u(self.read_memarg(1)?), + 0x45 => visitor.visit_i64_atomic_rmw8_xchg_u(self.read_memarg(0)?), + 0x46 => visitor.visit_i64_atomic_rmw16_xchg_u(self.read_memarg(1)?), + 0x47 => visitor.visit_i64_atomic_rmw32_xchg_u(self.read_memarg(2)?), + 0x48 => visitor.visit_i32_atomic_rmw_cmpxchg(self.read_memarg(2)?), + 0x49 => visitor.visit_i64_atomic_rmw_cmpxchg(self.read_memarg(3)?), + 0x4a => visitor.visit_i32_atomic_rmw8_cmpxchg_u(self.read_memarg(0)?), + 0x4b => visitor.visit_i32_atomic_rmw16_cmpxchg_u(self.read_memarg(1)?), + 0x4c => visitor.visit_i64_atomic_rmw8_cmpxchg_u(self.read_memarg(0)?), + 0x4d => visitor.visit_i64_atomic_rmw16_cmpxchg_u(self.read_memarg(1)?), + 0x4e => visitor.visit_i64_atomic_rmw32_cmpxchg_u(self.read_memarg(2)?), _ => bail!(pos, "unknown 0xfe subopcode: 0x{code:x}"), }) @@ -2107,61 +1525,6 @@ impl<'a> BinaryReader<'a> { self.read_u32() } - pub(crate) fn read_name_type(&mut self) -> Result { - let code = self.read_u7()?; - match code { - 0 => Ok(NameType::Module), - 1 => Ok(NameType::Function), - 2 => Ok(NameType::Local), - 3 => Ok(NameType::Label), - 4 => Ok(NameType::Type), - 5 => Ok(NameType::Table), - 6 => Ok(NameType::Memory), - 7 => Ok(NameType::Global), - 8 => Ok(NameType::Element), - 9 => Ok(NameType::Data), - _ => Ok(NameType::Unknown(code)), - } - } - - pub(crate) fn read_linking_type(&mut self) -> Result { - let ty = self.read_var_u32()?; - Ok(match ty { - 1 => LinkingType::StackPointer(self.read_var_u32()?), - _ => { - return Err(BinaryReaderError::new( - "invalid linking type", - self.original_position() - 1, - )); - } - }) - } - - pub(crate) fn read_reloc_type(&mut self) -> Result { - let code = self.read_u7()?; - match code { - 0 => Ok(RelocType::FunctionIndexLEB), - 1 => Ok(RelocType::TableIndexSLEB), - 2 => Ok(RelocType::TableIndexI32), - 3 => Ok(RelocType::GlobalAddrLEB), - 4 => Ok(RelocType::GlobalAddrSLEB), - 5 => Ok(RelocType::GlobalAddrI32), - 6 => Ok(RelocType::TypeIndexLEB), - 7 => Ok(RelocType::GlobalIndexLEB), - _ => Err(BinaryReaderError::new( - "invalid reloc type", - self.original_position() - 1, - )), - } - } - - pub(crate) fn read_const_expr(&mut self) -> Result> { - let expr_offset = self.position; - self.skip_const_expr()?; - let data = &self.buffer[expr_offset..self.position]; - Ok(ConstExpr::new(data, self.original_offset + expr_offset)) - } - pub(crate) fn skip_const_expr(&mut self) -> Result<()> { // TODO add skip_operator() method and/or validate ConstExpr operators. loop { @@ -2202,8 +1565,8 @@ impl<'a> BrTable<'a> { /// let buf = [0x0e, 0x02, 0x01, 0x02, 0x00]; /// let mut reader = wasmparser::BinaryReader::new(&buf); /// let op = reader.read_operator().unwrap(); - /// if let wasmparser::Operator::BrTable { table } = op { - /// let targets = table.targets().collect::, _>>().unwrap(); + /// if let wasmparser::Operator::BrTable { targets } = op { + /// let targets = targets.targets().collect::, _>>().unwrap(); /// assert_eq!(targets, [1, 2]); /// } /// ``` @@ -2286,7 +1649,7 @@ impl<'a> OperatorFactory<'a> { macro_rules! define_visit_operator { ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { $( - fn $visit(&mut self, _offset: usize $($(,$arg: $argty)*)?) -> Operator<'a> { + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Operator<'a> { Operator::$op $({ $($arg),* })? } )* @@ -2298,3 +1661,46 @@ impl<'a> VisitOperator<'a> for OperatorFactory<'a> { for_each_operator!(define_visit_operator); } + +/// Iterator returned from [`BinaryReader::read_iter`]. +pub struct BinaryReaderIter<'a, 'me, T: FromReader<'a>> { + remaining: usize, + reader: &'me mut BinaryReader<'a>, + _marker: marker::PhantomData, +} + +impl<'a, T> Iterator for BinaryReaderIter<'a, '_, T> +where + T: FromReader<'a>, +{ + type Item = Result; + + fn next(&mut self) -> Option> { + if self.remaining == 0 { + None + } else { + let ret = self.reader.read::(); + if ret.is_err() { + self.remaining = 0; + } else { + self.remaining -= 1; + } + Some(ret) + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.remaining, Some(self.remaining)) + } +} + +impl<'a, T> Drop for BinaryReaderIter<'a, '_, T> +where + T: FromReader<'a>, +{ + fn drop(&mut self) { + while self.next().is_some() { + // ... + } + } +} diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs index 10a1411fe9..194167230d 100644 --- a/crates/wasmparser/src/lib.rs +++ b/crates/wasmparser/src/lib.rs @@ -22,6 +22,9 @@ //! If you need random access to the entire WebAssembly data-structure, //! this is not the right library for you. You could however, build such //! a data-structure using this library. +//! +//! To get started, create a [`Parser`] using [`Parser::new`] and then follow +//! the examples documented for [`Parser::parse`] or [`Parser::parse_all`]. #![deny(missing_docs)] @@ -41,14 +44,15 @@ /// /// - `@mvp`: Denoting a Wasm operator from the initial Wasm MVP version. /// - `@exceptions`: [Wasm `expection-handling` proposal] -/// - `@tail_calls`: [Wasm `tail-calls` proposal] +/// - `@tail_call`: [Wasm `tail-calls` proposal] /// - `@reference_types`: [Wasm `reference-types` proposal] -/// - `@sign_ext_ops`: [Wasm `sign-extension-ops` proposal] -/// - `@non_trapping_f2i_conversions`: [Wasm `non_trapping_float-to-int-conversions` proposal] +/// - `@sign_extension`: [Wasm `sign-extension-ops` proposal] +/// - `@saturating_float_to_int`: [Wasm `non_trapping_float-to-int-conversions` proposal] /// - `@bulk_memory `:[Wasm `bulk-memory` proposal] /// - `@threads`: [Wasm `threads` proposal] /// - `@simd`: [Wasm `simd` proposal] /// - `@relaxed_simd`: [Wasm `relaxed-simd` proposal] +/// - `@gc`: [Wasm `gc` proposal] /// /// [Wasm `expection-handling` proposal]: /// https://github.com/WebAssembly/exception-handling @@ -77,6 +81,9 @@ /// [Wasm `relaxed-simd` proposal]: /// https://github.com/WebAssembly/relaxed-simd /// +/// [Wasm `gc` proposal]: +/// https://github.com/WebAssembly/gc +/// /// ``` /// macro_rules! define_visit_operator { /// // The outer layer of repetition represents how all operators are @@ -97,7 +104,7 @@ /// // `VisitOperator` trait that this corresponds to. /// ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { /// $( -/// fn $visit(&mut self, _offset: usize $($(,$arg: $argty)*)?) { +/// fn $visit(&mut self $($(,$arg: $argty)*)?) { /// // do nothing for this example /// } /// )* @@ -118,25 +125,25 @@ macro_rules! for_each_operator { $mac! { @mvp Unreachable => visit_unreachable @mvp Nop => visit_nop - @mvp Block { ty: $crate::BlockType } => visit_block - @mvp Loop { ty: $crate::BlockType } => visit_loop - @mvp If { ty: $crate::BlockType } => visit_if + @mvp Block { blockty: $crate::BlockType } => visit_block + @mvp Loop { blockty: $crate::BlockType } => visit_loop + @mvp If { blockty: $crate::BlockType } => visit_if @mvp Else => visit_else - @expections Try { ty: $crate::BlockType } => visit_try - @expections Catch { index: u32 } => visit_catch - @expections Throw { index: u32 } => visit_throw - @expections Rethrow { relative_depth: u32 } => visit_rethrow + @exceptions Try { blockty: $crate::BlockType } => visit_try + @exceptions Catch { tag_index: u32 } => visit_catch + @exceptions Throw { tag_index: u32 } => visit_throw + @exceptions Rethrow { relative_depth: u32 } => visit_rethrow @mvp End => visit_end @mvp Br { relative_depth: u32 } => visit_br @mvp BrIf { relative_depth: u32 } => visit_br_if - @mvp BrTable { table: $crate::BrTable<'a> } => visit_br_table + @mvp BrTable { targets: $crate::BrTable<'a> } => visit_br_table @mvp Return => visit_return @mvp Call { function_index: u32 } => visit_call - @mvp CallIndirect { index: u32, table_index: u32, table_byte: u8 } => visit_call_indirect - @tail_calls ReturnCall { function_index: u32 } => visit_return_call - @tail_calls ReturnCallIndirect { index: u32, table_index: u32 } => visit_return_call_indirect - @expections Delegate { relative_depth: u32 } => visit_delegate - @expections CatchAll => visit_catch_all + @mvp CallIndirect { type_index: u32, table_index: u32, table_byte: u8 } => visit_call_indirect + @tail_call ReturnCall { function_index: u32 } => visit_return_call + @tail_call ReturnCallIndirect { type_index: u32, table_index: u32 } => visit_return_call_indirect + @exceptions Delegate { relative_depth: u32 } => visit_delegate + @exceptions CatchAll => visit_catch_all @mvp Drop => visit_drop @mvp Select => visit_select @reference_types TypedSelect { ty: $crate::ValType } => visit_typed_select @@ -174,7 +181,7 @@ macro_rules! for_each_operator { @mvp I64Const { value: i64 } => visit_i64_const @mvp F32Const { value: $crate::Ieee32 } => visit_f32_const @mvp F64Const { value: $crate::Ieee64 } => visit_f64_const - @reference_types RefNull { ty: $crate::ValType } => visit_ref_null + @reference_types RefNull { hty: $crate::HeapType } => visit_ref_null @reference_types RefIsNull => visit_ref_is_null @reference_types RefFunc { function_index: u32 } => visit_ref_func @mvp I32Eqz => visit_i32_eqz @@ -300,44 +307,63 @@ macro_rules! for_each_operator { @mvp I64ReinterpretF64 => visit_i64_reinterpret_f64 @mvp F32ReinterpretI32 => visit_f32_reinterpret_i32 @mvp F64ReinterpretI64 => visit_f64_reinterpret_i64 - @sign_ext_ops I32Extend8S => visit_i32_extend8_s - @sign_ext_ops I32Extend16S => visit_i32_extend16_s - @sign_ext_ops I64Extend8S => visit_i64_extend8_s - @sign_ext_ops I64Extend16S => visit_i64_extend16_s - @sign_ext_ops I64Extend32S => visit_i64_extend32_s + @sign_extension I32Extend8S => visit_i32_extend8_s + @sign_extension I32Extend16S => visit_i32_extend16_s + @sign_extension I64Extend8S => visit_i64_extend8_s + @sign_extension I64Extend16S => visit_i64_extend16_s + @sign_extension I64Extend32S => visit_i64_extend32_s + + // 0xFB prefixed operators + // Garbage Collection + // http://github.com/WebAssembly/gc + @gc RefI31 => visit_ref_i31 + @gc I31GetS => visit_i31_get_s + @gc I31GetU => visit_i31_get_u // 0xFC operators // Non-trapping Float-to-int Conversions - @non_trapping_f2i_conversions I32TruncSatF32S => visit_i32_trunc_sat_f32_s - @non_trapping_f2i_conversions I32TruncSatF32U => visit_i32_trunc_sat_f32_u - @non_trapping_f2i_conversions I32TruncSatF64S => visit_i32_trunc_sat_f64_s - @non_trapping_f2i_conversions I32TruncSatF64U => visit_i32_trunc_sat_f64_u - @non_trapping_f2i_conversions I64TruncSatF32S => visit_i64_trunc_sat_f32_s - @non_trapping_f2i_conversions I64TruncSatF32U => visit_i64_trunc_sat_f32_u - @non_trapping_f2i_conversions I64TruncSatF64S => visit_i64_trunc_sat_f64_s - @non_trapping_f2i_conversions I64TruncSatF64U => visit_i64_trunc_sat_f64_u + // https://github.com/WebAssembly/nontrapping-float-to-int-conversions + @saturating_float_to_int I32TruncSatF32S => visit_i32_trunc_sat_f32_s + @saturating_float_to_int I32TruncSatF32U => visit_i32_trunc_sat_f32_u + @saturating_float_to_int I32TruncSatF64S => visit_i32_trunc_sat_f64_s + @saturating_float_to_int I32TruncSatF64U => visit_i32_trunc_sat_f64_u + @saturating_float_to_int I64TruncSatF32S => visit_i64_trunc_sat_f32_s + @saturating_float_to_int I64TruncSatF32U => visit_i64_trunc_sat_f32_u + @saturating_float_to_int I64TruncSatF64S => visit_i64_trunc_sat_f64_s + @saturating_float_to_int I64TruncSatF64U => visit_i64_trunc_sat_f64_u - // 0xFC operators - // bulk memory https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md - @bulk_memory MemoryInit { segment: u32, mem: u32 } => visit_memory_init - @bulk_memory DataDrop { segment: u32 } => visit_data_drop - @bulk_memory MemoryCopy { dst: u32, src: u32 } => visit_memory_copy + // 0xFC prefixed operators + // bulk memory operations + // https://github.com/WebAssembly/bulk-memory-operations + @bulk_memory MemoryInit { data_index: u32, mem: u32 } => visit_memory_init + @bulk_memory DataDrop { data_index: u32 } => visit_data_drop + @bulk_memory MemoryCopy { dst_mem: u32, src_mem: u32 } => visit_memory_copy @bulk_memory MemoryFill { mem: u32 } => visit_memory_fill - @bulk_memory TableInit { segment: u32, table: u32 } => visit_table_init - @bulk_memory ElemDrop { segment: u32 } => visit_elem_drop + @bulk_memory TableInit { elem_index: u32, table: u32 } => visit_table_init + @bulk_memory ElemDrop { elem_index: u32 } => visit_elem_drop @bulk_memory TableCopy { dst_table: u32, src_table: u32 } => visit_table_copy - @bulk_memory TableFill { table: u32 } => visit_table_fill - @bulk_memory TableGet { table: u32 } => visit_table_get - @bulk_memory TableSet { table: u32 } => visit_table_set - @bulk_memory TableGrow { table: u32 } => visit_table_grow - @bulk_memory TableSize { table: u32 } => visit_table_size - // 0xFE operators - // https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md + // 0xFC prefixed operators + // reference-types + // https://github.com/WebAssembly/reference-types + @reference_types TableFill { table: u32 } => visit_table_fill + @reference_types TableGet { table: u32 } => visit_table_get + @reference_types TableSet { table: u32 } => visit_table_set + @reference_types TableGrow { table: u32 } => visit_table_grow + @reference_types TableSize { table: u32 } => visit_table_size + + // OxFC prefixed operators + // memory control (experimental) + // https://github.com/WebAssembly/design/issues/1439 + @memory_control MemoryDiscard { mem: u32 } => visit_memory_discard + + // 0xFE prefixed operators + // threads + // https://github.com/WebAssembly/threads @threads MemoryAtomicNotify { memarg: $crate::MemArg } => visit_memory_atomic_notify @threads MemoryAtomicWait32 { memarg: $crate::MemArg } => visit_memory_atomic_wait32 @threads MemoryAtomicWait64 { memarg: $crate::MemArg } => visit_memory_atomic_wait64 - @threads AtomicFence { flags: u8 } => visit_atomic_fence + @threads AtomicFence => visit_atomic_fence @threads I32AtomicLoad { memarg: $crate::MemArg } => visit_i32_atomic_load @threads I64AtomicLoad { memarg: $crate::MemArg } => visit_i64_atomic_load @threads I32AtomicLoad8U { memarg: $crate::MemArg } => visit_i32_atomic_load8_u @@ -403,7 +429,9 @@ macro_rules! for_each_operator { @threads I64AtomicRmw32CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_cmpxchg_u // 0xFD operators - // SIMD https://webassembly.github.io/simd/core/binary/instructions.html + // 128-bit SIMD + // - https://github.com/webassembly/simd + // - https://webassembly.github.io/simd/core/binary/instructions.html @simd V128Load { memarg: $crate::MemArg } => visit_v128_load @simd V128Load8x8S { memarg: $crate::MemArg } => visit_v128_load8x8_s @simd V128Load8x8U { memarg: $crate::MemArg } => visit_v128_load8x8_u @@ -524,7 +552,7 @@ macro_rules! for_each_operator { @simd I8x16MinU => visit_i8x16_min_u @simd I8x16MaxS => visit_i8x16_max_s @simd I8x16MaxU => visit_i8x16_max_u - @simd I8x16RoundingAverageU => visit_i8x16_avgr_u + @simd I8x16AvgrU => visit_i8x16_avgr_u @simd I16x8ExtAddPairwiseI8x16S => visit_i16x8_extadd_pairwise_i8x16_s @simd I16x8ExtAddPairwiseI8x16U => visit_i16x8_extadd_pairwise_i8x16_u @simd I16x8Abs => visit_i16x8_abs @@ -552,7 +580,7 @@ macro_rules! for_each_operator { @simd I16x8MinU => visit_i16x8_min_u @simd I16x8MaxS => visit_i16x8_max_s @simd I16x8MaxU => visit_i16x8_max_u - @simd I16x8RoundingAverageU => visit_i16x8_avgr_u + @simd I16x8AvgrU => visit_i16x8_avgr_u @simd I16x8ExtMulLowI8x16S => visit_i16x8_extmul_low_i8x16_s @simd I16x8ExtMulHighI8x16S => visit_i16x8_extmul_high_i8x16_s @simd I16x8ExtMulLowI8x16U => visit_i16x8_extmul_low_i8x16_u @@ -642,23 +670,34 @@ macro_rules! for_each_operator { @simd F64x2PromoteLowF32x4 => visit_f64x2_promote_low_f32x4 // Relaxed SIMD operators + // https://github.com/WebAssembly/relaxed-simd @relaxed_simd I8x16RelaxedSwizzle => visit_i8x16_relaxed_swizzle - @relaxed_simd I32x4RelaxedTruncSatF32x4S => visit_i32x4_relaxed_trunc_sat_f32x4_s - @relaxed_simd I32x4RelaxedTruncSatF32x4U => visit_i32x4_relaxed_trunc_sat_f32x4_u - @relaxed_simd I32x4RelaxedTruncSatF64x2SZero => visit_i32x4_relaxed_trunc_sat_f64x2_s_zero - @relaxed_simd I32x4RelaxedTruncSatF64x2UZero => visit_i32x4_relaxed_trunc_sat_f64x2_u_zero - @relaxed_simd F32x4Fma => visit_f32x4_fma - @relaxed_simd F32x4Fms => visit_f32x4_fms - @relaxed_simd F64x2Fma => visit_f64x2_fma - @relaxed_simd F64x2Fms => visit_f64x2_fms - @relaxed_simd I8x16LaneSelect => visit_i8x16_laneselect - @relaxed_simd I16x8LaneSelect => visit_i16x8_laneselect - @relaxed_simd I32x4LaneSelect => visit_i32x4_laneselect - @relaxed_simd I64x2LaneSelect => visit_i64x2_laneselect + @relaxed_simd I32x4RelaxedTruncF32x4S => visit_i32x4_relaxed_trunc_f32x4_s + @relaxed_simd I32x4RelaxedTruncF32x4U => visit_i32x4_relaxed_trunc_f32x4_u + @relaxed_simd I32x4RelaxedTruncF64x2SZero => visit_i32x4_relaxed_trunc_f64x2_s_zero + @relaxed_simd I32x4RelaxedTruncF64x2UZero => visit_i32x4_relaxed_trunc_f64x2_u_zero + @relaxed_simd F32x4RelaxedMadd => visit_f32x4_relaxed_madd + @relaxed_simd F32x4RelaxedNmadd => visit_f32x4_relaxed_nmadd + @relaxed_simd F64x2RelaxedMadd => visit_f64x2_relaxed_madd + @relaxed_simd F64x2RelaxedNmadd => visit_f64x2_relaxed_nmadd + @relaxed_simd I8x16RelaxedLaneselect => visit_i8x16_relaxed_laneselect + @relaxed_simd I16x8RelaxedLaneselect => visit_i16x8_relaxed_laneselect + @relaxed_simd I32x4RelaxedLaneselect => visit_i32x4_relaxed_laneselect + @relaxed_simd I64x2RelaxedLaneselect => visit_i64x2_relaxed_laneselect @relaxed_simd F32x4RelaxedMin => visit_f32x4_relaxed_min @relaxed_simd F32x4RelaxedMax => visit_f32x4_relaxed_max @relaxed_simd F64x2RelaxedMin => visit_f64x2_relaxed_min @relaxed_simd F64x2RelaxedMax => visit_f64x2_relaxed_max + @relaxed_simd I16x8RelaxedQ15mulrS => visit_i16x8_relaxed_q15mulr_s + @relaxed_simd I16x8RelaxedDotI8x16I7x16S => visit_i16x8_relaxed_dot_i8x16_i7x16_s + @relaxed_simd I32x4RelaxedDotI8x16I7x16AddS => visit_i32x4_relaxed_dot_i8x16_i7x16_add_s + + // Typed Function references + @function_references CallRef { type_index: u32 } => visit_call_ref + @function_references ReturnCallRef { type_index: u32 } => visit_return_call_ref + @function_references RefAsNonNull => visit_ref_as_non_null + @function_references BrOnNull { relative_depth: u32 } => visit_br_on_null + @function_references BrOnNonNull { relative_depth: u32 } => visit_br_on_non_null } }; } diff --git a/crates/wasmparser/src/limits.rs b/crates/wasmparser/src/limits.rs index a8a3011c05..55acf53e49 100644 --- a/crates/wasmparser/src/limits.rs +++ b/crates/wasmparser/src/limits.rs @@ -16,6 +16,7 @@ // The following limits are imposed by wasmparser on WebAssembly modules. // The limits are agreed upon with other engines for consistency. pub const MAX_WASM_TYPES: usize = 1_000_000; +pub const MAX_WASM_SUPERTYPES: usize = 1; pub const MAX_WASM_FUNCTIONS: usize = 1_000_000; pub const MAX_WASM_EXPORTS: usize = 100_000; pub const MAX_WASM_GLOBALS: usize = 1_000_000; @@ -34,23 +35,23 @@ pub const MAX_WASM_TABLES: usize = 100; pub const MAX_WASM_MEMORIES: usize = 100; pub const MAX_WASM_TAGS: usize = 1_000_000; pub const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE; +pub const MAX_WASM_STRUCT_FIELDS: usize = 10_000; // Component-related limits pub const MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB -pub const MAX_WASM_MODULE_TYPE_DECLS: usize = 1000; -pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 1000; -pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 1000; +pub const MAX_WASM_MODULE_TYPE_DECLS: usize = 100_000; +pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 100_000; +pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 100_000; pub const MAX_WASM_RECORD_FIELDS: usize = 1000; pub const MAX_WASM_VARIANT_CASES: usize = 1000; pub const MAX_WASM_TUPLE_TYPES: usize = 1000; pub const MAX_WASM_FLAG_NAMES: usize = 1000; pub const MAX_WASM_ENUM_CASES: usize = 1000; -pub const MAX_WASM_UNION_TYPES: usize = 1000; -pub const MAX_WASM_INSTANTIATION_EXPORTS: usize = 1000; +pub const MAX_WASM_INSTANTIATION_EXPORTS: usize = 100_000; pub const MAX_WASM_CANONICAL_OPTIONS: usize = 10; -pub const MAX_WASM_INSTANTIATION_ARGS: usize = 1000; +pub const MAX_WASM_INSTANTIATION_ARGS: usize = 100_000; pub const MAX_WASM_START_ARGS: usize = 1000; -pub const MAX_WASM_TYPE_SIZE: usize = 100_000; +pub const MAX_WASM_TYPE_SIZE: u32 = 1_000_000; pub const MAX_WASM_MODULES: usize = 1_000; pub const MAX_WASM_COMPONENTS: usize = 1_000; pub const MAX_WASM_INSTANCES: usize = 1_000; diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index f23e7f894c..0ecfc3b613 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -1,21 +1,32 @@ +use crate::binary_reader::WASM_MAGIC_NUMBER; use crate::CoreTypeSectionReader; use crate::{ - limits::MAX_WASM_MODULE_SIZE, BinaryReader, BinaryReaderError, ComponentAliasSectionReader, - ComponentCanonicalSectionReader, ComponentExportSectionReader, ComponentImportSectionReader, - ComponentInstanceSectionReader, ComponentStartSectionReader, ComponentTypeSectionReader, - CustomSectionReader, DataSectionReader, ElementSectionReader, ExportSectionReader, - FunctionBody, FunctionSectionReader, GlobalSectionReader, ImportSectionReader, - InstanceSectionReader, MemorySectionReader, Result, TableSectionReader, TagSectionReader, - TypeSectionReader, + limits::MAX_WASM_MODULE_SIZE, BinaryReader, BinaryReaderError, ComponentCanonicalSectionReader, + ComponentExportSectionReader, ComponentImportSectionReader, ComponentInstanceSectionReader, + ComponentStartFunction, ComponentTypeSectionReader, CustomSectionReader, DataSectionReader, + ElementSectionReader, ExportSectionReader, FromReader, FunctionBody, FunctionSectionReader, + GlobalSectionReader, ImportSectionReader, InstanceSectionReader, MemorySectionReader, Result, + SectionLimited, TableSectionReader, TagSectionReader, TypeSectionReader, }; use std::convert::TryInto; use std::fmt; use std::iter; use std::ops::Range; -pub(crate) const WASM_EXPERIMENTAL_VERSION: u32 = 0xd; -pub(crate) const WASM_MODULE_VERSION: u32 = 0x1; -pub(crate) const WASM_COMPONENT_VERSION: u32 = 0x0001000a; +pub(crate) const WASM_MODULE_VERSION: u16 = 0x1; + +// Note that this started at `0xa` and we're incrementing up from there. When +// the component model is stabilized this will become 0x1. The changes here are: +// +// * [????-??-??] 0xa - original version +// * [2023-01-05] 0xb - `export` introduces an alias +// * [2023-02-06] 0xc - `export` has an optional type ascribed to it +// * [2023-05-10] 0xd - imports/exports drop URLs, new discriminator byte which +// allows for `(import (interface "...") ...)` syntax. +pub(crate) const WASM_COMPONENT_VERSION: u16 = 0xd; + +const KIND_MODULE: u16 = 0x00; +const KIND_COMPONENT: u16 = 0x01; /// The supported encoding formats for the parser. #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -96,7 +107,7 @@ pub enum Payload<'a> { /// Indicates the header of a WebAssembly module or component. Version { /// The version number found in the header. - num: u32, + num: u16, /// The encoding format being parsed. encoding: Encoding, /// The range of bytes that were parsed to consume the header of the @@ -238,16 +249,20 @@ pub enum Payload<'a> { ComponentInstanceSection(ComponentInstanceSectionReader<'a>), /// A component alias section was received and the provided reader can be /// used to parse the contents of the component alias section. - ComponentAliasSection(ComponentAliasSectionReader<'a>), + ComponentAliasSection(SectionLimited<'a, crate::ComponentAlias<'a>>), /// A component type section was received and the provided reader can be /// used to parse the contents of the component type section. ComponentTypeSection(ComponentTypeSectionReader<'a>), /// A component canonical section was received and the provided reader can be /// used to parse the contents of the component canonical section. ComponentCanonicalSection(ComponentCanonicalSectionReader<'a>), - /// A component start section was received, and the provided reader can be - /// used to parse the contents of the component start section. - ComponentStartSection(ComponentStartSectionReader<'a>), + /// A component start section was received. + ComponentStartSection { + /// The start function description. + start: ComponentStartFunction, + /// The range of bytes that specify the `start` field. + range: Range, + }, /// A component import section was received and the provided reader can be /// used to parse the contents of the component import section. ComponentImportSection(ComponentImportSectionReader<'a>), @@ -281,6 +296,33 @@ pub enum Payload<'a> { End(usize), } +const CUSTOM_SECTION: u8 = 0; +const TYPE_SECTION: u8 = 1; +const IMPORT_SECTION: u8 = 2; +const FUNCTION_SECTION: u8 = 3; +const TABLE_SECTION: u8 = 4; +const MEMORY_SECTION: u8 = 5; +const GLOBAL_SECTION: u8 = 6; +const EXPORT_SECTION: u8 = 7; +const START_SECTION: u8 = 8; +const ELEMENT_SECTION: u8 = 9; +const CODE_SECTION: u8 = 10; +const DATA_SECTION: u8 = 11; +const DATA_COUNT_SECTION: u8 = 12; +const TAG_SECTION: u8 = 13; + +const COMPONENT_MODULE_SECTION: u8 = 1; +const COMPONENT_CORE_INSTANCE_SECTION: u8 = 2; +const COMPONENT_CORE_TYPE_SECTION: u8 = 3; +const COMPONENT_SECTION: u8 = 4; +const COMPONENT_INSTANCE_SECTION: u8 = 5; +const COMPONENT_ALIAS_SECTION: u8 = 6; +const COMPONENT_TYPE_SECTION: u8 = 7; +const COMPONENT_CANONICAL_SECTION: u8 = 8; +const COMPONENT_START_SECTION: u8 = 9; +const COMPONENT_IMPORT_SECTION: u8 = 10; +const COMPONENT_EXPORT_SECTION: u8 = 11; + impl Parser { /// Creates a new parser. /// @@ -296,6 +338,42 @@ impl Parser { } } + /// Tests whether `bytes` looks like a core WebAssembly module. + /// + /// This will inspect the first 8 bytes of `bytes` and return `true` if it + /// starts with the standard core WebAssembly header. + pub fn is_core_wasm(bytes: &[u8]) -> bool { + const HEADER: [u8; 8] = [ + WASM_MAGIC_NUMBER[0], + WASM_MAGIC_NUMBER[1], + WASM_MAGIC_NUMBER[2], + WASM_MAGIC_NUMBER[3], + WASM_MODULE_VERSION.to_le_bytes()[0], + WASM_MODULE_VERSION.to_le_bytes()[1], + KIND_MODULE.to_le_bytes()[0], + KIND_MODULE.to_le_bytes()[1], + ]; + bytes.starts_with(&HEADER) + } + + /// Tests whether `bytes` looks like a WebAssembly component. + /// + /// This will inspect the first 8 bytes of `bytes` and return `true` if it + /// starts with the standard WebAssembly component header. + pub fn is_component(bytes: &[u8]) -> bool { + const HEADER: [u8; 8] = [ + WASM_MAGIC_NUMBER[0], + WASM_MAGIC_NUMBER[1], + WASM_MAGIC_NUMBER[2], + WASM_MAGIC_NUMBER[3], + WASM_COMPONENT_VERSION.to_le_bytes()[0], + WASM_COMPONENT_VERSION.to_le_bytes()[1], + KIND_COMPONENT.to_le_bytes()[0], + KIND_COMPONENT.to_le_bytes()[1], + ]; + bytes.starts_with(&HEADER) + } + /// Attempts to parse a chunk of data. /// /// This method will attempt to parse the next incremental portion of a @@ -346,12 +424,12 @@ impl Parser { /// /// fn parse(mut reader: impl Read) -> Result<()> { /// let mut buf = Vec::new(); - /// let mut parser = Parser::new(0); + /// let mut cur = Parser::new(0); /// let mut eof = false; /// let mut stack = Vec::new(); /// /// loop { - /// let (payload, consumed) = match parser.parse(&buf, eof)? { + /// let (payload, consumed) = match cur.parse(&buf, eof)? { /// Chunk::NeedMoreData(hint) => { /// assert!(!eof); // otherwise an error would be returned /// @@ -398,10 +476,8 @@ impl Parser { /// } /// /// // Sections for WebAssembly components - /// ModuleSection { .. } => { /* ... */ } /// InstanceSection(_) => { /* ... */ } /// CoreTypeSection(_) => { /* ... */ } - /// ComponentSection { .. } => { /* ... */ } /// ComponentInstanceSection(_) => { /* ... */ } /// ComponentAliasSection(_) => { /* ... */ } /// ComponentTypeSection(_) => { /* ... */ } @@ -410,6 +486,12 @@ impl Parser { /// ComponentImportSection(_) => { /* ... */ } /// ComponentExportSection(_) => { /* ... */ } /// + /// ModuleSection { parser, .. } + /// | ComponentSection { parser, .. } => { + /// stack.push(cur.clone()); + /// cur = parser.clone(); + /// } + /// /// CustomSection(_) => { /* ... */ } /// /// // most likely you'd return an error here @@ -420,7 +502,7 @@ impl Parser { /// // we're done. /// End(_) => { /// if let Some(parent_parser) = stack.pop() { - /// parser = parent_parser; + /// cur = parent_parser; /// } else { /// break; /// } @@ -485,17 +567,13 @@ impl Parser { match self.state { State::Header => { let start = reader.original_position(); - let num = reader.read_header_version()?; - self.encoding = match num { - WASM_EXPERIMENTAL_VERSION | WASM_MODULE_VERSION => Encoding::Module, - WASM_COMPONENT_VERSION => Encoding::Component, - _ => { - return Err(BinaryReaderError::new( - "unknown binary version", - reader.original_position() - 4, - )) - } + let header_version = reader.read_header_version()?; + self.encoding = match (header_version >> 16) as u16 { + KIND_MODULE => Encoding::Module, + KIND_COMPONENT => Encoding::Component, + _ => bail!(start + 4, "unknown binary version: {header_version:#10x}"), }; + let num = header_version as u16; self.state = State::SectionStart; Ok(Version { num, @@ -516,7 +594,7 @@ impl Parser { if id & 0x80 != 0 { return Err(BinaryReaderError::new("malformed section id", id_pos)); } - let len_pos = reader.position; + let len_pos = reader.original_position(); let mut len = reader.read_var_u32()?; // Test to make sure that this section actually fits within @@ -533,43 +611,40 @@ impl Parser { return Err(BinaryReaderError::new("section too large", len_pos)); } - // Check for custom sections (supported by all encodings) - if id == 0 {} - match (self.encoding, id) { // Sections for both modules and components. (_, 0) => section(reader, len, CustomSectionReader::new, CustomSection), // Module sections - (Encoding::Module, 1) => { + (Encoding::Module, TYPE_SECTION) => { section(reader, len, TypeSectionReader::new, TypeSection) } - (Encoding::Module, 2) => { + (Encoding::Module, IMPORT_SECTION) => { section(reader, len, ImportSectionReader::new, ImportSection) } - (Encoding::Module, 3) => { + (Encoding::Module, FUNCTION_SECTION) => { section(reader, len, FunctionSectionReader::new, FunctionSection) } - (Encoding::Module, 4) => { + (Encoding::Module, TABLE_SECTION) => { section(reader, len, TableSectionReader::new, TableSection) } - (Encoding::Module, 5) => { + (Encoding::Module, MEMORY_SECTION) => { section(reader, len, MemorySectionReader::new, MemorySection) } - (Encoding::Module, 6) => { + (Encoding::Module, GLOBAL_SECTION) => { section(reader, len, GlobalSectionReader::new, GlobalSection) } - (Encoding::Module, 7) => { + (Encoding::Module, EXPORT_SECTION) => { section(reader, len, ExportSectionReader::new, ExportSection) } - (Encoding::Module, 8) => { - let (func, range) = single_u32(reader, len, "start")?; + (Encoding::Module, START_SECTION) => { + let (func, range) = single_item(reader, len, "start")?; Ok(StartSection { func, range }) } - (Encoding::Module, 9) => { + (Encoding::Module, ELEMENT_SECTION) => { section(reader, len, ElementSectionReader::new, ElementSection) } - (Encoding::Module, 10) => { + (Encoding::Module, CODE_SECTION) => { let start = reader.original_position(); let count = delimited(reader, &mut len, |r| r.read_var_u32())?; let range = start..reader.original_position() + len as usize; @@ -583,20 +658,20 @@ impl Parser { size: len, }) } - (Encoding::Module, 11) => { + (Encoding::Module, DATA_SECTION) => { section(reader, len, DataSectionReader::new, DataSection) } - (Encoding::Module, 12) => { - let (count, range) = single_u32(reader, len, "data count")?; + (Encoding::Module, DATA_COUNT_SECTION) => { + let (count, range) = single_item(reader, len, "data count")?; Ok(DataCountSection { count, range }) } - (Encoding::Module, 13) => { + (Encoding::Module, TAG_SECTION) => { section(reader, len, TagSectionReader::new, TagSection) } // Component sections - (Encoding::Component, 1 /* module */) - | (Encoding::Component, 4 /* component */) => { + (Encoding::Component, COMPONENT_MODULE_SECTION) + | (Encoding::Component, COMPONENT_SECTION) => { if len as usize > MAX_WASM_MODULE_SIZE { bail!( len_pos, @@ -618,50 +693,44 @@ impl Parser { _ => unreachable!(), }) } - (Encoding::Component, 2) => { + (Encoding::Component, COMPONENT_CORE_INSTANCE_SECTION) => { section(reader, len, InstanceSectionReader::new, InstanceSection) } - (Encoding::Component, 3) => { + (Encoding::Component, COMPONENT_CORE_TYPE_SECTION) => { section(reader, len, CoreTypeSectionReader::new, CoreTypeSection) } - // Section 5 handled above - (Encoding::Component, 5) => section( + (Encoding::Component, COMPONENT_INSTANCE_SECTION) => section( reader, len, ComponentInstanceSectionReader::new, ComponentInstanceSection, ), - (Encoding::Component, 6) => section( - reader, - len, - ComponentAliasSectionReader::new, - ComponentAliasSection, - ), - (Encoding::Component, 7) => section( + (Encoding::Component, COMPONENT_ALIAS_SECTION) => { + section(reader, len, SectionLimited::new, ComponentAliasSection) + } + (Encoding::Component, COMPONENT_TYPE_SECTION) => section( reader, len, ComponentTypeSectionReader::new, ComponentTypeSection, ), - (Encoding::Component, 8) => section( + (Encoding::Component, COMPONENT_CANONICAL_SECTION) => section( reader, len, ComponentCanonicalSectionReader::new, ComponentCanonicalSection, ), - (Encoding::Component, 9) => section( - reader, - len, - ComponentStartSectionReader::new, - ComponentStartSection, - ), - (Encoding::Component, 10) => section( + (Encoding::Component, COMPONENT_START_SECTION) => { + let (start, range) = single_item(reader, len, "component start")?; + Ok(ComponentStartSection { start, range }) + } + (Encoding::Component, COMPONENT_IMPORT_SECTION) => section( reader, len, ComponentImportSectionReader::new, ComponentImportSection, ), - (Encoding::Component, 11) => section( + (Encoding::Component, COMPONENT_EXPORT_SECTION) => section( reader, len, ComponentExportSectionReader::new, @@ -739,6 +808,79 @@ impl Parser { /// Note that when this function yields sections that provide parsers, /// no further action is required for those sections as payloads from /// those parsers will be automatically returned. + /// + /// # Examples + /// + /// An example of reading a wasm file from a stream (`std::io::Read`) into + /// a buffer and then parsing it. + /// + /// ``` + /// use std::io::Read; + /// use anyhow::Result; + /// use wasmparser::{Parser, Chunk, Payload::*}; + /// + /// fn parse(mut reader: impl Read) -> Result<()> { + /// let mut buf = Vec::new(); + /// reader.read_to_end(&mut buf)?; + /// let parser = Parser::new(0); + /// + /// for payload in parser.parse_all(&buf) { + /// match payload? { + /// // Sections for WebAssembly modules + /// Version { .. } => { /* ... */ } + /// TypeSection(_) => { /* ... */ } + /// ImportSection(_) => { /* ... */ } + /// FunctionSection(_) => { /* ... */ } + /// TableSection(_) => { /* ... */ } + /// MemorySection(_) => { /* ... */ } + /// TagSection(_) => { /* ... */ } + /// GlobalSection(_) => { /* ... */ } + /// ExportSection(_) => { /* ... */ } + /// StartSection { .. } => { /* ... */ } + /// ElementSection(_) => { /* ... */ } + /// DataCountSection { .. } => { /* ... */ } + /// DataSection(_) => { /* ... */ } + /// + /// // Here we know how many functions we'll be receiving as + /// // `CodeSectionEntry`, so we can prepare for that, and + /// // afterwards we can parse and handle each function + /// // individually. + /// CodeSectionStart { .. } => { /* ... */ } + /// CodeSectionEntry(body) => { + /// // here we can iterate over `body` to parse the function + /// // and its locals + /// } + /// + /// // Sections for WebAssembly components + /// ModuleSection { .. } => { /* ... */ } + /// InstanceSection(_) => { /* ... */ } + /// CoreTypeSection(_) => { /* ... */ } + /// ComponentSection { .. } => { /* ... */ } + /// ComponentInstanceSection(_) => { /* ... */ } + /// ComponentAliasSection(_) => { /* ... */ } + /// ComponentTypeSection(_) => { /* ... */ } + /// ComponentCanonicalSection(_) => { /* ... */ } + /// ComponentStartSection { .. } => { /* ... */ } + /// ComponentImportSection(_) => { /* ... */ } + /// ComponentExportSection(_) => { /* ... */ } + /// + /// CustomSection(_) => { /* ... */ } + /// + /// // most likely you'd return an error here + /// UnknownSection { id, .. } => { /* ... */ } + /// + /// // Once we've reached the end of a parser we either resume + /// // at the parent parser or the payload iterator is at its + /// // end and we're done. + /// End(_) => {} + /// } + /// } + /// + /// Ok(()) + /// } + /// + /// # parse(&b"\0asm\x01\0\0\0"[..]).unwrap(); + /// ``` pub fn parse_all(self, mut data: &[u8]) -> impl Iterator> { let mut stack = Vec::new(); let mut cur = self; @@ -798,7 +940,7 @@ impl Parser { /// # Examples /// /// ``` - /// use wasmparser::{Result, Parser, Chunk, SectionReader, Payload::*}; + /// use wasmparser::{Result, Parser, Chunk, Payload::*}; /// use std::ops::Range; /// /// fn objdump_headers(mut wasm: &[u8]) -> Result<()> { @@ -869,36 +1011,28 @@ fn section<'a, T>( Ok(variant(reader)) } -/// Creates a new `BinaryReader` from the given `reader` which will be reading -/// the first `len` bytes. -/// -/// This means that `len` bytes must be resident in memory at the time of this -/// reading. -fn subreader<'a>(reader: &mut BinaryReader<'a>, len: u32) -> Result> { - let offset = reader.original_position(); - let payload = reader.read_bytes(len as usize)?; - Ok(BinaryReader::new_with_offset(payload, offset)) -} - /// Reads a section that is represented by a single uleb-encoded `u32`. -fn single_u32<'a>( +fn single_item<'a, T>( reader: &mut BinaryReader<'a>, len: u32, desc: &str, -) -> Result<(u32, Range)> { +) -> Result<(T, Range)> +where + T: FromReader<'a>, +{ let range = reader.original_position()..reader.original_position() + len as usize; - let mut content = subreader(reader, len)?; + let mut content = BinaryReader::new_with_offset(reader.read_bytes(len as usize)?, range.start); // We can't recover from "unexpected eof" here because our entire section is // already resident in memory, so clear the hint for how many more bytes are // expected. - let index = content.read_var_u32().map_err(clear_hint)?; + let ret = content.read().map_err(clear_hint)?; if !content.eof() { bail!( content.original_position(), "unexpected content in the {desc} section", ); } - Ok((index, range)) + Ok((ret, range)) } /// Attempts to parse using `f`. @@ -930,6 +1064,62 @@ impl Default for Parser { } } +impl Payload<'_> { + /// If this `Payload` represents a section in the original wasm module then + /// the section's id and range within the original wasm binary are returned. + /// + /// Not all payloads refer to entire sections, such as the `Version` and + /// `CodeSectionEntry` variants. These variants will return `None` from this + /// function. + /// + /// Otherwise this function will return `Some` where the first element is + /// the byte identifier for the section and the second element is the range + /// of the contents of the section within the original wasm binary. + /// + /// The purpose of this method is to enable tools to easily iterate over + /// entire sections if necessary and handle sections uniformly, for example + /// dropping custom sections while preserving all other sections. + pub fn as_section(&self) -> Option<(u8, Range)> { + use Payload::*; + + match self { + Version { .. } => None, + TypeSection(s) => Some((TYPE_SECTION, s.range())), + ImportSection(s) => Some((IMPORT_SECTION, s.range())), + FunctionSection(s) => Some((FUNCTION_SECTION, s.range())), + TableSection(s) => Some((TABLE_SECTION, s.range())), + MemorySection(s) => Some((MEMORY_SECTION, s.range())), + TagSection(s) => Some((TAG_SECTION, s.range())), + GlobalSection(s) => Some((GLOBAL_SECTION, s.range())), + ExportSection(s) => Some((EXPORT_SECTION, s.range())), + ElementSection(s) => Some((ELEMENT_SECTION, s.range())), + DataSection(s) => Some((DATA_SECTION, s.range())), + StartSection { range, .. } => Some((START_SECTION, range.clone())), + DataCountSection { range, .. } => Some((DATA_COUNT_SECTION, range.clone())), + CodeSectionStart { range, .. } => Some((CODE_SECTION, range.clone())), + CodeSectionEntry(_) => None, + + ModuleSection { range, .. } => Some((COMPONENT_MODULE_SECTION, range.clone())), + InstanceSection(s) => Some((COMPONENT_CORE_INSTANCE_SECTION, s.range())), + CoreTypeSection(s) => Some((COMPONENT_CORE_TYPE_SECTION, s.range())), + ComponentSection { range, .. } => Some((COMPONENT_SECTION, range.clone())), + ComponentInstanceSection(s) => Some((COMPONENT_INSTANCE_SECTION, s.range())), + ComponentAliasSection(s) => Some((COMPONENT_ALIAS_SECTION, s.range())), + ComponentTypeSection(s) => Some((COMPONENT_TYPE_SECTION, s.range())), + ComponentCanonicalSection(s) => Some((COMPONENT_CANONICAL_SECTION, s.range())), + ComponentStartSection { range, .. } => Some((COMPONENT_START_SECTION, range.clone())), + ComponentImportSection(s) => Some((COMPONENT_IMPORT_SECTION, s.range())), + ComponentExportSection(s) => Some((COMPONENT_EXPORT_SECTION, s.range())), + + CustomSection(c) => Some((CUSTOM_SECTION, c.range())), + + UnknownSection { id, range, .. } => Some((*id, range.clone())), + + End(_) => None, + } + } +} + impl fmt::Debug for Payload<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use Payload::*; @@ -998,7 +1188,7 @@ impl fmt::Debug for Payload<'_> { .debug_tuple("ComponentCanonicalSection") .field(&"...") .finish(), - ComponentStartSection(_) => f + ComponentStartSection { .. } => f .debug_tuple("ComponentStartSection") .field(&"...") .finish(), @@ -1093,7 +1283,7 @@ mod tests { fn parser_after_component_header() -> Parser { let mut p = Parser::default(); assert_matches!( - p.parse(b"\0asm\x0a\0\x01\0", false), + p.parse(b"\0asm\x0d\0\x01\0", false), Ok(Chunk::Parsed { consumed: 8, payload: Payload::Version { diff --git a/crates/wasmparser/src/readers.rs b/crates/wasmparser/src/readers.rs index 017a80df59..e2b25da7cf 100644 --- a/crates/wasmparser/src/readers.rs +++ b/crates/wasmparser/src/readers.rs @@ -13,7 +13,9 @@ * limitations under the License. */ -use crate::{BinaryReaderError, Result}; +use crate::{BinaryReader, BinaryReaderError, Result}; +use std::fmt; +use std::marker; use std::ops::Range; mod component; @@ -22,156 +24,202 @@ mod core; pub use self::component::*; pub use self::core::*; -/// A trait implemented by section readers. -pub trait SectionReader { - /// The item returned by the reader. - type Item; +/// A trait implemented for items that can be decoded directly from a +/// `BinaryReader`, or that which can be parsed from the WebAssembly binary +/// format. +/// +/// Note that this is also accessible as a [`BinaryReader::read`] method. +pub trait FromReader<'a>: Sized { + /// Attempts to read `Self` from the provided binary reader, returning an + /// error if it is unable to do so. + fn from_reader(reader: &mut BinaryReader<'a>) -> Result; +} - /// Reads an item from the section. - fn read(&mut self) -> Result; +impl<'a> FromReader<'a> for u32 { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + reader.read_var_u32() + } +} - /// Determines if the reader is at end-of-section. - fn eof(&self) -> bool; +impl<'a> FromReader<'a> for &'a str { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + reader.read_string() + } +} - /// Gets the original position of the reader. - fn original_position(&self) -> usize; +impl<'a, T, U> FromReader<'a> for (T, U) +where + T: FromReader<'a>, + U: FromReader<'a>, +{ + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok((reader.read()?, reader.read()?)) + } +} - /// Gets the range of the reader. - fn range(&self) -> Range; +/// A generic structure for reading a section of a WebAssembly binary which has +/// a limited number of items within it. +/// +/// Many WebAssembly sections are a count of items followed by that many items. +/// This helper structure can be used to parse these sections and provides +/// an iteration-based API for reading the contents. +/// +/// Note that this always implements the [`Clone`] trait to represent the +/// ability to parse the section multiple times. +pub struct SectionLimited<'a, T> { + reader: BinaryReader<'a>, + count: u32, + _marker: marker::PhantomData, +} - /// Ensures the reader is at the end of the section. +impl<'a, T> SectionLimited<'a, T> { + /// Creates a new section reader from the provided contents. /// - /// This methods returns an error if there is more data in the section - /// than what is described by the section's header. - fn ensure_end(&self) -> Result<()> { - if self.eof() { - return Ok(()); - } - Err(BinaryReaderError::new( - "section size mismatch: unexpected data at the end of the section", - self.original_position(), - )) + /// The `data` provided here is the data of the section itself that will be + /// parsed. The `offset` argument is the byte offset, in the original wasm + /// binary, that the section was found. The `offset` argument is used + /// for error reporting. + /// + /// # Errors + /// + /// Returns an error if a 32-bit count couldn't be read from the `data`. + pub fn new(data: &'a [u8], offset: usize) -> Result { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(SectionLimited { + reader, + count, + _marker: marker::PhantomData, + }) + } + + /// Returns the count of total items within this section. + pub fn count(&self) -> u32 { + self.count } -} -/// Implemented by sections with a limited number of items. -pub trait SectionWithLimitedItems: SectionReader { - /// Gets the count of the items in the section. - fn get_count(&self) -> u32; + /// Returns whether the original byte offset of this section. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } - /// Returns an iterator over the items within this section where the offset - /// in the original section is provided with the item. - fn into_iter_with_offsets(self) -> IntoIterWithOffsets + /// Returns the range, as byte offsets, of this section within the original + /// wasm binary. + pub fn range(&self) -> Range { + self.reader.range() + } + + /// Returns an iterator which yields not only each item in this section but + /// additionally the offset of each item within the section. + pub fn into_iter_with_offsets(self) -> SectionLimitedIntoIterWithOffsets<'a, T> where - Self: Sized, + T: FromReader<'a>, { - IntoIterWithOffsets { - iter: SectionIteratorLimited::new(self), + SectionLimitedIntoIterWithOffsets { + iter: self.into_iter(), } } } -/// An iterator over items in a section. -pub struct SectionIterator -where - R: SectionReader, -{ - reader: R, - err: bool, +impl Clone for SectionLimited<'_, T> { + fn clone(&self) -> Self { + SectionLimited { + reader: self.reader.clone(), + count: self.count, + _marker: self._marker, + } + } } -impl SectionIterator -where - R: SectionReader, -{ - /// Constructs a new `SectionIterator` for the given section reader. - pub fn new(reader: R) -> SectionIterator { - SectionIterator { reader, err: false } +impl fmt::Debug for SectionLimited<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SectionLimited") + .field("count", &self.count) + .field("range", &self.range()) + .finish() } } -impl Iterator for SectionIterator +impl<'a, T> IntoIterator for SectionLimited<'a, T> where - R: SectionReader, + T: FromReader<'a>, { - type Item = Result; + type Item = Result; + type IntoIter = SectionLimitedIntoIter<'a, T>; - fn next(&mut self) -> Option { - if self.err || self.reader.eof() { - return None; + fn into_iter(self) -> Self::IntoIter { + SectionLimitedIntoIter { + remaining: self.count, + section: self, + end: false, } - let result = self.reader.read(); - self.err = result.is_err(); - Some(result) } } -/// An iterator over a limited section iterator. -pub struct SectionIteratorLimited { - reader: R, - left: u32, +/// A consuming iterator of a [`SectionLimited`]. +/// +/// This is created via the [`IntoIterator`] `impl` for the [`SectionLimited`] +/// type. +pub struct SectionLimitedIntoIter<'a, T> { + section: SectionLimited<'a, T>, + remaining: u32, end: bool, } -impl SectionIteratorLimited -where - R: SectionWithLimitedItems, -{ - /// Constructs a new `SectionIteratorLimited` for the given limited section reader. - pub fn new(reader: R) -> SectionIteratorLimited { - let left = reader.get_count(); - SectionIteratorLimited { - reader, - left, - end: false, - } +impl SectionLimitedIntoIter<'_, T> { + /// Returns the current byte offset of the section within this iterator. + pub fn original_position(&self) -> usize { + self.section.reader.original_position() } } -impl Iterator for SectionIteratorLimited +impl<'a, T> Iterator for SectionLimitedIntoIter<'a, T> where - R: SectionWithLimitedItems, + T: FromReader<'a>, { - type Item = Result; + type Item = Result; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option> { if self.end { return None; } - if self.left == 0 { - return match self.reader.ensure_end() { - Ok(()) => None, - Err(err) => { - self.end = true; - Some(Err(err)) - } - }; + if self.remaining == 0 { + self.end = true; + if self.section.reader.eof() { + return None; + } + return Some(Err(BinaryReaderError::new( + "section size mismatch: unexpected data at the end of the section", + self.section.reader.original_position(), + ))); } - let result = self.reader.read(); + let result = self.section.reader.read(); self.end = result.is_err(); - self.left -= 1; + self.remaining -= 1; Some(result) } fn size_hint(&self) -> (usize, Option) { - let count = self.reader.get_count() as usize; - (count, Some(count)) + let remaining = self.remaining as usize; + (remaining, Some(remaining)) } } +impl<'a, T> ExactSizeIterator for SectionLimitedIntoIter<'a, T> where T: FromReader<'a> {} + /// An iterator over a limited section iterator. -pub struct IntoIterWithOffsets { - iter: SectionIteratorLimited, +pub struct SectionLimitedIntoIterWithOffsets<'a, T> { + iter: SectionLimitedIntoIter<'a, T>, } -impl Iterator for IntoIterWithOffsets +impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T> where - R: SectionWithLimitedItems, + T: FromReader<'a>, { - type Item = Result<(usize, R::Item)>; + type Item = Result<(usize, T)>; fn next(&mut self) -> Option { - let pos = self.iter.reader.original_position(); + let pos = self.iter.section.reader.original_position(); Some(self.iter.next()?.map(|item| (pos, item))) } @@ -179,3 +227,90 @@ where self.iter.size_hint() } } + +impl<'a, T> ExactSizeIterator for SectionLimitedIntoIterWithOffsets<'a, T> where T: FromReader<'a> {} + +/// A trait implemented for subsections of another outer section. +/// +/// This is currently only used for subsections within custom sections, such as +/// the `name` section of core wasm. +/// +/// This is used in conjunction with [`Subsections`]. +pub trait Subsection<'a>: Sized { + /// Converts the section identifier provided with the section contents into + /// a typed section + fn from_reader(id: u8, reader: BinaryReader<'a>) -> Result; +} + +/// Iterator/reader over the contents of a section which is composed of +/// subsections. +/// +/// This reader is used for the core `name` section, for example. This type +/// primarily implements [`Iterator`] for advancing through the sections. +pub struct Subsections<'a, T> { + reader: BinaryReader<'a>, + _marker: marker::PhantomData, +} + +impl<'a, T> Subsections<'a, T> { + /// Creates a new reader for the specified section contents starting at + /// `offset` within the original wasm file. + pub fn new(data: &'a [u8], offset: usize) -> Self { + Subsections { + reader: BinaryReader::new_with_offset(data, offset), + _marker: marker::PhantomData, + } + } + + /// Returns whether the original byte offset of this section. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Returns the range, as byte offsets, of this section within the original + /// wasm binary. + pub fn range(&self) -> Range { + self.reader.range() + } + + fn read(&mut self) -> Result + where + T: Subsection<'a>, + { + let subsection_id = self.reader.read_u7()?; + let reader = self.reader.read_reader("unexpected end of section")?; + T::from_reader(subsection_id, reader) + } +} + +impl Clone for Subsections<'_, T> { + fn clone(&self) -> Self { + Subsections { + reader: self.reader.clone(), + _marker: self._marker, + } + } +} + +impl fmt::Debug for Subsections<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Subsections") + .field("range", &self.range()) + .finish() + } +} + +impl<'a, T> Iterator for Subsections<'a, T> +where + T: Subsection<'a>, +{ + type Item = Result; + + fn next(&mut self) -> Option> { + if self.reader.eof() { + None + } else { + Some(self.read()) + } + } +} diff --git a/crates/wasmparser/src/readers/component.rs b/crates/wasmparser/src/readers/component.rs index 268b264cce..24b490d0c3 100644 --- a/crates/wasmparser/src/readers/component.rs +++ b/crates/wasmparser/src/readers/component.rs @@ -3,6 +3,7 @@ mod canonicals; mod exports; mod imports; mod instances; +mod names; mod start; mod types; @@ -11,5 +12,6 @@ pub use self::canonicals::*; pub use self::exports::*; pub use self::imports::*; pub use self::instances::*; +pub use self::names::*; pub use self::start::*; pub use self::types::*; diff --git a/crates/wasmparser/src/readers/component/aliases.rs b/crates/wasmparser/src/readers/component/aliases.rs index 2ef6e78338..fb71d579b4 100644 --- a/crates/wasmparser/src/readers/component/aliases.rs +++ b/crates/wasmparser/src/readers/component/aliases.rs @@ -1,8 +1,4 @@ -use crate::{ - BinaryReader, ComponentExternalKind, ExternalKind, Result, SectionIteratorLimited, - SectionReader, SectionWithLimitedItems, -}; -use std::ops::Range; +use crate::{BinaryReader, ComponentExternalKind, ExternalKind, FromReader, Result}; /// Represents the kind of an outer alias in a WebAssembly component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -49,79 +45,75 @@ pub enum ComponentAlias<'a> { }, } -/// A reader for the alias section of a WebAssembly component. -#[derive(Clone)] -pub struct ComponentAliasSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ComponentAliasSectionReader<'a> { - /// Constructs a new `ComponentAliasSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } +/// Section reader for the component alias section +pub type ComponentAliasSectionReader<'a> = crate::SectionLimited<'a, ComponentAlias<'a>>; - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } +impl<'a> FromReader<'a> for ComponentAlias<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + // We don't know what type of alias it is yet, so just read the sort bytes + let offset = reader.original_position(); + let byte1 = reader.read_u8()?; + let byte2 = if byte1 == 0x00 { + Some(reader.read_u8()?) + } else { + None + }; - /// Reads content of the alias section. - /// - /// # Examples - /// ``` - /// use wasmparser::ComponentAliasSectionReader; - /// let data: &[u8] = &[0x01, 0x01, 0x00, 0x00, 0x03, b'f', b'o', b'o']; - /// let mut reader = ComponentAliasSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let alias = reader.read().expect("alias"); - /// println!("Alias: {:?}", alias); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_component_alias() + Ok(match reader.read_u8()? { + 0x00 => ComponentAlias::InstanceExport { + kind: ComponentExternalKind::from_bytes(byte1, byte2, offset)?, + instance_index: reader.read_var_u32()?, + name: reader.read_string()?, + }, + 0x01 => ComponentAlias::CoreInstanceExport { + kind: BinaryReader::external_kind_from_byte( + byte2.ok_or_else(|| { + BinaryReader::invalid_leading_byte_error( + byte1, + "core instance export kind", + offset, + ) + })?, + offset, + )?, + instance_index: reader.read_var_u32()?, + name: reader.read_string()?, + }, + 0x02 => ComponentAlias::Outer { + kind: component_outer_alias_kind_from_bytes(byte1, byte2, offset)?, + count: reader.read_var_u32()?, + index: reader.read_var_u32()?, + }, + x => reader.invalid_leading_byte(x, "alias")?, + }) } } -impl<'a> SectionReader for ComponentAliasSectionReader<'a> { - type Item = ComponentAlias<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for ComponentAliasSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) - } -} - -impl<'a> IntoIterator for ComponentAliasSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } +fn component_outer_alias_kind_from_bytes( + byte1: u8, + byte2: Option, + offset: usize, +) -> Result { + Ok(match byte1 { + 0x00 => match byte2.unwrap() { + 0x10 => ComponentOuterAliasKind::CoreType, + 0x11 => ComponentOuterAliasKind::CoreModule, + x => { + return Err(BinaryReader::invalid_leading_byte_error( + x, + "component outer alias kind", + offset + 1, + )) + } + }, + 0x03 => ComponentOuterAliasKind::Type, + 0x04 => ComponentOuterAliasKind::Component, + x => { + return Err(BinaryReader::invalid_leading_byte_error( + x, + "component outer alias kind", + offset, + )) + } + }) } diff --git a/crates/wasmparser/src/readers/component/canonicals.rs b/crates/wasmparser/src/readers/component/canonicals.rs index 321e63fad0..3b8c64b7b9 100644 --- a/crates/wasmparser/src/readers/component/canonicals.rs +++ b/crates/wasmparser/src/readers/component/canonicals.rs @@ -1,5 +1,5 @@ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; -use std::ops::Range; +use crate::limits::MAX_WASM_CANONICAL_OPTIONS; +use crate::{BinaryReader, FromReader, Result, SectionLimited}; /// Represents options for component functions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -43,82 +43,78 @@ pub enum CanonicalFunction { /// The canonical options for the function. options: Box<[CanonicalOption]>, }, + /// A function which creates a new owned handle to a resource. + ResourceNew { + /// The type index of the resource that's being created. + resource: u32, + }, + /// A function which is used to drop resource handles of the specified type. + ResourceDrop { + /// The type index of the resource that's being dropped. + resource: u32, + }, + /// A function which returns the underlying i32-based representation of the + /// specified resource. + ResourceRep { + /// The type index of the resource that's being accessed. + resource: u32, + }, } /// A reader for the canonical section of a WebAssembly component. -#[derive(Clone)] -pub struct ComponentCanonicalSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ComponentCanonicalSectionReader<'a> { - /// Constructs a new `ComponentFunctionSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads function type index from the function section. - /// - /// # Examples - /// - /// ``` - /// use wasmparser::ComponentCanonicalSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00]; - /// let mut reader = ComponentCanonicalSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let func = reader.read().expect("func"); - /// println!("Function: {:?}", func); - /// } - /// ``` - pub fn read(&mut self) -> Result { - self.reader.read_canonical_func() - } -} - -impl<'a> SectionReader for ComponentCanonicalSectionReader<'a> { - type Item = CanonicalFunction; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } +pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>; - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for ComponentCanonicalSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) +impl<'a> FromReader<'a> for CanonicalFunction { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => match reader.read_u8()? { + 0x00 => { + let core_func_index = reader.read_var_u32()?; + let options = reader + .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? + .collect::>()?; + let type_index = reader.read_var_u32()?; + CanonicalFunction::Lift { + core_func_index, + options, + type_index, + } + } + x => return reader.invalid_leading_byte(x, "canonical function lift"), + }, + 0x01 => match reader.read_u8()? { + 0x00 => CanonicalFunction::Lower { + func_index: reader.read_var_u32()?, + options: reader + .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? + .collect::>()?, + }, + x => return reader.invalid_leading_byte(x, "canonical function lower"), + }, + 0x02 => CanonicalFunction::ResourceNew { + resource: reader.read()?, + }, + 0x03 => CanonicalFunction::ResourceDrop { + resource: reader.read()?, + }, + 0x04 => CanonicalFunction::ResourceRep { + resource: reader.read()?, + }, + x => return reader.invalid_leading_byte(x, "canonical function"), + }) } } -impl<'a> IntoIterator for ComponentCanonicalSectionReader<'a> { - type Item = Result; - type IntoIter = SectionIteratorLimited; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for CanonicalOption { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => CanonicalOption::UTF8, + 0x01 => CanonicalOption::UTF16, + 0x02 => CanonicalOption::CompactUTF16, + 0x03 => CanonicalOption::Memory(reader.read_var_u32()?), + 0x04 => CanonicalOption::Realloc(reader.read_var_u32()?), + 0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?), + x => return reader.invalid_leading_byte(x, "canonical option"), + }) } } diff --git a/crates/wasmparser/src/readers/component/exports.rs b/crates/wasmparser/src/readers/component/exports.rs index dc08131c3a..35c5439405 100644 --- a/crates/wasmparser/src/readers/component/exports.rs +++ b/crates/wasmparser/src/readers/component/exports.rs @@ -1,5 +1,6 @@ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; -use std::ops::Range; +use crate::{ + BinaryReader, ComponentExternName, ComponentTypeRef, FromReader, Result, SectionLimited, +}; /// Represents the kind of an external items of a WebAssembly component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -18,91 +19,99 @@ pub enum ComponentExternalKind { Component, } +impl ComponentExternalKind { + pub(crate) fn from_bytes( + byte1: u8, + byte2: Option, + offset: usize, + ) -> Result { + Ok(match byte1 { + 0x00 => match byte2.unwrap() { + 0x11 => ComponentExternalKind::Module, + x => { + return Err(BinaryReader::invalid_leading_byte_error( + x, + "component external kind", + offset + 1, + )) + } + }, + 0x01 => ComponentExternalKind::Func, + 0x02 => ComponentExternalKind::Value, + 0x03 => ComponentExternalKind::Type, + 0x04 => ComponentExternalKind::Component, + 0x05 => ComponentExternalKind::Instance, + x => { + return Err(BinaryReader::invalid_leading_byte_error( + x, + "component external kind", + offset, + )) + } + }) + } + + /// Returns a simple string description of this kind. + pub fn desc(&self) -> &'static str { + use ComponentExternalKind::*; + match self { + Module => "module", + Func => "func", + Value => "value", + Type => "type", + Instance => "instance", + Component => "component", + } + } +} + /// Represents an export in a WebAssembly component. #[derive(Debug, Clone)] pub struct ComponentExport<'a> { /// The name of the exported item. - pub name: &'a str, + pub name: ComponentExternName<'a>, /// The kind of the export. pub kind: ComponentExternalKind, /// The index of the exported item. pub index: u32, + /// An optionally specified type ascribed to this export. + pub ty: Option, } /// A reader for the export section of a WebAssembly component. -#[derive(Clone)] -pub struct ComponentExportSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ComponentExportSectionReader<'a> { - /// Constructs a new `ComponentExportSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the export section. - /// - /// # Examples - /// ``` - /// use wasmparser::ComponentExportSectionReader; - /// - /// # let data: &[u8] = &[0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; - /// let mut reader = ComponentExportSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let export = reader.read().expect("export"); - /// println!("Export: {:?}", export); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_component_export() - } -} - -impl<'a> SectionReader for ComponentExportSectionReader<'a> { - type Item = ComponentExport<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} +pub type ComponentExportSectionReader<'a> = SectionLimited<'a, ComponentExport<'a>>; -impl<'a> SectionWithLimitedItems for ComponentExportSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) +impl<'a> FromReader<'a> for ComponentExport<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(ComponentExport { + name: reader.read()?, + kind: reader.read()?, + index: reader.read()?, + ty: match reader.read_u8()? { + 0x00 => None, + 0x01 => Some(reader.read()?), + other => { + return Err(BinaryReader::invalid_leading_byte_error( + other, + "optional component export type", + reader.original_position() - 1, + )) + } + }, + }) } } -impl<'a> IntoIterator for ComponentExportSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; +impl<'a> FromReader<'a> for ComponentExternalKind { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let offset = reader.original_position(); + let byte1 = reader.read_u8()?; + let byte2 = if byte1 == 0x00 { + Some(reader.read_u8()?) + } else { + None + }; - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) + ComponentExternalKind::from_bytes(byte1, byte2, offset) } } diff --git a/crates/wasmparser/src/readers/component/imports.rs b/crates/wasmparser/src/readers/component/imports.rs index 0b7b4faf86..d5e09cbc8f 100644 --- a/crates/wasmparser/src/readers/component/imports.rs +++ b/crates/wasmparser/src/readers/component/imports.rs @@ -1,14 +1,24 @@ use crate::{ - BinaryReader, ComponentValType, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, + BinaryReader, ComponentExternalKind, ComponentValType, FromReader, Result, SectionLimited, }; -use std::ops::Range; /// Represents the type bounds for imports and exports. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum TypeBounds { /// The type is bounded by equality. - Eq, + Eq(u32), + /// A fresh resource type, + SubResource, +} + +impl<'a> FromReader<'a> for TypeBounds { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => TypeBounds::Eq(reader.read()?), + 0x01 => TypeBounds::SubResource, + x => return reader.invalid_leading_byte(x, "type bound"), + }) + } } /// Represents a reference to a component type. @@ -27,7 +37,7 @@ pub enum ComponentTypeRef { /// The reference is to a bounded type. /// /// The index is expected to be a type index. - Type(TypeBounds, u32), + Type(TypeBounds), /// The reference is to an instance type. /// /// The index is a type index to an instance type. @@ -38,88 +48,90 @@ pub enum ComponentTypeRef { Component(u32), } +impl ComponentTypeRef { + /// Returns the corresponding [`ComponentExternalKind`] for this reference. + pub fn kind(&self) -> ComponentExternalKind { + match self { + ComponentTypeRef::Module(_) => ComponentExternalKind::Module, + ComponentTypeRef::Func(_) => ComponentExternalKind::Func, + ComponentTypeRef::Value(_) => ComponentExternalKind::Value, + ComponentTypeRef::Type(..) => ComponentExternalKind::Type, + ComponentTypeRef::Instance(_) => ComponentExternalKind::Instance, + ComponentTypeRef::Component(_) => ComponentExternalKind::Component, + } + } +} + +impl<'a> FromReader<'a> for ComponentTypeRef { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read()? { + ComponentExternalKind::Module => ComponentTypeRef::Module(reader.read()?), + ComponentExternalKind::Func => ComponentTypeRef::Func(reader.read()?), + ComponentExternalKind::Value => ComponentTypeRef::Value(reader.read()?), + ComponentExternalKind::Type => ComponentTypeRef::Type(reader.read()?), + ComponentExternalKind::Instance => ComponentTypeRef::Instance(reader.read()?), + ComponentExternalKind::Component => ComponentTypeRef::Component(reader.read()?), + }) + } +} + /// Represents an import in a WebAssembly component #[derive(Debug, Copy, Clone)] pub struct ComponentImport<'a> { /// The name of the imported item. - pub name: &'a str, + pub name: ComponentExternName<'a>, /// The type reference for the import. pub ty: ComponentTypeRef, } -/// A reader for the import section of a WebAssembly component. -#[derive(Clone)] -pub struct ComponentImportSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ComponentImportSectionReader<'a> { - /// Constructs a new `ComponentImportSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the import section. - /// - /// # Examples - /// ``` - /// use wasmparser::ComponentImportSectionReader; - /// let data: &[u8] = &[0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00]; - /// let mut reader = ComponentImportSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let import = reader.read().expect("import"); - /// println!("Import: {:?}", import); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_component_import() +impl<'a> FromReader<'a> for ComponentImport<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(ComponentImport { + name: reader.read()?, + ty: reader.read()?, + }) } } -impl<'a> SectionReader for ComponentImportSectionReader<'a> { - type Item = ComponentImport<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } +/// A reader for the import section of a WebAssembly component. +/// +/// # Examples +/// +/// ``` +/// use wasmparser::ComponentImportSectionReader; +/// let data: &[u8] = &[0x01, 0x00, 0x01, 0x41, 0x01, 0x66]; +/// let reader = ComponentImportSectionReader::new(data, 0).unwrap(); +/// for import in reader { +/// let import = import.expect("import"); +/// println!("Import: {:?}", import); +/// } +/// ``` +pub type ComponentImportSectionReader<'a> = SectionLimited<'a, ComponentImport<'a>>; + +/// Represents the name of a component import. +#[derive(Debug, Copy, Clone)] +#[allow(missing_docs)] +pub enum ComponentExternName<'a> { + Kebab(&'a str), + Interface(&'a str), } -impl<'a> SectionWithLimitedItems for ComponentImportSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) +impl<'a> ComponentExternName<'a> { + /// Returns the underlying string representing this name. + pub fn as_str(&self) -> &'a str { + match self { + ComponentExternName::Kebab(name) => name, + ComponentExternName::Interface(name) => name, + } } } -impl<'a> IntoIterator for ComponentImportSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for ComponentExternName<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => ComponentExternName::Kebab(reader.read()?), + 0x01 => ComponentExternName::Interface(reader.read()?), + x => return reader.invalid_leading_byte(x, "import name"), + }) } } diff --git a/crates/wasmparser/src/readers/component/instances.rs b/crates/wasmparser/src/readers/component/instances.rs index 79cacfbe94..a33762c420 100644 --- a/crates/wasmparser/src/readers/component/instances.rs +++ b/crates/wasmparser/src/readers/component/instances.rs @@ -1,8 +1,8 @@ +use crate::limits::{MAX_WASM_INSTANTIATION_ARGS, MAX_WASM_INSTANTIATION_EXPORTS}; use crate::{ - BinaryReader, ComponentExport, ComponentExternalKind, Export, Result, SectionIteratorLimited, - SectionReader, SectionWithLimitedItems, + BinaryReader, ComponentExport, ComponentExternalKind, Export, FromReader, Result, + SectionLimited, }; -use std::ops::Range; /// Represents the kind of an instantiation argument for a core instance. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -37,91 +37,54 @@ pub enum Instance<'a> { } /// A reader for the core instance section of a WebAssembly component. -#[derive(Clone)] -pub struct InstanceSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> InstanceSectionReader<'a> { - /// Constructs a new `InstanceSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the instance section. - /// - /// # Examples - /// ``` - /// use wasmparser::InstanceSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00]; - /// let mut reader = InstanceSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let instance = reader.read().expect("instance"); - /// println!("Instance: {:?}", instance); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_instance() +/// +/// # Examples +/// +/// ``` +/// use wasmparser::InstanceSectionReader; +/// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00]; +/// let mut reader = InstanceSectionReader::new(data, 0).unwrap(); +/// for inst in reader { +/// println!("Instance {:?}", inst.expect("instance")); +/// } +/// ``` +pub type InstanceSectionReader<'a> = SectionLimited<'a, Instance<'a>>; + +impl<'a> FromReader<'a> for Instance<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => Instance::Instantiate { + module_index: reader.read_var_u32()?, + args: reader + .read_iter(MAX_WASM_INSTANTIATION_ARGS, "core instantiation arguments")? + .collect::>()?, + }, + 0x01 => Instance::FromExports( + reader + .read_iter(MAX_WASM_INSTANTIATION_ARGS, "core instantiation arguments")? + .collect::>()?, + ), + x => return reader.invalid_leading_byte(x, "core instance"), + }) } } -impl<'a> SectionReader for InstanceSectionReader<'a> { - type Item = Instance<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for InstanceSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) +impl<'a> FromReader<'a> for InstantiationArg<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(InstantiationArg { + name: reader.read()?, + kind: reader.read()?, + index: reader.read()?, + }) } } -impl<'a> IntoIterator for InstanceSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - /// Implements iterator over the instance section. - /// - /// # Examples - /// - /// ``` - /// use wasmparser::InstanceSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00]; - /// let mut reader = InstanceSectionReader::new(data, 0).unwrap(); - /// for inst in reader { - /// println!("Instance {:?}", inst.expect("instance")); - /// } - /// ``` - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for InstantiationArgKind { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x12 => InstantiationArgKind::Instance, + x => return reader.invalid_leading_byte(x, "instantiation arg kind"), + }) } } @@ -151,90 +114,50 @@ pub enum ComponentInstance<'a> { } /// A reader for the component instance section of a WebAssembly component. -#[derive(Clone)] -pub struct ComponentInstanceSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ComponentInstanceSectionReader<'a> { - /// Constructs a new `ComponentInstanceSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the instance section. - /// - /// # Examples - /// ``` - /// use wasmparser::ComponentInstanceSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; - /// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let instance = reader.read().expect("instance"); - /// println!("Instance: {:?}", instance); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_component_instance() +/// +/// # Examples +/// +/// ``` +/// use wasmparser::ComponentInstanceSectionReader; +/// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; +/// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap(); +/// for inst in reader { +/// println!("Instance {:?}", inst.expect("instance")); +/// } +/// ``` +pub type ComponentInstanceSectionReader<'a> = SectionLimited<'a, ComponentInstance<'a>>; + +impl<'a> FromReader<'a> for ComponentInstance<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => ComponentInstance::Instantiate { + component_index: reader.read_var_u32()?, + args: reader + .read_iter(MAX_WASM_INSTANTIATION_ARGS, "instantiation arguments")? + .collect::>()?, + }, + 0x01 => ComponentInstance::FromExports( + (0..reader.read_size(MAX_WASM_INSTANTIATION_EXPORTS, "instantiation exports")?) + .map(|_| { + Ok(ComponentExport { + name: reader.read()?, + kind: reader.read()?, + index: reader.read()?, + ty: None, + }) + }) + .collect::>()?, + ), + x => return reader.invalid_leading_byte(x, "instance"), + }) } } - -impl<'a> SectionReader for ComponentInstanceSectionReader<'a> { - type Item = ComponentInstance<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for ComponentInstanceSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) - } -} - -impl<'a> IntoIterator for ComponentInstanceSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - /// Implements iterator over the instance section. - /// - /// # Examples - /// - /// ``` - /// use wasmparser::ComponentInstanceSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; - /// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap(); - /// for inst in reader { - /// println!("Instance {:?}", inst.expect("instance")); - /// } - /// ``` - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for ComponentInstantiationArg<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(ComponentInstantiationArg { + name: reader.read()?, + kind: reader.read()?, + index: reader.read()?, + }) } } diff --git a/crates/wasmparser/src/readers/component/names.rs b/crates/wasmparser/src/readers/component/names.rs new file mode 100644 index 0000000000..19de2752d0 --- /dev/null +++ b/crates/wasmparser/src/readers/component/names.rs @@ -0,0 +1,102 @@ +use crate::{BinaryReader, BinaryReaderError, NameMap, Result, Subsection, Subsections}; +use std::ops::Range; + +/// Type used to iterate and parse the contents of the `component-name` custom +/// section in compnents, similar to the `name` section of core modules. +pub type ComponentNameSectionReader<'a> = Subsections<'a, ComponentName<'a>>; + +/// Represents a name read from the names custom section. +#[derive(Clone)] +#[allow(missing_docs)] +pub enum ComponentName<'a> { + Component { + name: &'a str, + name_range: Range, + }, + CoreFuncs(NameMap<'a>), + CoreGlobals(NameMap<'a>), + CoreMemories(NameMap<'a>), + CoreTables(NameMap<'a>), + CoreModules(NameMap<'a>), + CoreInstances(NameMap<'a>), + CoreTypes(NameMap<'a>), + Types(NameMap<'a>), + Instances(NameMap<'a>), + Components(NameMap<'a>), + Funcs(NameMap<'a>), + Values(NameMap<'a>), + + /// An unknown [name subsection](https://webassembly.github.io/spec/core/appendix/custom.html#subsections). + Unknown { + /// The identifier for this subsection. + ty: u8, + /// The contents of this subsection. + data: &'a [u8], + /// The range of bytes, relative to the start of the original data + /// stream, that the contents of this subsection reside in. + range: Range, + }, +} + +impl<'a> Subsection<'a> for ComponentName<'a> { + fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result { + let data = reader.remaining_buffer(); + let offset = reader.original_position(); + Ok(match id { + 0 => { + let name = reader.read_string()?; + if !reader.eof() { + return Err(BinaryReaderError::new( + "trailing data at the end of a name", + reader.original_position(), + )); + } + ComponentName::Component { + name, + name_range: offset..offset + reader.position, + } + } + 1 => { + let ctor: fn(NameMap<'a>) -> ComponentName<'a> = match reader.read_u8()? { + 0x00 => match reader.read_u8()? { + 0x00 => ComponentName::CoreFuncs, + 0x01 => ComponentName::CoreTables, + 0x02 => ComponentName::CoreMemories, + 0x03 => ComponentName::CoreGlobals, + 0x10 => ComponentName::CoreTypes, + 0x11 => ComponentName::CoreModules, + 0x12 => ComponentName::CoreInstances, + _ => { + return Ok(ComponentName::Unknown { + ty: 1, + data, + range: offset..offset + data.len(), + }); + } + }, + 0x01 => ComponentName::Funcs, + 0x02 => ComponentName::Values, + 0x03 => ComponentName::Types, + 0x04 => ComponentName::Components, + 0x05 => ComponentName::Instances, + _ => { + return Ok(ComponentName::Unknown { + ty: 1, + data, + range: offset..offset + data.len(), + }); + } + }; + ctor(NameMap::new( + reader.remaining_buffer(), + reader.original_position(), + )?) + } + ty => ComponentName::Unknown { + ty, + data, + range: offset..offset + data.len(), + }, + }) + } +} diff --git a/crates/wasmparser/src/readers/component/start.rs b/crates/wasmparser/src/readers/component/start.rs index 7bfd0c8af4..dc01fa4340 100644 --- a/crates/wasmparser/src/readers/component/start.rs +++ b/crates/wasmparser/src/readers/component/start.rs @@ -1,5 +1,5 @@ -use crate::{BinaryReader, Result, SectionReader}; -use std::ops::Range; +use crate::limits::{MAX_WASM_FUNCTION_RETURNS, MAX_WASM_START_ARGS}; +use crate::{BinaryReader, FromReader, Result}; /// Represents the start function in a WebAssembly component. #[derive(Debug, Clone)] @@ -14,53 +14,17 @@ pub struct ComponentStartFunction { pub results: u32, } -/// A reader for the start section of a WebAssembly component. -#[derive(Clone)] -pub struct ComponentStartSectionReader<'a>(BinaryReader<'a>); - -impl<'a> ComponentStartSectionReader<'a> { - /// Constructs a new `ComponentStartSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - Ok(Self(BinaryReader::new_with_offset(data, offset))) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.0.original_position() - } - - /// Reads the start function from the section. - /// - /// # Examples - /// ``` - /// use wasmparser::ComponentStartSectionReader; - /// - /// # let data: &[u8] = &[0x00, 0x03, 0x01, 0x02, 0x03, 0x01]; - /// let mut reader = ComponentStartSectionReader::new(data, 0).unwrap(); - /// let start = reader.read().expect("start"); - /// println!("Start: {:?}", start); - /// ``` - pub fn read(&mut self) -> Result { - self.0.read_component_start() - } -} - -impl<'a> SectionReader for ComponentStartSectionReader<'a> { - type Item = ComponentStartFunction; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.0.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.0.range() +impl<'a> FromReader<'a> for ComponentStartFunction { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let func_index = reader.read_var_u32()?; + let arguments = reader + .read_iter(MAX_WASM_START_ARGS, "start function arguments")? + .collect::>()?; + let results = reader.read_size(MAX_WASM_FUNCTION_RETURNS, "start function results")? as u32; + Ok(ComponentStartFunction { + func_index, + arguments, + results, + }) } } diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 157ad01e0e..b33b3cd526 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -1,8 +1,9 @@ +use crate::limits::*; use crate::{ - BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, FuncType, Import, Result, - SectionIteratorLimited, SectionReader, SectionWithLimitedItems, Type, TypeRef, + BinaryReader, ComponentAlias, ComponentExternName, ComponentImport, ComponentTypeRef, + FromReader, FuncType, Import, Result, SectionLimited, SubType, TypeRef, ValType, }; -use std::ops::Range; +use std::fmt; /// Represents the kind of an outer core alias in a WebAssembly component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -20,11 +21,25 @@ pub enum CoreType<'a> { Module(Box<[ModuleTypeDeclaration<'a>]>), } +impl<'a> FromReader<'a> for CoreType<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x60 => CoreType::Func(reader.read()?), + 0x50 => CoreType::Module( + reader + .read_iter(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")? + .collect::>()?, + ), + x => return reader.invalid_leading_byte(x, "core type"), + }) + } +} + /// Represents a module type declaration in a WebAssembly component. #[derive(Debug, Clone)] pub enum ModuleTypeDeclaration<'a> { /// The module type definition is for a type. - Type(Type), + Type(SubType), /// The module type definition is for an export. Export { /// The name of the exported item. @@ -45,93 +60,50 @@ pub enum ModuleTypeDeclaration<'a> { Import(Import<'a>), } -/// A reader for the core type section of a WebAssembly component. -#[derive(Clone)] -pub struct CoreTypeSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> CoreTypeSectionReader<'a> { - /// Constructs a new `CoreTypeSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets a count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the type section. - /// - /// # Examples - /// ``` - /// use wasmparser::CoreTypeSectionReader; - /// let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; - /// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let ty = reader.read().expect("type"); - /// println!("Type {:?}", ty); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_core_type() - } -} - -impl<'a> SectionReader for CoreTypeSectionReader<'a> { - type Item = CoreType<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for CoreTypeSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) +impl<'a> FromReader<'a> for ModuleTypeDeclaration<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => ModuleTypeDeclaration::Import(reader.read()?), + 0x01 => ModuleTypeDeclaration::Type(reader.read()?), + 0x02 => { + let kind = match reader.read_u8()? { + 0x10 => OuterAliasKind::Type, + x => { + return reader.invalid_leading_byte(x, "outer alias kind"); + } + }; + match reader.read_u8()? { + 0x01 => ModuleTypeDeclaration::OuterAlias { + kind, + count: reader.read()?, + index: reader.read()?, + }, + x => { + return reader.invalid_leading_byte(x, "outer alias target"); + } + } + } + 0x03 => ModuleTypeDeclaration::Export { + name: reader.read()?, + ty: reader.read()?, + }, + x => return reader.invalid_leading_byte(x, "type definition"), + }) } } -impl<'a> IntoIterator for CoreTypeSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - /// Implements iterator over the type section. - /// - /// # Examples - /// ``` - /// use wasmparser::CoreTypeSectionReader; - /// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; - /// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap(); - /// for ty in reader { - /// println!("Type {:?}", ty.expect("type")); - /// } - /// ``` - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } -} +/// A reader for the core type section of a WebAssembly component. +/// +/// # Examples +/// ``` +/// use wasmparser::CoreTypeSectionReader; +/// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; +/// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap(); +/// for ty in reader { +/// println!("Type {:?}", ty.expect("type")); +/// } +/// ``` +pub type CoreTypeSectionReader<'a> = SectionLimited<'a, CoreType<'a>>; /// Represents a value type in a WebAssembly component. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -142,6 +114,27 @@ pub enum ComponentValType { Type(u32), } +impl<'a> FromReader<'a> for ComponentValType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + if let Some(ty) = PrimitiveValType::from_byte(reader.peek()?) { + reader.position += 1; + return Ok(ComponentValType::Primitive(ty)); + } + + Ok(ComponentValType::Type(reader.read_var_s33()? as u32)) + } +} + +impl<'a> FromReader<'a> for Option { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + match reader.read_u8()? { + 0x0 => Ok(None), + 0x1 => Ok(Some(reader.read()?)), + x => reader.invalid_leading_byte(x, "optional component value type"), + } + } +} + /// Represents a primitive value type. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PrimitiveValType { @@ -174,37 +167,60 @@ pub enum PrimitiveValType { } impl PrimitiveValType { - pub(crate) fn requires_realloc(&self) -> bool { + fn from_byte(byte: u8) -> Option { + Some(match byte { + 0x7f => PrimitiveValType::Bool, + 0x7e => PrimitiveValType::S8, + 0x7d => PrimitiveValType::U8, + 0x7c => PrimitiveValType::S16, + 0x7b => PrimitiveValType::U16, + 0x7a => PrimitiveValType::S32, + 0x79 => PrimitiveValType::U32, + 0x78 => PrimitiveValType::S64, + 0x77 => PrimitiveValType::U64, + 0x76 => PrimitiveValType::Float32, + 0x75 => PrimitiveValType::Float64, + 0x74 => PrimitiveValType::Char, + 0x73 => PrimitiveValType::String, + _ => return None, + }) + } + + pub(crate) fn contains_ptr(&self) -> bool { matches!(self, Self::String) } /// Determines if primitive value type `a` is a subtype of `b`. pub fn is_subtype_of(a: Self, b: Self) -> bool { - // Subtyping rules according to - // https://github.com/WebAssembly/component-model/blob/17f94ed1270a98218e0e796ca1dad1feb7e5c507/design/mvp/Subtyping.md + // Note that this intentionally diverges from the upstream specification + // at this time and only considers exact equality for subtyping + // relationships. + // + // More information can be found in the subtyping implementation for + // component functions. a == b - || matches!( - (a, b), - (Self::S8, Self::S16) - | (Self::S8, Self::S32) - | (Self::S8, Self::S64) - | (Self::U8, Self::U16) - | (Self::U8, Self::U32) - | (Self::U8, Self::U64) - | (Self::U8, Self::S16) - | (Self::U8, Self::S32) - | (Self::U8, Self::S64) - | (Self::S16, Self::S32) - | (Self::S16, Self::S64) - | (Self::U16, Self::U32) - | (Self::U16, Self::U64) - | (Self::U16, Self::S32) - | (Self::U16, Self::S64) - | (Self::S32, Self::S64) - | (Self::U32, Self::U64) - | (Self::U32, Self::S64) - | (Self::Float32, Self::Float64) - ) + } +} + +impl fmt::Display for PrimitiveValType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use PrimitiveValType::*; + let s = match self { + Bool => "bool", + S8 => "s8", + U8 => "u8", + S16 => "s16", + U16 => "u16", + S32 => "s32", + U32 => "u32", + S64 => "s64", + U64 => "u64", + Float32 => "float32", + Float64 => "float64", + Char => "char", + String => "string", + }; + s.fmt(f) } } @@ -219,6 +235,53 @@ pub enum ComponentType<'a> { Component(Box<[ComponentTypeDeclaration<'a>]>), /// The type is an instance type. Instance(Box<[InstanceTypeDeclaration<'a>]>), + /// The type is a fresh new resource type. + Resource { + /// The representation of this resource type in core WebAssembly. + rep: ValType, + /// An optionally-specified destructor to use for when this resource is + /// no longer needed. + dtor: Option, + }, +} + +impl<'a> FromReader<'a> for ComponentType<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x3f => ComponentType::Resource { + rep: reader.read()?, + dtor: match reader.read_u8()? { + 0x00 => None, + 0x01 => Some(reader.read()?), + b => return reader.invalid_leading_byte(b, "resource destructor"), + }, + }, + 0x40 => { + let params = reader + .read_iter(MAX_WASM_FUNCTION_PARAMS, "component function parameters")? + .collect::>()?; + let results = reader.read()?; + ComponentType::Func(ComponentFuncType { params, results }) + } + 0x41 => ComponentType::Component( + reader + .read_iter(MAX_WASM_COMPONENT_TYPE_DECLS, "component type declaration")? + .collect::>()?, + ), + 0x42 => ComponentType::Instance( + reader + .read_iter(MAX_WASM_INSTANCE_TYPE_DECLS, "instance type declaration")? + .collect::>()?, + ), + x => { + if let Some(ty) = PrimitiveValType::from_byte(x) { + ComponentType::Defined(ComponentDefinedType::Primitive(ty)) + } else { + ComponentType::Defined(ComponentDefinedType::read(reader, x)?) + } + } + }) + } } /// Represents part of a component type declaration in a WebAssembly component. @@ -233,7 +296,7 @@ pub enum ComponentTypeDeclaration<'a> { /// The component type declaration is for an export. Export { /// The name of the export. - name: &'a str, + name: ComponentExternName<'a>, /// The type reference for the export. ty: ComponentTypeRef, }, @@ -241,6 +304,27 @@ pub enum ComponentTypeDeclaration<'a> { Import(ComponentImport<'a>), } +impl<'a> FromReader<'a> for ComponentTypeDeclaration<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + // Component types are effectively instance types with the additional + // variant of imports; check for imports here or delegate to + // `InstanceTypeDeclaration` with the appropriate conversions. + if reader.peek()? == 0x03 { + reader.position += 1; + return Ok(ComponentTypeDeclaration::Import(reader.read()?)); + } + + Ok(match reader.read()? { + InstanceTypeDeclaration::CoreType(t) => ComponentTypeDeclaration::CoreType(t), + InstanceTypeDeclaration::Type(t) => ComponentTypeDeclaration::Type(t), + InstanceTypeDeclaration::Alias(a) => ComponentTypeDeclaration::Alias(a), + InstanceTypeDeclaration::Export { name, ty } => { + ComponentTypeDeclaration::Export { name, ty } + } + }) + } +} + /// Represents an instance type declaration in a WebAssembly component. #[derive(Debug, Clone)] pub enum InstanceTypeDeclaration<'a> { @@ -253,37 +337,60 @@ pub enum InstanceTypeDeclaration<'a> { /// The instance type declaration is for an export. Export { /// The name of the export. - name: &'a str, + name: ComponentExternName<'a>, /// The type reference for the export. ty: ComponentTypeRef, }, } -/// Represents the vector of types in a component function's -/// parameters or results. +impl<'a> FromReader<'a> for InstanceTypeDeclaration<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => InstanceTypeDeclaration::CoreType(reader.read()?), + 0x01 => InstanceTypeDeclaration::Type(reader.read()?), + 0x02 => InstanceTypeDeclaration::Alias(reader.read()?), + 0x04 => InstanceTypeDeclaration::Export { + name: reader.read()?, + ty: reader.read()?, + }, + x => return reader.invalid_leading_byte(x, "component or instance type declaration"), + }) + } +} + +/// Represents the result type of a component function. #[derive(Debug, Clone)] -pub enum TypeVec<'a> { - /// The type vector contains a single, unnamed type. +pub enum ComponentFuncResult<'a> { + /// The function returns a singular, unnamed type. Unnamed(ComponentValType), - /// The type vector contains zero or more named types. + /// The function returns zero or more named types. Named(Box<[(&'a str, ComponentValType)]>), } -impl TypeVec<'_> { - /// Gets the type vector's length. - pub fn len(&self) -> usize { +impl<'a> FromReader<'a> for ComponentFuncResult<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read_u8()? { + 0x00 => ComponentFuncResult::Unnamed(reader.read()?), + 0x01 => ComponentFuncResult::Named( + reader + .read_iter(MAX_WASM_FUNCTION_RETURNS, "component function results")? + .collect::>()?, + ), + x => return reader.invalid_leading_byte(x, "component function results"), + }) + } +} + +impl ComponentFuncResult<'_> { + /// Gets the count of types returned by the function. + pub fn type_count(&self) -> usize { match self { Self::Unnamed(_) => 1, Self::Named(vec) => vec.len(), } } - /// Determines if the type vector is empty. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Iterates over the types in the type vector. + /// Iterates over the types returned by the function. pub fn iter(&self) -> impl Iterator, &ComponentValType)> { enum Either { Left(L), @@ -316,9 +423,9 @@ impl TypeVec<'_> { #[derive(Debug, Clone)] pub struct ComponentFuncType<'a> { /// The function parameters. - pub params: TypeVec<'a>, - /// The function results. - pub results: TypeVec<'a>, + pub params: Box<[(&'a str, ComponentValType)]>, + /// The function result. + pub results: ComponentFuncResult<'a>, } /// Represents a case in a variant type. @@ -332,6 +439,20 @@ pub struct VariantCase<'a> { pub refines: Option, } +impl<'a> FromReader<'a> for VariantCase<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(VariantCase { + name: reader.read()?, + ty: reader.read()?, + refines: match reader.read_u8()? { + 0x0 => None, + 0x1 => Some(reader.read_var_u32()?), + x => return reader.invalid_leading_byte(x, "variant case refines"), + }, + }) + } +} + /// Represents a defined type in a WebAssembly component. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ComponentDefinedType<'a> { @@ -349,8 +470,6 @@ pub enum ComponentDefinedType<'a> { Flags(Box<[&'a str]>), /// The type is an enum with the given tags. Enum(Box<[&'a str]>), - /// The type is a union of the given value types. - Union(Box<[ComponentValType]>), /// The type is an option of the given value type. Option(ComponentValType), /// The type is a result type. @@ -360,92 +479,64 @@ pub enum ComponentDefinedType<'a> { /// The type returned for failure. err: Option, }, + /// An owned handle to a resource. + Own(u32), + /// A borrowed handle to a resource. + Borrow(u32), } -/// A reader for the type section of a WebAssembly component. -#[derive(Clone)] -pub struct ComponentTypeSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ComponentTypeSectionReader<'a> { - /// Constructs a new `ComponentTypeSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets a count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the type section. - /// - /// # Examples - /// ``` - /// use wasmparser::ComponentTypeSectionReader; - /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73]; - /// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let ty = reader.read().expect("type"); - /// println!("Type {:?}", ty); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_component_type() +impl<'a> ComponentDefinedType<'a> { + fn read(reader: &mut BinaryReader<'a>, byte: u8) -> Result> { + Ok(match byte { + 0x72 => ComponentDefinedType::Record( + reader + .read_iter(MAX_WASM_RECORD_FIELDS, "record field")? + .collect::>()?, + ), + 0x71 => ComponentDefinedType::Variant( + reader + .read_iter(MAX_WASM_VARIANT_CASES, "variant cases")? + .collect::>()?, + ), + 0x70 => ComponentDefinedType::List(reader.read()?), + 0x6f => ComponentDefinedType::Tuple( + reader + .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")? + .collect::>()?, + ), + 0x6e => ComponentDefinedType::Flags( + reader + .read_iter(MAX_WASM_FLAG_NAMES, "flag names")? + .collect::>()?, + ), + 0x6d => ComponentDefinedType::Enum( + reader + .read_iter(MAX_WASM_ENUM_CASES, "enum cases")? + .collect::>()?, + ), + // NOTE: 0x6c (union) removed + 0x6b => ComponentDefinedType::Option(reader.read()?), + 0x6a => ComponentDefinedType::Result { + ok: reader.read()?, + err: reader.read()?, + }, + 0x69 => ComponentDefinedType::Own(reader.read()?), + 0x68 => ComponentDefinedType::Borrow(reader.read()?), + x => return reader.invalid_leading_byte(x, "component defined type"), + }) } } -impl<'a> SectionReader for ComponentTypeSectionReader<'a> { - type Item = ComponentType<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for ComponentTypeSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) - } -} - -impl<'a> IntoIterator for ComponentTypeSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - /// Implements iterator over the type section. - /// - /// # Examples - /// ``` - /// use wasmparser::ComponentTypeSectionReader; - /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73]; - /// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); - /// for ty in reader { - /// println!("Type {:?}", ty.expect("type")); - /// } - /// ``` - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } -} +/// A reader for the type section of a WebAssembly component. +/// +/// # Examples +/// +/// ``` +/// use wasmparser::ComponentTypeSectionReader; +/// let data: &[u8] = &[0x01, 0x40, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73]; +/// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); +/// for ty in reader { +/// println!("Type {:?}", ty.expect("type")); +/// } +/// ``` +pub type ComponentTypeSectionReader<'a> = SectionLimited<'a, ComponentType<'a>>; diff --git a/crates/wasmparser/src/readers/core.rs b/crates/wasmparser/src/readers/core.rs index 941f208548..f6fbc075ef 100644 --- a/crates/wasmparser/src/readers/core.rs +++ b/crates/wasmparser/src/readers/core.rs @@ -1,37 +1,37 @@ mod code; +mod coredumps; mod custom; mod data; +mod dylink0; mod elements; mod exports; mod functions; mod globals; mod imports; mod init; -mod linking; mod memories; mod names; mod operators; mod producers; -mod relocs; mod tables; mod tags; mod types; pub use self::code::*; +pub use self::coredumps::*; pub use self::custom::*; pub use self::data::*; +pub use self::dylink0::*; pub use self::elements::*; pub use self::exports::*; pub use self::functions::*; pub use self::globals::*; pub use self::imports::*; pub use self::init::*; -pub use self::linking::*; pub use self::memories::*; pub use self::names::*; pub use self::operators::*; pub use self::producers::*; -pub use self::relocs::*; pub use self::tables::*; pub use self::tags::*; pub use self::types::*; diff --git a/crates/wasmparser/src/readers/core/code.rs b/crates/wasmparser/src/readers/core/code.rs index 500e3ad189..2a463727e8 100644 --- a/crates/wasmparser/src/readers/core/code.rs +++ b/crates/wasmparser/src/readers/core/code.rs @@ -13,27 +13,23 @@ * limitations under the License. */ -use crate::{ - BinaryReader, BinaryReaderError, OperatorsReader, Result, SectionIteratorLimited, - SectionReader, SectionWithLimitedItems, ValType, -}; +use crate::{BinaryReader, FromReader, OperatorsReader, Result, SectionLimited, ValType}; use std::ops::Range; +/// A reader for the code section of a WebAssembly module. +pub type CodeSectionReader<'a> = SectionLimited<'a, FunctionBody<'a>>; + /// Represents a WebAssembly function body. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub struct FunctionBody<'a> { - offset: usize, - data: &'a [u8], - allow_memarg64: bool, + reader: BinaryReader<'a>, } impl<'a> FunctionBody<'a> { /// Constructs a new `FunctionBody` for the given data and offset. pub fn new(offset: usize, data: &'a [u8]) -> Self { Self { - offset, - data, - allow_memarg64: false, + reader: BinaryReader::new_with_offset(data, offset), } } @@ -43,54 +39,47 @@ impl<'a> FunctionBody<'a> { /// This is intended to be `true` when support for the memory64 /// WebAssembly proposal is also enabled. pub fn allow_memarg64(&mut self, allow: bool) { - self.allow_memarg64 = allow; + self.reader.allow_memarg64(allow); } /// Gets a binary reader for this function body. - pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> - where - 'a: 'b, - { - let mut reader = BinaryReader::new_with_offset(self.data, self.offset); - reader.allow_memarg64(self.allow_memarg64); - reader + pub fn get_binary_reader(&self) -> BinaryReader<'a> { + self.reader.clone() } fn skip_locals(reader: &mut BinaryReader) -> Result<()> { let count = reader.read_var_u32()?; for _ in 0..count { reader.read_var_u32()?; - reader.read_var_u32()?; + reader.read::()?; } Ok(()) } /// Gets the locals reader for this function body. - pub fn get_locals_reader<'b>(&self) -> Result> - where - 'a: 'b, - { - let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + pub fn get_locals_reader(&self) -> Result> { + let mut reader = self.reader.clone(); let count = reader.read_var_u32()?; Ok(LocalsReader { reader, count }) } /// Gets the operators reader for this function body. - pub fn get_operators_reader<'b>(&self) -> Result> - where - 'a: 'b, - { - let mut reader = BinaryReader::new_with_offset(self.data, self.offset); + pub fn get_operators_reader(&self) -> Result> { + let mut reader = self.reader.clone(); Self::skip_locals(&mut reader)?; - let pos = reader.position; - let mut reader = OperatorsReader::new(&self.data[pos..], self.offset + pos); - reader.allow_memarg64(self.allow_memarg64); - Ok(reader) + Ok(OperatorsReader::new(reader)) } /// Gets the range of the function body. pub fn range(&self) -> Range { - self.offset..self.offset + self.data.len() + self.reader.range() + } +} + +impl<'a> FromReader<'a> for FunctionBody<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let reader = reader.read_reader("function body extends past end of the code section")?; + Ok(FunctionBody { reader }) } } @@ -113,8 +102,8 @@ impl<'a> LocalsReader<'a> { /// Reads an item from the reader. pub fn read(&mut self) -> Result<(u32, ValType)> { - let count = self.reader.read_var_u32()?; - let value_type = self.reader.read_val_type()?; + let count = self.reader.read()?; + let value_type = self.reader.read()?; Ok((count, value_type)) } } @@ -155,116 +144,3 @@ impl<'a> Iterator for LocalsIterator<'a> { (count, Some(count)) } } - -/// A reader for the code section of a WebAssembly module. -pub struct CodeSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> CodeSectionReader<'a> { - /// Constructs a new `CodeSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(CodeSectionReader { reader, count }) - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - fn verify_body_end(&self, end: usize) -> Result<()> { - if self.reader.buffer.len() < end { - return Err(BinaryReaderError::new( - "function body extends past end of the code section", - self.reader.original_offset + self.reader.buffer.len(), - )); - } - Ok(()) - } - - /// Reads content of the code section. - /// - /// # Examples - /// ``` - /// use wasmparser::CodeSectionReader; - /// # let data: &[u8] = &[ - /// # 0x01, 0x03, 0x00, 0x01, 0x0b]; - /// let mut code_reader = CodeSectionReader::new(data, 0).unwrap(); - /// for _ in 0..code_reader.get_count() { - /// let body = code_reader.read().expect("function body"); - /// let mut binary_reader = body.get_binary_reader(); - /// assert!(binary_reader.read_var_u32().expect("local count") == 0); - /// let op = binary_reader.read_operator().expect("first operator"); - /// println!("First operator: {:?}", op); - /// } - /// ``` - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let size = self.reader.read_var_u32()? as usize; - let body_start = self.reader.position; - let body_end = body_start + size; - self.verify_body_end(body_end)?; - self.reader.skip_to(body_end); - Ok(FunctionBody { - offset: self.reader.original_offset + body_start, - data: &self.reader.buffer[body_start..body_end], - allow_memarg64: false, - }) - } -} - -impl<'a> SectionReader for CodeSectionReader<'a> { - type Item = FunctionBody<'a>; - fn read(&mut self) -> Result { - CodeSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - CodeSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for CodeSectionReader<'a> { - fn get_count(&self) -> u32 { - CodeSectionReader::get_count(self) - } -} - -impl<'a> IntoIterator for CodeSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited>; - - /// Implements iterator over the code section. - /// - /// # Examples - /// ``` - /// use wasmparser::CodeSectionReader; - /// # let data: &[u8] = &[ - /// # 0x01, 0x03, 0x00, 0x01, 0x0b]; - /// let mut code_reader = CodeSectionReader::new(data, 0).unwrap(); - /// for body in code_reader { - /// let mut binary_reader = body.expect("b").get_binary_reader(); - /// assert!(binary_reader.read_var_u32().expect("local count") == 0); - /// let op = binary_reader.read_operator().expect("first operator"); - /// println!("First operator: {:?}", op); - /// } - /// ``` - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } -} diff --git a/crates/wasmparser/src/readers/core/coredumps.rs b/crates/wasmparser/src/readers/core/coredumps.rs new file mode 100644 index 0000000000..3579fdcefe --- /dev/null +++ b/crates/wasmparser/src/readers/core/coredumps.rs @@ -0,0 +1,243 @@ +use crate::{BinaryReader, FromReader, Result}; + +/// The data portion of a custom section representing a core dump. Per the +/// tool-conventions repo, this section just specifies the executable name that +/// the core dump came from while the rest of the core dump information is +/// contained in a corestack custom section +/// +/// # Examples +/// +/// ``` +/// use wasmparser::{ BinaryReader, CoreDumpSection, FromReader, Result }; +/// let data: &[u8] = &[0x00, 0x09, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x77, 0x61, +/// 0x73, 0x6d]; +/// let mut reader = BinaryReader::new(data); +/// let core = CoreDumpSection::from_reader(&mut reader).unwrap(); +/// assert!(core.name == "test.wasm") +/// ``` +pub struct CoreDumpSection<'a> { + /// The name of the process that created the core dump + pub name: &'a str, +} + +impl<'a> FromReader<'a> for CoreDumpSection<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let pos = reader.original_position(); + if reader.read_u8()? != 0 { + bail!(pos, "invalid start byte for core dump name"); + } + let name = reader.read_string()?; + Ok(CoreDumpSection { name }) + } +} + +/// The data portion of a "coremodules" custom section. This contains a vec of +/// module names that will be referenced by index by other coredump sections. +/// +/// # Example +/// +/// ``` +/// use wasmparser::{ BinaryReader, CoreDumpModulesSection, FromReader, Result }; +/// let data: &[u8] = &[0x01, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74]; +/// let mut reader = BinaryReader::new(data); +/// let modules_section = CoreDumpModulesSection::from_reader(&mut reader).unwrap(); +/// assert!(modules_section.modules[0] == "test") +/// ``` +#[derive(Debug)] +pub struct CoreDumpModulesSection<'a> { + /// A list of module names, which may be URLs, file paths, or other + /// identifiers for the module. + pub modules: Vec<&'a str>, +} + +impl<'a> FromReader<'a> for CoreDumpModulesSection<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let pos = reader.original_position(); + let mut modules = vec![]; + for _ in 0..reader.read_var_u32()? { + if reader.read_u8()? != 0 { + bail!(pos, "invalid start byte for coremodule"); + } + modules.push(reader.read_string()?); + } + Ok(CoreDumpModulesSection { modules }) + } +} +/// A custom section representing the instances involved in a given coredump +pub struct CoreDumpInstancesSection { + /// The instances for the coredump + pub instances: Vec, +} + +impl<'a> FromReader<'a> for CoreDumpInstancesSection { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let mut instances = vec![]; + for _ in 0..reader.read_var_u32()? { + instances.push(CoreDumpInstance::from_reader(reader)?); + } + Ok(CoreDumpInstancesSection { instances }) + } +} + +/// A single instance from a coredump instances section +pub struct CoreDumpInstance { + /// The module that this is an instance of, as an index into a "coremodules" + /// section. + pub module_index: u32, + + /// Which of the coredump's memories are this instance's memories, via + /// indexing into the memory index space. + pub memories: Vec, + + /// Which of the coredump's globals are this instance's globals, via + /// indexing into the global index space. + pub globals: Vec, +} + +impl<'a> FromReader<'a> for CoreDumpInstance { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let pos = reader.original_position(); + if reader.read_u8()? != 0 { + bail!(pos, "invalid start byte for core dump instance"); + } + let module_index = reader.read_var_u32()?; + let mut memories = vec![]; + for _ in 0..reader.read_var_u32()? { + memories.push(reader.read_var_u32()?); + } + let mut globals = vec![]; + + for _ in 0..reader.read_var_u32()? { + globals.push(reader.read_var_u32()?); + } + + Ok(CoreDumpInstance { + module_index, + memories, + globals, + }) + } +} + +/// The data portion of a custom section representing a core dump stack. The +/// structure of this follows the coredump spec in the tool-conventions repo +/// +/// # Examples +/// +/// ``` +/// let data: &[u8] = &[0x00, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x01, 0x00, 0x04, +/// 0x2a, 0x33, 0x01, 0x7f, 0x01, 0x01, 0x7f, 0x02]; +/// use wasmparser::{ BinaryReader, CoreDumpStackSection, FromReader }; +/// let mut reader = BinaryReader::new(data); +/// let corestack = CoreDumpStackSection::from_reader(&mut reader).unwrap(); +/// assert!(corestack.name == "main"); +/// assert!(corestack.frames.len() == 1); +/// let frame = &corestack.frames[0]; +/// assert!(frame.instanceidx == 4); +/// assert!(frame.funcidx == 42); +/// assert!(frame.codeoffset == 51); +/// assert!(frame.locals.len() == 1); +/// assert!(frame.stack.len() == 1); +/// ``` +pub struct CoreDumpStackSection<'a> { + /// The thread name + pub name: &'a str, + /// The stack frames for the core dump + pub frames: Vec, +} + +impl<'a> FromReader<'a> for CoreDumpStackSection<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let pos = reader.original_position(); + if reader.read_u8()? != 0 { + bail!(pos, "invalid start byte for core dump stack name"); + } + let name = reader.read_string()?; + let mut frames = vec![]; + for _ in 0..reader.read_var_u32()? { + frames.push(CoreDumpStackFrame::from_reader(reader)?); + } + Ok(CoreDumpStackSection { + name: name, + frames: frames, + }) + } +} + +/// A single stack frame from a core dump +#[derive(Debug)] +pub struct CoreDumpStackFrame { + /// The instance that this stack frame belongs to. + pub instanceidx: u32, + /// The function index in the module + pub funcidx: u32, + /// The instruction's offset relative to the function's start + pub codeoffset: u32, + /// The locals for this stack frame (including function parameters) + pub locals: Vec, + /// The values on the stack + pub stack: Vec, +} + +impl<'a> FromReader<'a> for CoreDumpStackFrame { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let pos = reader.original_position(); + if reader.read_u8()? != 0 { + bail!(pos, "invalid start byte for core dump stack frame"); + } + let instanceidx = reader.read_var_u32()?; + let funcidx = reader.read_var_u32()?; + let codeoffset = reader.read_var_u32()?; + let mut locals = vec![]; + for _ in 0..reader.read_var_u32()? { + locals.push(CoreDumpValue::from_reader(reader)?); + } + let mut stack = vec![]; + for _ in 0..reader.read_var_u32()? { + stack.push(CoreDumpValue::from_reader(reader)?); + } + + Ok(CoreDumpStackFrame { + instanceidx, + funcidx, + codeoffset, + locals, + stack, + }) + } +} + +/// Local and stack values are encoded using one byte for the type (similar to +/// Wasm's Number Types) followed by bytes representing the actual value +/// See the tool-conventions repo for more details. +#[derive(Clone, Debug)] +pub enum CoreDumpValue { + /// A missing value (usually missing because it was optimized out) + Missing, + /// An i32 value + I32(i32), + /// An i64 value + I64(i64), + /// An f32 value + F32(f32), + /// An f64 value + F64(f64), +} + +impl<'a> FromReader<'a> for CoreDumpValue { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let pos = reader.original_position(); + match reader.read_u8()? { + 0x01 => Ok(CoreDumpValue::Missing), + 0x7F => Ok(CoreDumpValue::I32(reader.read_var_i32()?)), + 0x7E => Ok(CoreDumpValue::I64(reader.read_var_i64()?)), + 0x7D => Ok(CoreDumpValue::F32(f32::from_bits( + reader.read_f32()?.bits(), + ))), + 0x7C => Ok(CoreDumpValue::F64(f64::from_bits( + reader.read_f64()?.bits(), + ))), + _ => bail!(pos, "invalid CoreDumpValue type"), + } + } +} diff --git a/crates/wasmparser/src/readers/core/data.rs b/crates/wasmparser/src/readers/core/data.rs index 8843f1aa50..5ea5f99457 100644 --- a/crates/wasmparser/src/readers/core/data.rs +++ b/crates/wasmparser/src/readers/core/data.rs @@ -13,10 +13,7 @@ * limitations under the License. */ -use crate::{ - BinaryReader, BinaryReaderError, ConstExpr, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, -}; +use crate::{BinaryReader, BinaryReaderError, ConstExpr, FromReader, Result, SectionLimited}; use std::ops::Range; /// Represents a data segment in a core WebAssembly module. @@ -45,66 +42,14 @@ pub enum DataKind<'a> { } /// A reader for the data section of a WebAssembly module. -#[derive(Clone)] -pub struct DataSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> DataSectionReader<'a> { - /// Constructs a new `DataSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(DataSectionReader { reader, count }) - } +pub type DataSectionReader<'a> = SectionLimited<'a, Data<'a>>; - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - fn verify_data_end(&self, end: usize) -> Result<()> { - if self.reader.buffer.len() < end { - return Err(BinaryReaderError::new( - "unexpected end of section or function: data segment extends past end of the data section", - self.reader.original_offset + self.reader.buffer.len(), - )); - } - Ok(()) - } - - /// Reads content of the data section. - /// - /// # Examples - /// ``` - /// use wasmparser::{DataSectionReader, DataKind}; - /// # let data: &[u8] = &[ - /// # 0x01, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00]; - /// let mut data_reader = DataSectionReader::new(data, 0).unwrap(); - /// for _ in 0..data_reader.get_count() { - /// let data = data_reader.read().expect("data"); - /// println!("Data: {:?}", data); - /// if let DataKind::Active { offset_expr, .. } = data.kind { - /// let mut offset_expr_reader = offset_expr.get_binary_reader(); - /// let op = offset_expr_reader.read_operator().expect("op"); - /// println!("offset expression: {:?}", op); - /// } - /// } - /// ``` - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let segment_start = self.reader.original_position(); +impl<'a> FromReader<'a> for Data<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let segment_start = reader.original_position(); // The current handling of the flags is largely specified in the `bulk-memory` proposal, - // which at the time this commend is written has been merged to the main specification + // which at the time this comment is written has been merged to the main specification // draft. // // Notably, this proposal allows multiple different encodings of the memory index 0. `00` @@ -116,21 +61,16 @@ impl<'a> DataSectionReader<'a> { // current specification draft does not allow for this. // // See also https://github.com/WebAssembly/spec/issues/1439 - let flags = self.reader.read_var_u32()?; + let flags = reader.read_var_u32()?; let kind = match flags { 1 => DataKind::Passive, 0 | 2 => { let memory_index = if flags == 0 { 0 } else { - self.reader.read_var_u32()? - }; - let offset_expr = { - let expr_offset = self.reader.position; - self.reader.skip_const_expr()?; - let data = &self.reader.buffer[expr_offset..self.reader.position]; - ConstExpr::new(data, self.reader.original_offset + expr_offset) + reader.read_var_u32()? }; + let offset_expr = reader.read()?; DataKind::Active { memory_index, offset_expr, @@ -139,51 +79,18 @@ impl<'a> DataSectionReader<'a> { _ => { return Err(BinaryReaderError::new( "invalid flags byte in data segment", - self.reader.original_position() - 1, + segment_start, )); } }; - let data_len = self.reader.read_var_u32()? as usize; - let data_end = self.reader.position + data_len; - self.verify_data_end(data_end)?; - let data = &self.reader.buffer[self.reader.position..data_end]; - self.reader.skip_to(data_end); - - let segment_end = self.reader.original_position(); - let range = segment_start..segment_end; - - Ok(Data { kind, data, range }) - } -} - -impl<'a> SectionReader for DataSectionReader<'a> { - type Item = Data<'a>; - fn read(&mut self) -> Result { - DataSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - DataSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for DataSectionReader<'a> { - fn get_count(&self) -> u32 { - DataSectionReader::get_count(self) - } -} - -impl<'a> IntoIterator for DataSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) + let data = reader.read_reader( + "unexpected end of section or function: data segment extends past end of the section", + )?; + Ok(Data { + kind, + data: data.remaining_buffer(), + range: segment_start..data.range().end, + }) } } diff --git a/crates/wasmparser/src/readers/core/dylink0.rs b/crates/wasmparser/src/readers/core/dylink0.rs new file mode 100644 index 0000000000..3a7cfc1077 --- /dev/null +++ b/crates/wasmparser/src/readers/core/dylink0.rs @@ -0,0 +1,132 @@ +use crate::{BinaryReader, Result, Subsection, Subsections}; +use std::ops::Range; + +/// Parser for the dynamic linking `dylink.0` custom section. +/// +/// This format is currently defined upstream at +/// . +pub type Dylink0SectionReader<'a> = Subsections<'a, Dylink0Subsection<'a>>; + +const WASM_DYLINK_MEM_INFO: u8 = 1; +const WASM_DYLINK_NEEDED: u8 = 2; +const WASM_DYLINK_EXPORT_INFO: u8 = 3; +const WASM_DYLINK_IMPORT_INFO: u8 = 4; + +#[allow(missing_docs)] +pub const WASM_SYM_BINDING_WEAK: u32 = 1 << 0; +#[allow(missing_docs)] +pub const WASM_SYM_BINDING_LOCAL: u32 = 1 << 1; +#[allow(missing_docs)] +pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 1 << 2; +#[allow(missing_docs)] +pub const WASM_SYM_UNDEFINED: u32 = 1 << 4; +#[allow(missing_docs)] +pub const WASM_SYM_EXPORTED: u32 = 1 << 5; +#[allow(missing_docs)] +pub const WASM_SYM_EXPLICIT_NAME: u32 = 1 << 6; +#[allow(missing_docs)] +pub const WASM_SYM_NO_STRIP: u32 = 1 << 7; + +/// Represents a `WASM_DYLINK_MEM_INFO` field +#[derive(Debug, Copy, Clone)] +pub struct MemInfo { + /// Size of the memory area the loader should reserve for the module, which + /// will begin at `env.__memory_base`. + pub memory_size: u32, + + /// The required alignment of the memory area, in bytes, encoded as a power + /// of 2. + pub memory_alignment: u32, + + /// Size of the table area the loader should reserve for the module, which + /// will begin at `env.__table_base`. + pub table_size: u32, + + /// The required alignment of the table area, in elements, encoded as a + /// power of 2. + pub table_alignment: u32, +} + +#[allow(missing_docs)] +#[derive(Debug)] +pub struct ExportInfo<'a> { + pub name: &'a str, + + /// Note that these flags correspond to those described in + /// + /// with the `WASM_SYM_*` prefix. + pub flags: u32, +} + +#[allow(missing_docs)] +#[derive(Debug)] +pub struct ImportInfo<'a> { + pub module: &'a str, + pub field: &'a str, + + /// Note that these flags correspond to those described in + /// + /// with the `WASM_SYM_*` prefix. + pub flags: u32, +} + +/// Possible subsections of the `dylink.0` custom section. +#[derive(Debug)] +#[allow(missing_docs)] +pub enum Dylink0Subsection<'a> { + MemInfo(MemInfo), + Needed(Vec<&'a str>), + ExportInfo(Vec>), + ImportInfo(Vec>), + Unknown { + ty: u8, + data: &'a [u8], + range: Range, + }, +} + +impl<'a> Subsection<'a> for Dylink0Subsection<'a> { + fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result { + let data = reader.remaining_buffer(); + let offset = reader.original_position(); + Ok(match id { + WASM_DYLINK_MEM_INFO => Self::MemInfo(MemInfo { + memory_size: reader.read_var_u32()?, + memory_alignment: reader.read_var_u32()?, + table_size: reader.read_var_u32()?, + table_alignment: reader.read_var_u32()?, + }), + WASM_DYLINK_NEEDED => Self::Needed( + (0..reader.read_var_u32()?) + .map(|_| reader.read_string()) + .collect::>()?, + ), + WASM_DYLINK_EXPORT_INFO => Self::ExportInfo( + (0..reader.read_var_u32()?) + .map(|_| { + Ok(ExportInfo { + name: reader.read_string()?, + flags: reader.read_var_u32()?, + }) + }) + .collect::>()?, + ), + WASM_DYLINK_IMPORT_INFO => Self::ImportInfo( + (0..reader.read_var_u32()?) + .map(|_| { + Ok(ImportInfo { + module: reader.read_string()?, + field: reader.read_string()?, + flags: reader.read_var_u32()?, + }) + }) + .collect::>()?, + ), + ty => Self::Unknown { + ty, + data, + range: offset..offset + data.len(), + }, + }) + } +} diff --git a/crates/wasmparser/src/readers/core/elements.rs b/crates/wasmparser/src/readers/core/elements.rs index 3eb0735d4f..a8bbb17d52 100644 --- a/crates/wasmparser/src/readers/core/elements.rs +++ b/crates/wasmparser/src/readers/core/elements.rs @@ -14,8 +14,8 @@ */ use crate::{ - BinaryReader, BinaryReaderError, ConstExpr, ExternalKind, Result, SectionIteratorLimited, - SectionReader, SectionWithLimitedItems, ValType, + BinaryReader, BinaryReaderError, ConstExpr, ExternalKind, FromReader, RefType, Result, + SectionLimited, }; use std::ops::Range; @@ -26,8 +26,6 @@ pub struct Element<'a> { pub kind: ElementKind<'a>, /// The initial elements of the element segment. pub items: ElementItems<'a>, - /// The type of the elements. - pub ty: ValType, /// The range of the the element segment. pub range: Range, } @@ -40,7 +38,7 @@ pub enum ElementKind<'a> { /// The element segment is active. Active { /// The index of the table being initialized. - table_index: u32, + table_index: Option, /// The initial expression of the element segment. offset_expr: ConstExpr<'a>, }, @@ -49,167 +47,20 @@ pub enum ElementKind<'a> { } /// Represents the items of an element segment. -#[derive(Debug, Copy, Clone)] -pub struct ElementItems<'a> { - exprs: bool, - offset: usize, - data: &'a [u8], -} - -/// Represents an individual item of an element segment. -#[derive(Debug)] -pub enum ElementItem<'a> { - /// The item is a function index. - Func(u32), - /// The item is an initialization expression. - Expr(ConstExpr<'a>), -} - -impl<'a> ElementItems<'a> { - /// Gets an items reader for the items in an element segment. - pub fn get_items_reader<'b>(&self) -> Result> - where - 'a: 'b, - { - ElementItemsReader::new(self.data, self.offset, self.exprs) - } -} - -/// A reader for element items in an element segment. -pub struct ElementItemsReader<'a> { - reader: BinaryReader<'a>, - count: u32, - exprs: bool, -} - -impl<'a> ElementItemsReader<'a> { - /// Constructs a new `ElementItemsReader` for the given data and offset. - pub fn new(data: &[u8], offset: usize, exprs: bool) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(ElementItemsReader { - reader, - count, - exprs, - }) - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of element items in the segment. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Whether or not initialization expressions are used. - pub fn uses_exprs(&self) -> bool { - self.exprs - } - - /// Reads an element item from the segment. - pub fn read(&mut self) -> Result> { - if self.exprs { - let expr = self.reader.read_const_expr()?; - Ok(ElementItem::Expr(expr)) - } else { - let idx = self.reader.read_var_u32()?; - Ok(ElementItem::Func(idx)) - } - } -} - -impl<'a> IntoIterator for ElementItemsReader<'a> { - type Item = Result>; - type IntoIter = ElementItemsIterator<'a>; - fn into_iter(self) -> Self::IntoIter { - let count = self.count; - ElementItemsIterator { - reader: self, - left: count, - err: false, - } - } -} - -/// An iterator over element items in an element segment. -pub struct ElementItemsIterator<'a> { - reader: ElementItemsReader<'a>, - left: u32, - err: bool, -} - -impl<'a> Iterator for ElementItemsIterator<'a> { - type Item = Result>; - fn next(&mut self) -> Option { - if self.err || self.left == 0 { - return None; - } - let result = self.reader.read(); - self.err = result.is_err(); - self.left -= 1; - Some(result) - } - fn size_hint(&self) -> (usize, Option) { - let count = self.reader.get_count() as usize; - (count, Some(count)) - } -} - -/// A reader for the element section of a WebAssembly module. #[derive(Clone)] -pub struct ElementSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, +pub enum ElementItems<'a> { + /// This element contains function indices. + Functions(SectionLimited<'a, u32>), + /// This element contains constant expressions used to initialize the table. + Expressions(RefType, SectionLimited<'a, ConstExpr<'a>>), } -impl<'a> ElementSectionReader<'a> { - /// Constructs a new `ElementSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(ElementSectionReader { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } +/// A reader for the element section of a WebAssembly module. +pub type ElementSectionReader<'a> = SectionLimited<'a, Element<'a>>; - /// Reads content of the element section. - /// - /// # Examples - /// - /// ```no_run - /// # let data: &[u8] = &[]; - /// use wasmparser::{ElementSectionReader, ElementKind}; - /// let mut element_reader = ElementSectionReader::new(data, 0).unwrap(); - /// for _ in 0..element_reader.get_count() { - /// let element = element_reader.read().expect("element"); - /// if let ElementKind::Active { offset_expr, .. } = element.kind { - /// let mut offset_expr_reader = offset_expr.get_binary_reader(); - /// let op = offset_expr_reader.read_operator().expect("op"); - /// println!("offset expression: {:?}", op); - /// } - /// let mut items_reader = element.items.get_items_reader().expect("items reader"); - /// for _ in 0..items_reader.get_count() { - /// let item = items_reader.read().expect("item"); - /// println!(" Item: {:?}", item); - /// } - /// } - /// ``` - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let elem_start = self.reader.original_position(); +impl<'a> FromReader<'a> for Element<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let elem_start = reader.original_position(); // The current handling of the flags is largely specified in the `bulk-memory` proposal, // which at the time this commend is written has been merged to the main specification // draft. @@ -223,11 +74,11 @@ impl<'a> ElementSectionReader<'a> { // though the current specification draft does not allow for this. // // See also https://github.com/WebAssembly/spec/issues/1439 - let flags = self.reader.read_var_u32()?; + let flags = reader.read_var_u32()?; if (flags & !0b111) != 0 { return Err(BinaryReaderError::new( "invalid flags byte in element segment", - self.reader.original_position() - 1, + reader.original_position() - 1, )); } let kind = if flags & 0b001 != 0 { @@ -238,16 +89,11 @@ impl<'a> ElementSectionReader<'a> { } } else { let table_index = if flags & 0b010 == 0 { - 0 + None } else { - self.reader.read_var_u32()? - }; - let offset_expr = { - let expr_offset = self.reader.position; - self.reader.skip_const_expr()?; - let data = &self.reader.buffer[expr_offset..self.reader.position]; - ConstExpr::new(data, self.reader.original_offset + expr_offset) + Some(reader.read_var_u32()?) }; + let offset_expr = reader.read()?; ElementKind::Active { table_index, offset_expr, @@ -256,78 +102,51 @@ impl<'a> ElementSectionReader<'a> { let exprs = flags & 0b100 != 0; let ty = if flags & 0b011 != 0 { if exprs { - self.reader.read_val_type()? + Some(reader.read()?) } else { - match self.reader.read_external_kind()? { - ExternalKind::Func => ValType::FuncRef, + match reader.read()? { + ExternalKind::Func => None, _ => { return Err(BinaryReaderError::new( "only the function external type is supported in elem segment", - self.reader.original_position() - 1, + reader.original_position() - 1, )); } } } } else { - ValType::FuncRef + None }; - let data_start = self.reader.position; - let items_count = self.reader.read_var_u32()?; - if exprs { - for _ in 0..items_count { - self.reader.skip_const_expr()?; + // FIXME(#188) ideally wouldn't have to do skips here + let data = reader.skip(|reader| { + let items_count = reader.read_var_u32()?; + if exprs { + for _ in 0..items_count { + reader.skip_const_expr()?; + } + } else { + for _ in 0..items_count { + reader.read_var_u32()?; + } } + Ok(()) + })?; + let items = if exprs { + ElementItems::Expressions( + ty.unwrap_or(RefType::FUNCREF), + SectionLimited::new(data.remaining_buffer(), data.original_position())?, + ) } else { - for _ in 0..items_count { - self.reader.read_var_u32()?; - } - } - let data_end = self.reader.position; - let items = ElementItems { - offset: self.reader.original_offset + data_start, - data: &self.reader.buffer[data_start..data_end], - exprs, + assert!(ty.is_none()); + ElementItems::Functions(SectionLimited::new( + data.remaining_buffer(), + data.original_position(), + )?) }; - let elem_end = self.reader.original_position(); + let elem_end = reader.original_position(); let range = elem_start..elem_end; - Ok(Element { - kind, - items, - ty, - range, - }) - } -} - -impl<'a> SectionReader for ElementSectionReader<'a> { - type Item = Element<'a>; - fn read(&mut self) -> Result { - ElementSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - ElementSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for ElementSectionReader<'a> { - fn get_count(&self) -> u32 { - ElementSectionReader::get_count(self) - } -} - -impl<'a> IntoIterator for ElementSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) + Ok(Element { kind, items, range }) } } diff --git a/crates/wasmparser/src/readers/core/exports.rs b/crates/wasmparser/src/readers/core/exports.rs index 0f4eb0a3a9..c1bd62626b 100644 --- a/crates/wasmparser/src/readers/core/exports.rs +++ b/crates/wasmparser/src/readers/core/exports.rs @@ -13,8 +13,10 @@ * limitations under the License. */ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; -use std::ops::Range; +use crate::{BinaryReader, FromReader, Result, SectionLimited}; + +/// A reader for the export section of a WebAssembly module. +pub type ExportSectionReader<'a> = SectionLimited<'a, Export<'a>>; /// External types as defined [here]. /// @@ -44,80 +46,20 @@ pub struct Export<'a> { pub index: u32, } -/// A reader for the export section of a WebAssembly module. -#[derive(Clone)] -pub struct ExportSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ExportSectionReader<'a> { - /// Constructs a new `ExportSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the export section. - /// - /// # Examples - /// ``` - /// use wasmparser::ExportSectionReader; - /// - /// # let data: &[u8] = &[0x01, 0x01, 0x65, 0x00, 0x00]; - /// let mut reader = ExportSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let export = reader.read().expect("export"); - /// println!("Export: {:?}", export); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_export() +impl<'a> FromReader<'a> for Export<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(Export { + name: reader.read_string()?, + kind: reader.read()?, + index: reader.read_var_u32()?, + }) } } -impl<'a> SectionReader for ExportSectionReader<'a> { - type Item = Export<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for ExportSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) - } -} - -impl<'a> IntoIterator for ExportSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for ExternalKind { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let offset = reader.original_position(); + let byte = reader.read_u8()?; + BinaryReader::external_kind_from_byte(byte, offset) } } diff --git a/crates/wasmparser/src/readers/core/functions.rs b/crates/wasmparser/src/readers/core/functions.rs index a98b7fa9fe..ebddce05a3 100644 --- a/crates/wasmparser/src/readers/core/functions.rs +++ b/crates/wasmparser/src/readers/core/functions.rs @@ -13,83 +13,5 @@ * limitations under the License. */ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; -use std::ops::Range; - /// A reader for the function section of a WebAssembly module. -#[derive(Clone)] -pub struct FunctionSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> FunctionSectionReader<'a> { - /// Constructs a new `FunctionSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads function type index from the function section. - /// - /// # Examples - /// - /// ``` - /// use wasmparser::FunctionSectionReader; - /// # let data: &[u8] = &[0x01, 0x00]; - /// let mut reader = FunctionSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let ty = reader.read().expect("function type index"); - /// println!("Function type index: {}", ty); - /// } - /// ``` - pub fn read(&mut self) -> Result { - self.reader.read_var_u32() - } -} - -impl<'a> SectionReader for FunctionSectionReader<'a> { - type Item = u32; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for FunctionSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) - } -} - -impl<'a> IntoIterator for FunctionSectionReader<'a> { - type Item = Result; - type IntoIter = SectionIteratorLimited; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } -} +pub type FunctionSectionReader<'a> = crate::SectionLimited<'a, u32>; diff --git a/crates/wasmparser/src/readers/core/globals.rs b/crates/wasmparser/src/readers/core/globals.rs index 49e31c320a..6fd99bc0b8 100644 --- a/crates/wasmparser/src/readers/core/globals.rs +++ b/crates/wasmparser/src/readers/core/globals.rs @@ -13,11 +13,7 @@ * limitations under the License. */ -use crate::{ - BinaryReader, ConstExpr, GlobalType, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, -}; -use std::ops::Range; +use crate::{BinaryReader, ConstExpr, FromReader, GlobalType, Result, SectionLimited}; /// Represents a core WebAssembly global. #[derive(Debug, Copy, Clone)] @@ -29,82 +25,25 @@ pub struct Global<'a> { } /// A reader for the global section of a WebAssembly module. -#[derive(Clone)] -pub struct GlobalSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> GlobalSectionReader<'a> { - /// Constructs a new `GlobalSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(GlobalSectionReader { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } +pub type GlobalSectionReader<'a> = SectionLimited<'a, Global<'a>>; - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the global section. - /// - /// # Examples - /// ``` - /// use wasmparser::GlobalSectionReader; - /// # let data: &[u8] = &[0x01, 0x7F, 0x01, 0x41, 0x90, 0x88, 0x04, 0x0B]; - /// let mut global_reader = GlobalSectionReader::new(data, 0).unwrap(); - /// for _ in 0..global_reader.get_count() { - /// let global = global_reader.read().expect("global"); - /// println!("Global: {:?}", global); - /// let mut init_expr_reader = global.init_expr.get_binary_reader(); - /// let op = init_expr_reader.read_operator().expect("op"); - /// println!("Init const: {:?}", op); - /// } - /// ``` - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let ty = self.reader.read_global_type()?; - let init_expr = self.reader.read_const_expr()?; +impl<'a> FromReader<'a> for Global<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let ty = reader.read()?; + let init_expr = reader.read()?; Ok(Global { ty, init_expr }) } } -impl<'a> SectionReader for GlobalSectionReader<'a> { - type Item = Global<'a>; - fn read(&mut self) -> Result { - GlobalSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - GlobalSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for GlobalSectionReader<'a> { - fn get_count(&self) -> u32 { - GlobalSectionReader::get_count(self) - } -} - -impl<'a> IntoIterator for GlobalSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for GlobalType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(GlobalType { + content_type: reader.read()?, + mutable: match reader.read_u8()? { + 0x00 => false, + 0x01 => true, + _ => bail!(reader.original_position() - 1, "malformed mutability",), + }, + }) } } diff --git a/crates/wasmparser/src/readers/core/imports.rs b/crates/wasmparser/src/readers/core/imports.rs index a8a7a5d5ae..d2a33c89e3 100644 --- a/crates/wasmparser/src/readers/core/imports.rs +++ b/crates/wasmparser/src/readers/core/imports.rs @@ -14,10 +14,9 @@ */ use crate::{ - BinaryReader, GlobalType, MemoryType, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, TableType, TagType, + BinaryReader, ExternalKind, FromReader, GlobalType, MemoryType, Result, SectionLimited, + TableType, TagType, }; -use std::ops::Range; /// Represents a reference to a type definition in a WebAssembly module. #[derive(Debug, Clone, Copy)] @@ -52,78 +51,26 @@ pub struct Import<'a> { } /// A reader for the import section of a WebAssembly module. -#[derive(Clone)] -pub struct ImportSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ImportSectionReader<'a> { - /// Constructs a new `ImportSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the import section. - /// - /// # Examples - /// ``` - /// use wasmparser::ImportSectionReader; - /// let data: &[u8] = &[0x01, 0x01, 0x41, 0x01, 0x66, 0x00, 0x00]; - /// let mut reader = ImportSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let import = reader.read().expect("import"); - /// println!("Import: {:?}", import); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_import() +pub type ImportSectionReader<'a> = SectionLimited<'a, Import<'a>>; + +impl<'a> FromReader<'a> for Import<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(Import { + module: reader.read()?, + name: reader.read()?, + ty: reader.read()?, + }) } } -impl<'a> SectionReader for ImportSectionReader<'a> { - type Item = Import<'a>; - - fn read(&mut self) -> Result { - Self::read(self) - } - - fn eof(&self) -> bool { - self.reader.eof() - } - - fn original_position(&self) -> usize { - Self::original_position(self) - } - - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for ImportSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) - } -} - -impl<'a> IntoIterator for ImportSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for TypeRef { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.read()? { + ExternalKind::Func => TypeRef::Func(reader.read_var_u32()?), + ExternalKind::Table => TypeRef::Table(reader.read()?), + ExternalKind::Memory => TypeRef::Memory(reader.read()?), + ExternalKind::Global => TypeRef::Global(reader.read()?), + ExternalKind::Tag => TypeRef::Tag(reader.read()?), + }) } } diff --git a/crates/wasmparser/src/readers/core/init.rs b/crates/wasmparser/src/readers/core/init.rs index ad7e677add..fcd3bd73c9 100644 --- a/crates/wasmparser/src/readers/core/init.rs +++ b/crates/wasmparser/src/readers/core/init.rs @@ -13,7 +13,7 @@ * limitations under the License. */ -use crate::{BinaryReader, OperatorsReader}; +use crate::{BinaryReader, FromReader, OperatorsReader, Result}; /// Represents an initialization expression. #[derive(Debug, Copy, Clone)] @@ -29,18 +29,23 @@ impl<'a> ConstExpr<'a> { } /// Gets a binary reader for the initialization expression. - pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b> - where - 'a: 'b, - { + pub fn get_binary_reader(&self) -> BinaryReader<'a> { BinaryReader::new_with_offset(self.data, self.offset) } /// Gets an operators reader for the initialization expression. - pub fn get_operators_reader<'b>(&self) -> OperatorsReader<'b> - where - 'a: 'b, - { - OperatorsReader::new(self.data, self.offset) + pub fn get_operators_reader(&self) -> OperatorsReader<'a> { + OperatorsReader::new(self.get_binary_reader()) + } +} + +impl<'a> FromReader<'a> for ConstExpr<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + // FIXME(#188) ideally shouldn't need to skip here + let reader = reader.skip(|r| r.skip_const_expr())?; + Ok(ConstExpr::new( + reader.remaining_buffer(), + reader.original_position(), + )) } } diff --git a/crates/wasmparser/src/readers/core/linking.rs b/crates/wasmparser/src/readers/core/linking.rs deleted file mode 100644 index a619288dd6..0000000000 --- a/crates/wasmparser/src/readers/core/linking.rs +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright 2018 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; -use std::ops::Range; - -/// Represents a linking type. -#[derive(Debug, Copy, Clone)] -pub enum LinkingType { - /// The linking uses a stack pointer. - StackPointer(u32), -} - -/// A reader for the linking custom section of a WebAssembly module. -pub struct LinkingSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> LinkingSectionReader<'a> { - /// Constructs a new `LinkingSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(LinkingSectionReader { reader, count }) - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Reads an item from the section. - pub fn read<'b>(&mut self) -> Result - where - 'a: 'b, - { - self.reader.read_linking_type() - } -} - -impl<'a> SectionReader for LinkingSectionReader<'a> { - type Item = LinkingType; - fn read(&mut self) -> Result { - LinkingSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - LinkingSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for LinkingSectionReader<'a> { - fn get_count(&self) -> u32 { - LinkingSectionReader::get_count(self) - } -} - -impl<'a> IntoIterator for LinkingSectionReader<'a> { - type Item = Result; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } -} diff --git a/crates/wasmparser/src/readers/core/memories.rs b/crates/wasmparser/src/readers/core/memories.rs index 23d1cdcac9..d1941b1cdc 100644 --- a/crates/wasmparser/src/readers/core/memories.rs +++ b/crates/wasmparser/src/readers/core/memories.rs @@ -13,81 +13,44 @@ * limitations under the License. */ -use crate::{ - BinaryReader, MemoryType, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, -}; -use std::ops::Range; +use crate::{BinaryReader, FromReader, MemoryType, Result, SectionLimited}; /// A reader for the memory section of a WebAssembly module. -#[derive(Clone)] -pub struct MemorySectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> MemorySectionReader<'a> { - /// Constructs a new `MemorySectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(MemorySectionReader { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the memory section. - /// - /// # Examples - /// ``` - /// use wasmparser::MemorySectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x02]; - /// let mut memory_reader = MemorySectionReader::new(data, 0).unwrap(); - /// for _ in 0..memory_reader.get_count() { - /// let memory = memory_reader.read().expect("memory"); - /// println!("Memory: {:?}", memory); - /// } - /// ``` - pub fn read(&mut self) -> Result { - self.reader.read_memory_type() - } -} - -impl<'a> SectionReader for MemorySectionReader<'a> { - type Item = MemoryType; - fn read(&mut self) -> Result { - MemorySectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - MemorySectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for MemorySectionReader<'a> { - fn get_count(&self) -> u32 { - MemorySectionReader::get_count(self) - } -} - -impl<'a> IntoIterator for MemorySectionReader<'a> { - type Item = Result; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +pub type MemorySectionReader<'a> = SectionLimited<'a, MemoryType>; + +impl<'a> FromReader<'a> for MemoryType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let pos = reader.original_position(); + let flags = reader.read_u8()?; + if (flags & !0b111) != 0 { + bail!(pos, "invalid memory limits flags"); + } + + let memory64 = flags & 0b100 != 0; + let shared = flags & 0b010 != 0; + let has_max = flags & 0b001 != 0; + Ok(MemoryType { + memory64, + shared, + // FIXME(WebAssembly/memory64#21) as currently specified if the + // `shared` flag is set we should be reading a 32-bit limits field + // here. That seems a bit odd to me at the time of this writing so + // I've taken the liberty of reading a 64-bit limits field in those + // situations. I suspect that this is a typo in the spec, but if not + // we'll need to update this to read a 32-bit limits field when the + // shared flag is set. + initial: if memory64 { + reader.read_var_u64()? + } else { + reader.read_var_u32()?.into() + }, + maximum: if !has_max { + None + } else if memory64 { + Some(reader.read_var_u64()?) + } else { + Some(reader.read_var_u32()?.into()) + }, + }) } } diff --git a/crates/wasmparser/src/readers/core/names.rs b/crates/wasmparser/src/readers/core/names.rs index ef06ef886d..aa8a11dde2 100644 --- a/crates/wasmparser/src/readers/core/names.rs +++ b/crates/wasmparser/src/readers/core/names.rs @@ -13,9 +13,14 @@ * limitations under the License. */ -use crate::{BinaryReader, BinaryReaderError, Result, SectionIterator, SectionReader}; +use crate::{ + BinaryReader, BinaryReaderError, FromReader, Result, SectionLimited, Subsection, Subsections, +}; use std::ops::Range; +/// Represents a name map from the names custom section. +pub type NameMap<'a> = SectionLimited<'a, Naming<'a>>; + /// Represents a name for an index from the names section. #[derive(Debug, Copy, Clone)] pub struct Naming<'a> { @@ -25,221 +30,59 @@ pub struct Naming<'a> { pub name: &'a str, } -/// Represents the type of name. -#[derive(Debug, Copy, Clone)] -pub enum NameType { - /// The name is for a module. - Module, - /// The name is for a function. - Function, - /// The name is for a local. - Local, - /// The name is for a label. - Label, - /// The name is for a type. - Type, - /// The name is for a table. - Table, - /// The name is for a memory. - Memory, - /// The name is for a global. - Global, - /// The name is for an element segment. - Element, - /// The name is for a data segment. - Data, - /// The name is unknown. - /// - /// The value is the unknown section identifier. - Unknown(u8), -} - -/// Represents a single name in the names custom section. -#[derive(Debug, Copy, Clone)] -pub struct SingleName<'a> { - data: &'a [u8], - offset: usize, -} - -impl<'a> SingleName<'a> { - /// Gets the name as a string. - pub fn get_name<'b>(&self) -> Result<&'b str> - where - 'a: 'b, - { - let mut reader = BinaryReader::new_with_offset(self.data, self.offset); - let result = reader.read_string()?; - if !reader.eof() { - return Err(BinaryReaderError::new( - "trailing data at the end of a name", - reader.original_position(), - )); - } - Ok(result) - } - - /// Gets the original position of the name. - pub fn original_position(&self) -> usize { - self.offset - } -} - -/// A reader for direct names in the names custom section. -pub struct NamingReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> NamingReader<'a> { - fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(NamingReader { reader, count }) - } - - fn skip(reader: &mut BinaryReader) -> Result<()> { - let count = reader.read_var_u32()?; - for _ in 0..count { - reader.read_var_u32()?; - reader.skip_string()?; - } - Ok(()) - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads a name from the names custom section. - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let index = self.reader.read_var_u32()?; - let name = self.reader.read_string()?; +impl<'a> FromReader<'a> for Naming<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let index = reader.read_var_u32()?; + let name = reader.read_string()?; Ok(Naming { index, name }) } } -/// Represents a name map from the names custom section. -#[derive(Debug, Copy, Clone)] -pub struct NameMap<'a> { - data: &'a [u8], - offset: usize, -} - -impl<'a> NameMap<'a> { - /// Gets a naming reader for the map. - pub fn get_map<'b>(&self) -> Result> - where - 'a: 'b, - { - NamingReader::new(self.data, self.offset) - } - - /// Gets the original position of the map. - pub fn original_position(&self) -> usize { - self.offset - } -} +/// Represents a reader for indirect names from the names custom section. +pub type IndirectNameMap<'a> = SectionLimited<'a, IndirectNaming<'a>>; /// Represents an indirect name in the names custom section. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub struct IndirectNaming<'a> { /// The indirect index of the name. - pub indirect_index: u32, - data: &'a [u8], - offset: usize, -} - -impl<'a> IndirectNaming<'a> { - /// Gets the naming reader for the indirect name. - pub fn get_map<'b>(&self) -> Result> - where - 'a: 'b, - { - NamingReader::new(self.data, self.offset) - } - - /// Gets the original position of the indirect name. - pub fn original_position(&self) -> usize { - self.offset - } -} - -/// Represents a reader for indirect names from the names custom section. -pub struct IndirectNamingReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> IndirectNamingReader<'a> { - fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(IndirectNamingReader { reader, count }) - } - - /// Gets the count of indirect names. - pub fn get_indirect_count(&self) -> u32 { - self.count - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } + pub index: u32, + /// The map of names within the `index` prior. + pub names: NameMap<'a>, +} + +impl<'a> FromReader<'a> for IndirectNaming<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let index = reader.read_var_u32()?; + + // Skip the `NameMap` manually here. + // + // FIXME(#188) shouldn't need to skip here + let names = reader.skip(|reader| { + let count = reader.read_var_u32()?; + for _ in 0..count { + reader.read_var_u32()?; + reader.skip_string()?; + } + Ok(()) + })?; - /// Reads an indirect name from the reader. - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let index = self.reader.read_var_u32()?; - let start = self.reader.position; - NamingReader::skip(&mut self.reader)?; - let end = self.reader.position; Ok(IndirectNaming { - indirect_index: index, - data: &self.reader.buffer[start..end], - offset: self.reader.original_offset + start, + index, + names: NameMap::new(names.remaining_buffer(), names.original_position())?, }) } } -/// Represents an indirect name map. -#[derive(Debug, Copy, Clone)] -pub struct IndirectNameMap<'a> { - data: &'a [u8], - offset: usize, -} - -impl<'a> IndirectNameMap<'a> { - /// Gets an indirect naming reader for the map. - pub fn get_indirect_map<'b>(&self) -> Result> - where - 'a: 'b, - { - IndirectNamingReader::new(self.data, self.offset) - } - - /// Gets an original position of the map. - pub fn original_position(&self) -> usize { - self.offset - } -} - /// Represents a name read from the names custom section. -#[derive(Debug, Clone)] +#[derive(Clone)] pub enum Name<'a> { /// The name is for the module. - Module(SingleName<'a>), + Module { + /// The specified name. + name: &'a str, + /// The byte range that `name` occupies in the original binary. + name_range: Range, + }, /// The name is for the functions. Function(NameMap<'a>), /// The name is for the function locals. @@ -271,92 +114,40 @@ pub enum Name<'a> { } /// A reader for the name custom section of a WebAssembly module. -pub struct NameSectionReader<'a> { - reader: BinaryReader<'a>, -} - -impl<'a> NameSectionReader<'a> { - /// Constructs a new `NameSectionReader` from the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - Ok(NameSectionReader { - reader: BinaryReader::new_with_offset(data, offset), - }) - } - - fn verify_section_end(&self, end: usize) -> Result<()> { - if self.reader.buffer.len() < end { - return Err(BinaryReaderError::new( - "name entry extends past end of the code section", - self.reader.original_offset + self.reader.buffer.len(), - )); - } - Ok(()) - } - - /// Determines if the reader is at the end of the section. - pub fn eof(&self) -> bool { - self.reader.eof() - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Reads a name from the section. - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let ty = self.reader.read_name_type()?; - let payload_len = self.reader.read_var_u32()? as usize; - let payload_start = self.reader.position; - let payload_end = payload_start + payload_len; - self.verify_section_end(payload_end)?; - let offset = self.reader.original_offset + payload_start; - let data = &self.reader.buffer[payload_start..payload_end]; - self.reader.skip_to(payload_end); - Ok(match ty { - NameType::Module => Name::Module(SingleName { data, offset }), - NameType::Function => Name::Function(NameMap { data, offset }), - NameType::Local => Name::Local(IndirectNameMap { data, offset }), - NameType::Label => Name::Label(IndirectNameMap { data, offset }), - NameType::Type => Name::Type(NameMap { data, offset }), - NameType::Table => Name::Table(NameMap { data, offset }), - NameType::Memory => Name::Memory(NameMap { data, offset }), - NameType::Global => Name::Global(NameMap { data, offset }), - NameType::Element => Name::Element(NameMap { data, offset }), - NameType::Data => Name::Data(NameMap { data, offset }), - NameType::Unknown(ty) => Name::Unknown { +pub type NameSectionReader<'a> = Subsections<'a, Name<'a>>; + +impl<'a> Subsection<'a> for Name<'a> { + fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result { + let data = reader.remaining_buffer(); + let offset = reader.original_position(); + Ok(match id { + 0 => { + let name = reader.read_string()?; + if !reader.eof() { + return Err(BinaryReaderError::new( + "trailing data at the end of a name", + reader.original_position(), + )); + } + Name::Module { + name, + name_range: offset..offset + reader.position, + } + } + 1 => Name::Function(NameMap::new(data, offset)?), + 2 => Name::Local(IndirectNameMap::new(data, offset)?), + 3 => Name::Label(IndirectNameMap::new(data, offset)?), + 4 => Name::Type(NameMap::new(data, offset)?), + 5 => Name::Table(NameMap::new(data, offset)?), + 6 => Name::Memory(NameMap::new(data, offset)?), + 7 => Name::Global(NameMap::new(data, offset)?), + 8 => Name::Element(NameMap::new(data, offset)?), + 9 => Name::Data(NameMap::new(data, offset)?), + ty => Name::Unknown { ty, data, - range: offset..offset + payload_len, + range: offset..offset + data.len(), }, }) } } - -impl<'a> SectionReader for NameSectionReader<'a> { - type Item = Name<'a>; - fn read(&mut self) -> Result { - NameSectionReader::read(self) - } - fn eof(&self) -> bool { - NameSectionReader::eof(self) - } - fn original_position(&self) -> usize { - NameSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> IntoIterator for NameSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIterator>; - - fn into_iter(self) -> Self::IntoIter { - SectionIterator::new(self) - } -} diff --git a/crates/wasmparser/src/readers/core/operators.rs b/crates/wasmparser/src/readers/core/operators.rs index 0448927d70..d1312c259f 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -33,6 +33,12 @@ pub enum BlockType { pub struct MemArg { /// Alignment, stored as `n` where the actual alignment is `2^n` pub align: u8, + /// Maximum alignment, stored as `n` where the actual alignment is `2^n`. + /// + /// Note that this field is not actually read from the binary format, it + /// will be a constant depending on which instruction this `MemArg` is a + /// payload for. + pub max_align: u8, /// A fixed byte-offset that this memory immediate specifies. /// /// Note that the memory64 proposal can specify a full 64-bit byte offset @@ -123,13 +129,8 @@ pub struct OperatorsReader<'a> { } impl<'a> OperatorsReader<'a> { - pub(crate) fn new<'b>(data: &'a [u8], offset: usize) -> OperatorsReader<'b> - where - 'a: 'b, - { - OperatorsReader { - reader: BinaryReader::new_with_offset(data, offset), - } + pub(crate) fn new(reader: BinaryReader<'a>) -> OperatorsReader<'a> { + OperatorsReader { reader } } /// Determines if the reader is at the end of the operators. @@ -165,18 +166,12 @@ impl<'a> OperatorsReader<'a> { } /// Reads an operator from the reader. - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { + pub fn read(&mut self) -> Result> { self.reader.read_operator() } /// Converts to an iterator of operators paired with offsets. - pub fn into_iter_with_offsets<'b>(self) -> OperatorsIteratorWithOffsets<'b> - where - 'a: 'b, - { + pub fn into_iter_with_offsets(self) -> OperatorsIteratorWithOffsets<'a> { OperatorsIteratorWithOffsets { reader: self, err: false, @@ -184,19 +179,15 @@ impl<'a> OperatorsReader<'a> { } /// Reads an operator with its offset. - pub fn read_with_offset<'b>(&mut self) -> Result<(Operator<'b>, usize)> - where - 'a: 'b, - { + pub fn read_with_offset(&mut self) -> Result<(Operator<'a>, usize)> { let pos = self.reader.original_position(); Ok((self.read()?, pos)) } - /// Visits an operator with its offset. - pub fn visit_with_offset( - &mut self, - visitor: &mut T, - ) -> Result<>::Output> + /// Visit a single operator with the specified [`VisitOperator`] instance. + /// + /// See [`BinaryReader::visit_operator`] for more information. + pub fn visit_operator(&mut self, visitor: &mut T) -> Result<>::Output> where T: VisitOperator<'a>, { @@ -220,9 +211,9 @@ impl<'a> IntoIterator for OperatorsReader<'a> { /// use wasmparser::{Operator, CodeSectionReader, Result}; /// # let data: &[u8] = &[ /// # 0x01, 0x03, 0x00, 0x01, 0x0b]; - /// let mut code_reader = CodeSectionReader::new(data, 0).unwrap(); - /// for _ in 0..code_reader.get_count() { - /// let body = code_reader.read().expect("function body"); + /// let code_reader = CodeSectionReader::new(data, 0).unwrap(); + /// for body in code_reader { + /// let body = body.expect("function body"); /// let mut op_reader = body.get_operators_reader().expect("op reader"); /// let ops = op_reader.into_iter().collect::>>().expect("ops"); /// assert!( @@ -275,9 +266,9 @@ impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { /// use wasmparser::{Operator, CodeSectionReader, Result}; /// # let data: &[u8] = &[ /// # 0x01, 0x03, 0x00, /* offset = 23 */ 0x01, 0x0b]; - /// let mut code_reader = CodeSectionReader::new(data, 20).unwrap(); - /// for _ in 0..code_reader.get_count() { - /// let body = code_reader.read().expect("function body"); + /// let code_reader = CodeSectionReader::new(data, 20).unwrap(); + /// for body in code_reader { + /// let body = body.expect("function body"); /// let mut op_reader = body.get_operators_reader().expect("op reader"); /// let ops = op_reader.into_iter_with_offsets().collect::>>().expect("ops"); /// assert!( @@ -300,7 +291,7 @@ impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { macro_rules! define_visit_operator { ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { $( - fn $visit(&mut self, offset: usize $($(,$arg: $argty)*)?) -> Self::Output; + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output; )* } } @@ -319,12 +310,12 @@ pub trait VisitOperator<'a> { /// critical use cases. For performance critical implementations users /// are recommended to directly use the respective `visit` methods or /// implement [`VisitOperator`] on their own. - fn visit_operator(&mut self, offset: usize, op: &Operator<'a>) -> Self::Output { + fn visit_operator(&mut self, op: &Operator<'a>) -> Self::Output { macro_rules! visit_operator { ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { match op { $( - Operator::$op $({ $($arg),* })? => self.$visit(offset, $($($arg.clone()),*)?), + Operator::$op $({ $($arg),* })? => self.$visit($($($arg.clone()),*)?), )* } } @@ -335,3 +326,29 @@ pub trait VisitOperator<'a> { for_each_operator!(define_visit_operator); } + +macro_rules! define_visit_operator_delegate { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + $( + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { + V::$visit(&mut *self, $($($arg),*)?) + } + )* + } +} + +impl<'a, 'b, V: VisitOperator<'a> + ?Sized> VisitOperator<'a> for &'b mut V { + type Output = V::Output; + fn visit_operator(&mut self, op: &Operator<'a>) -> Self::Output { + V::visit_operator(*self, op) + } + for_each_operator!(define_visit_operator_delegate); +} + +impl<'a, V: VisitOperator<'a> + ?Sized> VisitOperator<'a> for Box { + type Output = V::Output; + fn visit_operator(&mut self, op: &Operator<'a>) -> Self::Output { + V::visit_operator(&mut *self, op) + } + for_each_operator!(define_visit_operator_delegate); +} diff --git a/crates/wasmparser/src/readers/core/producers.rs b/crates/wasmparser/src/readers/core/producers.rs index 4999aa45be..050cb4966c 100644 --- a/crates/wasmparser/src/readers/core/producers.rs +++ b/crates/wasmparser/src/readers/core/producers.rs @@ -13,199 +13,71 @@ * limitations under the License. */ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; -use std::ops::Range; +use crate::{BinaryReader, FromReader, Result, SectionLimited}; -/// Represents a field value in the producers custom section. -#[derive(Debug, Copy, Clone)] -pub struct ProducersFieldValue<'a> { - /// The field name. - pub name: &'a str, - /// The field version. - pub version: &'a str, -} - -/// A reader for fields in the producers custom section. -pub struct ProducersFieldValuesReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> ProducersFieldValuesReader<'a> { - /// Gets the count of items in the reader. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - fn skip(reader: &mut BinaryReader, values_count: u32) -> Result<()> { - for _ in 0..values_count { - reader.skip_string()?; - reader.skip_string()?; - } - Ok(()) - } - - /// Reads a field from the reader. - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let name = self.reader.read_string()?; - let version = self.reader.read_string()?; - Ok(ProducersFieldValue { name, version }) - } -} - -impl<'a> IntoIterator for ProducersFieldValuesReader<'a> { - type Item = Result>; - type IntoIter = ProducersFieldValuesIterator<'a>; - fn into_iter(self) -> Self::IntoIter { - let count = self.count; - ProducersFieldValuesIterator { - reader: self, - left: count, - err: false, - } - } -} - -/// An iterator over fields in the producers custom section. -pub struct ProducersFieldValuesIterator<'a> { - reader: ProducersFieldValuesReader<'a>, - left: u32, - err: bool, -} - -impl<'a> Iterator for ProducersFieldValuesIterator<'a> { - type Item = Result>; - fn next(&mut self) -> Option { - if self.err || self.left == 0 { - return None; - } - let result = self.reader.read(); - self.err = result.is_err(); - self.left -= 1; - Some(result) - } - fn size_hint(&self) -> (usize, Option) { - let count = self.reader.get_count() as usize; - (count, Some(count)) - } -} +/// A reader for the producers custom section of a WebAssembly module. +/// +/// # Examples +/// +/// ``` +/// # let data: &[u8] = &[0x01, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, +/// # 0x02, 0x03, 0x77, 0x61, 0x74, 0x01, 0x31, 0x01, 0x43, 0x03, 0x39, 0x2e, 0x30]; +/// use wasmparser::{ProducersSectionReader, ProducersFieldValue, Result}; +/// let reader = ProducersSectionReader::new(data, 0).expect("producers reader"); +/// let field = reader.into_iter().next().unwrap().expect("producers field"); +/// assert!(field.name == "language"); +/// let value = field.values.into_iter().collect::>>().expect("values"); +/// assert!(value.len() == 2); +/// assert!(value[0].name == "wat" && value[0].version == "1"); +/// assert!(value[1].name == "C" && value[1].version == "9.0"); +/// ``` +pub type ProducersSectionReader<'a> = SectionLimited<'a, ProducersField<'a>>; /// A field from the producers custom section. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub struct ProducersField<'a> { /// The name of the field. pub name: &'a str, - values_count: u32, - values_data: &'a [u8], - values_offset: usize, -} - -impl<'a> ProducersField<'a> { - /// Gets a reader of values for the field. - pub fn get_producer_field_values_reader<'b>(&self) -> Result> - where - 'a: 'b, - { - Ok(ProducersFieldValuesReader { - reader: BinaryReader::new_with_offset(self.values_data, self.values_offset), - count: self.values_count, - }) - } -} - -/// A reader for the producers custom section of a WebAssembly module. -pub struct ProducersSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, + /// The values specified for this field + pub values: SectionLimited<'a, ProducersFieldValue<'a>>, } -impl<'a> ProducersSectionReader<'a> { - /// Creates reader for the producers section. - /// - /// # Examples - /// ``` - /// # let data: &[u8] = &[0x01, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, - /// # 0x02, 0x03, 0x77, 0x61, 0x74, 0x01, 0x31, 0x01, 0x43, 0x03, 0x39, 0x2e, 0x30]; - /// use wasmparser::{ProducersSectionReader, ProducersFieldValue, Result}; - /// let mut reader = ProducersSectionReader::new(data, 0).expect("producers reader"); - /// let field = reader.read().expect("producers field"); - /// assert!(field.name == "language"); - /// let mut values_reader = field.get_producer_field_values_reader().expect("values reader"); - /// let value = values_reader.into_iter().collect::>>().expect("values"); - /// assert!(value.len() == 2); - /// assert!(value[0].name == "wat" && value[0].version == "1"); - /// assert!(value[1].name == "C" && value[1].version == "9.0"); - /// ``` - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(ProducersSectionReader { reader, count }) - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the reader. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads an item from the reader. - pub fn read<'b>(&mut self) -> Result> - where - 'a: 'b, - { - let name = self.reader.read_string()?; - let values_count = self.reader.read_var_u32()?; - let values_start = self.reader.position; - ProducersFieldValuesReader::skip(&mut self.reader, values_count)?; - let values_end = self.reader.position; +impl<'a> FromReader<'a> for ProducersField<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let offset = reader.original_position(); + let name = reader.read_string()?; + match name { + "language" | "sdk" | "processed-by" => {} + _ => bail!(offset, "invalid producers field name: `{name}`"), + } + let values = reader.skip(|reader| { + // FIXME(#188) ideally shouldn't need to skip here + for _ in 0..reader.read_var_u32()? { + reader.skip_string()?; + reader.skip_string()?; + } + Ok(()) + })?; Ok(ProducersField { name, - values_count, - values_data: &self.reader.buffer[values_start..values_end], - values_offset: self.reader.original_offset + values_start, + values: SectionLimited::new(values.remaining_buffer(), values.original_position())?, }) } } -impl<'a> SectionReader for ProducersSectionReader<'a> { - type Item = ProducersField<'a>; - fn read(&mut self) -> Result { - ProducersSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - ProducersSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for ProducersSectionReader<'a> { - fn get_count(&self) -> u32 { - ProducersSectionReader::get_count(self) - } +/// Represents a field value in the producers custom section. +#[derive(Debug, Copy, Clone)] +pub struct ProducersFieldValue<'a> { + /// The field name. + pub name: &'a str, + /// The field version. + pub version: &'a str, } -impl<'a> IntoIterator for ProducersSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for ProducersFieldValue<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let name = reader.read_string()?; + let version = reader.read_string()?; + Ok(ProducersFieldValue { name, version }) } } diff --git a/crates/wasmparser/src/readers/core/relocs.rs b/crates/wasmparser/src/readers/core/relocs.rs deleted file mode 100644 index 29a9e33faf..0000000000 --- a/crates/wasmparser/src/readers/core/relocs.rs +++ /dev/null @@ -1,198 +0,0 @@ -/* Copyright 2018 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; -use std::ops::Range; - -/// Represents a relocation type. -#[derive(Debug, Copy, Clone)] -#[allow(missing_docs)] -pub enum RelocType { - FunctionIndexLEB, - TableIndexSLEB, - TableIndexI32, - GlobalAddrLEB, - GlobalAddrSLEB, - GlobalAddrI32, - TypeIndexLEB, - GlobalIndexLEB, -} - -/// Represents known custom section kinds. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub enum CustomSectionKind { - /// The custom section is not known. - Unknown, - /// The name custom section. - Name, - /// The producers custom section. - Producers, - /// The source mapping URL custom section. - SourceMappingURL, - /// The reloc custom section. - Reloc, - /// The linking custom section. - Linking, -} - -/// Section code as defined [here]. -/// -/// [here]: https://webassembly.github.io/spec/core/binary/modules.html#sections -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub enum SectionCode<'a> { - /// The custom section. - Custom { - /// The name of the custom section. - name: &'a str, - /// The kind of the custom section. - kind: CustomSectionKind, - }, - /// The type section. - Type, - /// The import section. - Import, - /// The function section. - Function, - /// The table section. - Table, - /// The memory section. - Memory, - /// The global section. - Global, - /// The export section. - Export, - /// The start section. - Start, - /// The element section. - Element, - /// The code section. - Code, - /// The data section. - Data, - /// The passive data count section. - DataCount, - /// The tag section. - Tag, -} - -/// Represents a relocation entry. -#[derive(Debug, Copy, Clone)] -pub struct Reloc { - /// The relocation type. - pub ty: RelocType, - /// The relocation offset. - pub offset: u32, - /// The relocation index. - pub index: u32, - /// The relocation addend. - pub addend: Option, -} - -/// A reader for the relocations custom section of a WebAssembly module. -pub struct RelocSectionReader<'a> { - reader: BinaryReader<'a>, - section_code: SectionCode<'a>, - count: u32, -} - -impl<'a> RelocSectionReader<'a> { - /// Constructs a new `RelocSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - - let section_id_position = reader.position; - let section_id = reader.read_u7()?; - let section_code = reader.read_section_code(section_id, section_id_position)?; - - let count = reader.read_var_u32()?; - Ok(RelocSectionReader { - reader, - section_code, - count, - }) - } - - /// Gets a count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Gets the section code from the section. - pub fn get_section_code<'b>(&self) -> SectionCode<'b> - where - 'a: 'b, - { - self.section_code - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Reads an item from the reader. - pub fn read(&mut self) -> Result { - let ty = self.reader.read_reloc_type()?; - let offset = self.reader.read_var_u32()?; - let index = self.reader.read_var_u32()?; - let addend = match ty { - RelocType::FunctionIndexLEB - | RelocType::TableIndexSLEB - | RelocType::TableIndexI32 - | RelocType::TypeIndexLEB - | RelocType::GlobalIndexLEB => None, - RelocType::GlobalAddrLEB | RelocType::GlobalAddrSLEB | RelocType::GlobalAddrI32 => { - Some(self.reader.read_var_u32()?) - } - }; - Ok(Reloc { - ty, - offset, - index, - addend, - }) - } -} - -impl<'a> SectionReader for RelocSectionReader<'a> { - type Item = Reloc; - fn read(&mut self) -> Result { - RelocSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - RelocSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for RelocSectionReader<'a> { - fn get_count(&self) -> u32 { - RelocSectionReader::get_count(self) - } -} - -impl<'a> IntoIterator for RelocSectionReader<'a> { - type Item = Result; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } -} diff --git a/crates/wasmparser/src/readers/core/tables.rs b/crates/wasmparser/src/readers/core/tables.rs index 3121b5fe98..211e415efd 100644 --- a/crates/wasmparser/src/readers/core/tables.rs +++ b/crates/wasmparser/src/readers/core/tables.rs @@ -13,81 +13,75 @@ * limitations under the License. */ -use crate::{ - BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TableType, -}; -use std::ops::Range; +use crate::{BinaryReader, ConstExpr, FromReader, Result, SectionLimited, TableType}; /// A reader for the table section of a WebAssembly module. -#[derive(Clone)] -pub struct TableSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> TableSectionReader<'a> { - /// Constructs a new `TableSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(TableSectionReader { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } +pub type TableSectionReader<'a> = SectionLimited<'a, Table<'a>>; - /// Reads content of the table section. - /// - /// # Examples - /// ``` - /// use wasmparser::TableSectionReader; - /// - /// # let data: &[u8] = &[0x01, 0x70, 0x01, 0x01, 0x01]; - /// let mut table_reader = TableSectionReader::new(data, 0).unwrap(); - /// for _ in 0..table_reader.get_count() { - /// let table = table_reader.read().expect("table"); - /// println!("Table: {:?}", table); - /// } - /// ``` - pub fn read(&mut self) -> Result { - self.reader.read_table_type() - } +/// Type information about a table defined in the table section of a WebAssembly +/// module. +#[derive(Debug)] +pub struct Table<'a> { + /// The type of this table, including its element type and its limits. + pub ty: TableType, + /// The initialization expression for the table. + pub init: TableInit<'a>, } -impl<'a> SectionReader for TableSectionReader<'a> { - type Item = TableType; - fn read(&mut self) -> Result { - TableSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - TableSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } +/// Different modes of initializing a table. +#[derive(Debug)] +pub enum TableInit<'a> { + /// The table is initialized to all null elements. + RefNull, + /// Each element in the table is initialized with the specified constant + /// expression. + Expr(ConstExpr<'a>), } -impl<'a> SectionWithLimitedItems for TableSectionReader<'a> { - fn get_count(&self) -> u32 { - TableSectionReader::get_count(self) +impl<'a> FromReader<'a> for Table<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let has_init_expr = if reader.peek()? == 0x40 { + reader.read_u8()?; + true + } else { + false + }; + + if has_init_expr { + if reader.read_u8()? != 0x00 { + bail!(reader.original_position() - 1, "invalid table encoding"); + } + } + + let ty = reader.read::()?; + let init = if has_init_expr { + TableInit::Expr(reader.read()?) + } else { + TableInit::RefNull + }; + Ok(Table { ty, init }) } } -impl<'a> IntoIterator for TableSectionReader<'a> { - type Item = Result; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for TableType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let element_type = reader.read()?; + let has_max = match reader.read_u8()? { + 0x00 => false, + 0x01 => true, + _ => { + bail!( + reader.original_position() - 1, + "invalid table resizable limits flags", + ) + } + }; + let initial = reader.read()?; + let maximum = if has_max { Some(reader.read()?) } else { None }; + Ok(TableType { + element_type, + initial, + maximum, + }) } } diff --git a/crates/wasmparser/src/readers/core/tags.rs b/crates/wasmparser/src/readers/core/tags.rs index fd40779791..746b3ea7ac 100644 --- a/crates/wasmparser/src/readers/core/tags.rs +++ b/crates/wasmparser/src/readers/core/tags.rs @@ -13,80 +13,20 @@ * limitations under the License. */ -use crate::{ - BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, TagType, -}; -use std::ops::Range; +use crate::{BinaryReader, FromReader, Result, SectionLimited, TagKind, TagType}; /// A reader for the tags section of a WebAssembly module. -#[derive(Clone)] -pub struct TagSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> TagSectionReader<'a> { - /// Constructs a new `TagSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result> { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(TagSectionReader { reader, count }) - } - - /// Gets the original position of the section reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets the count of items in the section. - pub fn get_count(&self) -> u32 { - self.count - } - - /// Reads content of the tag section. - /// - /// # Examples - /// ``` - /// use wasmparser::TagSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x01]; - /// let mut reader = TagSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let ty = reader.read().expect("tag type"); - /// println!("Tag type: {:?}", ty); - /// } - /// ``` - pub fn read(&mut self) -> Result { - self.reader.read_tag_type() - } -} - -impl<'a> SectionReader for TagSectionReader<'a> { - type Item = TagType; - fn read(&mut self) -> Result { - TagSectionReader::read(self) - } - fn eof(&self) -> bool { - self.reader.eof() - } - fn original_position(&self) -> usize { - TagSectionReader::original_position(self) - } - fn range(&self) -> Range { - self.reader.range() - } -} - -impl<'a> SectionWithLimitedItems for TagSectionReader<'a> { - fn get_count(&self) -> u32 { - TagSectionReader::get_count(self) - } -} - -impl<'a> IntoIterator for TagSectionReader<'a> { - type Item = Result; - type IntoIter = SectionIteratorLimited>; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +pub type TagSectionReader<'a> = SectionLimited<'a, TagType>; + +impl<'a> FromReader<'a> for TagType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let attribute = reader.read_u8()?; + if attribute != 0 { + bail!(reader.original_position() - 1, "invalid tag attributes"); + } + Ok(TagType { + kind: TagKind::Exception, + func_type_idx: reader.read_var_u32()?, + }) } } diff --git a/crates/wasmparser/src/readers/core/types.rs b/crates/wasmparser/src/readers/core/types.rs index 974c197321..87c0002998 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -13,9 +13,14 @@ * limitations under the License. */ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; -use std::fmt::Debug; -use std::ops::Range; +use std::fmt::{self, Debug, Write}; +use std::slice; + +use crate::limits::{ + MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS, MAX_WASM_STRUCT_FIELDS, + MAX_WASM_SUPERTYPES, MAX_WASM_TYPES, +}; +use crate::{BinaryReader, BinaryReaderError, FromReader, Result, SectionLimited}; /// Represents the types of values in a WebAssembly module. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -30,27 +35,806 @@ pub enum ValType { F64, /// The value type is v128. V128, - /// The value type is a function reference. - FuncRef, - /// The value type is an extern reference. - ExternRef, + /// The value type is a reference. + Ref(RefType), +} + +/// Represents storage types introduced in the GC spec for array and struct fields. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum StorageType { + /// The storage type is i8. + I8, + /// The storage type is i16. + I16, + /// The storage type is a value type. + Val(ValType), +} + +// The size of `ValType` is performance sensitive. +const _: () = { + assert!(std::mem::size_of::() == 4); +}; + +pub(crate) trait Matches { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType; +} + +impl From for ValType { + fn from(ty: RefType) -> ValType { + ValType::Ref(ty) + } } impl ValType { + /// Alias for the wasm `funcref` type. + pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF); + + /// Alias for the wasm `externref` type. + pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF); + /// Returns whether this value type is a "reference type". /// /// Only reference types are allowed in tables, for example, and with some /// instructions. Current reference types include `funcref` and `externref`. pub fn is_reference_type(&self) -> bool { - matches!(self, ValType::FuncRef | ValType::ExternRef) + matches!(self, ValType::Ref(_)) + } + + /// Whether the type is defaultable, i.e. it is not a non-nullable reference + /// type. + pub fn is_defaultable(&self) -> bool { + match *self { + Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true, + Self::Ref(rt) => rt.is_nullable(), + } + } + + pub(crate) fn is_valtype_byte(byte: u8) -> bool { + match byte { + 0x7F | 0x7E | 0x7D | 0x7C | 0x7B | 0x70 | 0x6F | 0x64 | 0x63 | 0x6E | 0x71 | 0x72 + | 0x73 | 0x6D | 0x6B | 0x6A | 0x6C => true, + _ => false, + } } } -/// Represents a type in a WebAssembly module. +impl Matches for ValType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + match (self, other) { + (Self::Ref(r1), Self::Ref(r2)) => r1.matches(r2, type_at), + (a, b) => a == b, + } + } +} + +impl<'a> FromReader<'a> for StorageType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + match reader.peek()? { + 0x78 => { + reader.position += 1; + Ok(StorageType::I8) + } + 0x77 => { + reader.position += 1; + Ok(StorageType::I16) + } + _ => Ok(StorageType::Val(reader.read()?)), + } + } +} + +impl<'a> FromReader<'a> for ValType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + match reader.peek()? { + 0x7F => { + reader.position += 1; + Ok(ValType::I32) + } + 0x7E => { + reader.position += 1; + Ok(ValType::I64) + } + 0x7D => { + reader.position += 1; + Ok(ValType::F32) + } + 0x7C => { + reader.position += 1; + Ok(ValType::F64) + } + 0x7B => { + reader.position += 1; + Ok(ValType::V128) + } + 0x70 | 0x6F | 0x64 | 0x63 | 0x6E | 0x71 | 0x72 | 0x73 | 0x6D | 0x6B | 0x6A | 0x6C => { + Ok(ValType::Ref(reader.read()?)) + } + _ => bail!(reader.original_position(), "invalid value type"), + } + } +} + +impl fmt::Display for ValType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + ValType::I32 => "i32", + ValType::I64 => "i64", + ValType::F32 => "f32", + ValType::F64 => "f64", + ValType::V128 => "v128", + ValType::Ref(r) => return fmt::Display::fmt(r, f), + }; + f.write_str(s) + } +} + +/// A reference type. +/// +/// The reference types proposal first introduced `externref` and `funcref`. +/// +/// The function references proposal introduced typed function references. +/// +/// The GC proposal introduces heap types: any, eq, i31, struct, array, nofunc, noextern, none. +// +// RefType is a bit-packed enum that fits in a `u24` aka `[u8; 3]`. +// Note that its content is opaque (and subject to change), but its API is stable. +// +// It has the following internal structure: +// +// ``` +// [nullable:u1] [indexed==1:u1] [kind:u2] [index:u20] +// [nullable:u1] [indexed==0:u1] [type:u4] [(unused):u18] +// ``` +// +// Where +// +// - `nullable` determines nullability of the ref +// +// - `indexed` determines if the ref is of a dynamically defined type with an +// index (encoded in a following bit-packing section) or of a known fixed type +// +// - `kind` determines what kind of indexed type the index is pointing to: +// +// ``` +// 10 = struct +// 11 = array +// 01 = function +// ``` +// +// - `index` is the type index +// +// - `type` is an enumeration of known types: +// +// ``` +// 1111 = any +// +// 1101 = eq +// 1000 = i31 +// 1001 = struct +// 1100 = array +// +// 0101 = func +// 0100 = nofunc +// +// 0011 = extern +// 0010 = noextern +// +// 0000 = none +// ``` +// +// - `(unused)` is unused sequence of bits +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct RefType([u8; 3]); + +impl Debug for RefType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match (self.is_nullable(), self.heap_type()) { + (true, HeapType::Any) => write!(f, "anyref"), + (false, HeapType::Any) => write!(f, "(ref any)"), + (true, HeapType::None) => write!(f, "nullref"), + (false, HeapType::None) => write!(f, "(ref none)"), + (true, HeapType::NoExtern) => write!(f, "nullexternref"), + (false, HeapType::NoExtern) => write!(f, "(ref noextern)"), + (true, HeapType::NoFunc) => write!(f, "nullfuncref"), + (false, HeapType::NoFunc) => write!(f, "(ref nofunc)"), + (true, HeapType::Eq) => write!(f, "eqref"), + (false, HeapType::Eq) => write!(f, "(ref eq)"), + (true, HeapType::Struct) => write!(f, "structref"), + (false, HeapType::Struct) => write!(f, "(ref struct)"), + (true, HeapType::Array) => write!(f, "arrayref"), + (false, HeapType::Array) => write!(f, "(ref array)"), + (true, HeapType::I31) => write!(f, "i31ref"), + (false, HeapType::I31) => write!(f, "(ref i31)"), + (true, HeapType::Extern) => write!(f, "externref"), + (false, HeapType::Extern) => write!(f, "(ref extern)"), + (true, HeapType::Func) => write!(f, "funcref"), + (false, HeapType::Func) => write!(f, "(ref func)"), + (true, HeapType::Indexed(idx)) => write!(f, "(ref null {idx})"), + (false, HeapType::Indexed(idx)) => write!(f, "(ref {idx})"), + } + } +} + +// Static assert that we can fit indices up to `MAX_WASM_TYPES` inside `RefType`. +const _: () = { + const fn can_roundtrip_index(index: u32) -> bool { + assert!(RefType::can_represent_type_index(index)); + let rt = match RefType::indexed_func(true, index) { + Some(rt) => rt, + None => panic!(), + }; + assert!(rt.is_nullable()); + let actual_index = match rt.type_index() { + Some(i) => i, + None => panic!(), + }; + actual_index == index + } + + assert!(can_roundtrip_index(crate::limits::MAX_WASM_TYPES as u32)); + assert!(can_roundtrip_index(0b00000000_00001111_00000000_00000000)); + assert!(can_roundtrip_index(0b00000000_00000000_11111111_00000000)); + assert!(can_roundtrip_index(0b00000000_00000000_00000000_11111111)); + assert!(can_roundtrip_index(0)); +}; + +impl RefType { + const NULLABLE_BIT: u32 = 1 << 23; // bit #23 + const INDEXED_BIT: u32 = 1 << 22; // bit #22 + + const TYPE_MASK: u32 = 0b1111 << 18; // 4 bits #21-#18 (if `indexed == 0`) + const ANY_TYPE: u32 = 0b1111 << 18; + const EQ_TYPE: u32 = 0b1101 << 18; + const I31_TYPE: u32 = 0b1000 << 18; + const STRUCT_TYPE: u32 = 0b1001 << 18; + const ARRAY_TYPE: u32 = 0b1100 << 18; + const FUNC_TYPE: u32 = 0b0101 << 18; + const NOFUNC_TYPE: u32 = 0b0100 << 18; + const EXTERN_TYPE: u32 = 0b0011 << 18; + const NOEXTERN_TYPE: u32 = 0b0010 << 18; + const NONE_TYPE: u32 = 0b0000 << 18; + + const KIND_MASK: u32 = 0b11 << 20; // 2 bits #21-#20 (if `indexed == 1`) + const STRUCT_KIND: u32 = 0b10 << 20; + const ARRAY_KIND: u32 = 0b11 << 20; + const FUNC_KIND: u32 = 0b01 << 20; + + const INDEX_MASK: u32 = (1 << 20) - 1; // 20 bits #19-#0 (if `indexed == 1`) + + /// A nullable untyped function reference aka `(ref null func)` aka + /// `funcref` aka `anyfunc`. + pub const FUNCREF: Self = RefType::FUNC.nullable(); + + /// A nullable reference to an extern object aka `(ref null extern)` aka + /// `externref`. + pub const EXTERNREF: Self = RefType::EXTERN.nullable(); + + /// A non-nullable untyped function reference aka `(ref func)`. + pub const FUNC: Self = RefType::from_u32(Self::FUNC_TYPE); + + /// A non-nullable reference to an extern object aka `(ref extern)`. + pub const EXTERN: Self = RefType::from_u32(Self::EXTERN_TYPE); + + /// A non-nullable reference to any object aka `(ref any)`. + pub const ANY: Self = RefType::from_u32(Self::ANY_TYPE); + + /// A non-nullable reference to no object aka `(ref none)`. + pub const NONE: Self = RefType::from_u32(Self::NONE_TYPE); + + /// A non-nullable reference to a noextern object aka `(ref noextern)`. + pub const NOEXTERN: Self = RefType::from_u32(Self::NOEXTERN_TYPE); + + /// A non-nullable reference to a nofunc object aka `(ref nofunc)`. + pub const NOFUNC: Self = RefType::from_u32(Self::NOFUNC_TYPE); + + /// A non-nullable reference to an eq object aka `(ref eq)`. + pub const EQ: Self = RefType::from_u32(Self::EQ_TYPE); + + /// A non-nullable reference to a struct aka `(ref struct)`. + pub const STRUCT: Self = RefType::from_u32(Self::STRUCT_TYPE); + + /// A non-nullable reference to an array aka `(ref array)`. + pub const ARRAY: Self = RefType::from_u32(Self::ARRAY_TYPE); + + /// A non-nullable reference to an i31 object aka `(ref i31)`. + pub const I31: Self = RefType::from_u32(Self::I31_TYPE); + + const fn can_represent_type_index(index: u32) -> bool { + index & Self::INDEX_MASK == index + } + + const fn u24_to_u32(bytes: [u8; 3]) -> u32 { + let expanded_bytes = [bytes[0], bytes[1], bytes[2], 0]; + u32::from_le_bytes(expanded_bytes) + } + + const fn u32_to_u24(x: u32) -> [u8; 3] { + let bytes = x.to_le_bytes(); + debug_assert!(bytes[3] == 0); + [bytes[0], bytes[1], bytes[2]] + } + + #[inline] + const fn as_u32(&self) -> u32 { + Self::u24_to_u32(self.0) + } + + #[inline] + const fn from_u32(x: u32) -> Self { + debug_assert!(x & (0b11111111 << 24) == 0); + + // if not indexed, type must be any/eq/i31/struct/array/func/extern/nofunc/noextern/none + debug_assert!( + x & Self::INDEXED_BIT != 0 + || matches!( + x & Self::TYPE_MASK, + Self::ANY_TYPE + | Self::EQ_TYPE + | Self::I31_TYPE + | Self::STRUCT_TYPE + | Self::ARRAY_TYPE + | Self::FUNC_TYPE + | Self::NOFUNC_TYPE + | Self::EXTERN_TYPE + | Self::NOEXTERN_TYPE + | Self::NONE_TYPE + ) + ); + RefType(Self::u32_to_u24(x)) + } + + /// Create a reference to a typed function with the type at the given index. + /// + /// Returns `None` when the type index is beyond this crate's implementation + /// limits and therefore is not representable. + pub const fn indexed_func(nullable: bool, index: u32) -> Option { + Self::indexed(nullable, Self::FUNC_KIND, index) + } + + /// Create a reference to an array with the type at the given index. + /// + /// Returns `None` when the type index is beyond this crate's implementation + /// limits and therefore is not representable. + pub const fn indexed_array(nullable: bool, index: u32) -> Option { + Self::indexed(nullable, Self::ARRAY_KIND, index) + } + + /// Create a reference to a struct with the type at the given index. + /// + /// Returns `None` when the type index is beyond this crate's implementation + /// limits and therefore is not representable. + pub const fn indexed_struct(nullable: bool, index: u32) -> Option { + Self::indexed(nullable, Self::STRUCT_KIND, index) + } + + /// Create a reference to a user defined type at the given index. + /// + /// Returns `None` when the type index is beyond this crate's implementation + /// limits and therefore is not representable, or when the heap type is not + /// a typed array, struct or function. + const fn indexed(nullable: bool, kind: u32, index: u32) -> Option { + if Self::can_represent_type_index(index) { + let nullable32 = Self::NULLABLE_BIT * nullable as u32; + Some(RefType::from_u32( + nullable32 | Self::INDEXED_BIT | kind | index, + )) + } else { + None + } + } + + /// Create a new `RefType`. + /// + /// Returns `None` when the heap type's type index (if any) is beyond this + /// crate's implementation limits and therfore is not representable. + pub const fn new(nullable: bool, heap_type: HeapType) -> Option { + let nullable32 = Self::NULLABLE_BIT * nullable as u32; + match heap_type { + HeapType::Indexed(index) => RefType::indexed(nullable, 0, index), // 0 bc we don't know the kind + HeapType::Func => Some(Self::from_u32(nullable32 | Self::FUNC_TYPE)), + HeapType::Extern => Some(Self::from_u32(nullable32 | Self::EXTERN_TYPE)), + HeapType::Any => Some(Self::from_u32(nullable32 | Self::ANY_TYPE)), + HeapType::None => Some(Self::from_u32(nullable32 | Self::NONE_TYPE)), + HeapType::NoExtern => Some(Self::from_u32(nullable32 | Self::NOEXTERN_TYPE)), + HeapType::NoFunc => Some(Self::from_u32(nullable32 | Self::NOFUNC_TYPE)), + HeapType::Eq => Some(Self::from_u32(nullable32 | Self::EQ_TYPE)), + HeapType::Struct => Some(Self::from_u32(nullable32 | Self::STRUCT_TYPE)), + HeapType::Array => Some(Self::from_u32(nullable32 | Self::ARRAY_TYPE)), + HeapType::I31 => Some(Self::from_u32(nullable32 | Self::I31_TYPE)), + } + } + + /// Is this a reference to a typed function? + pub const fn is_typed_func_ref(&self) -> bool { + self.is_indexed_type_ref() && self.as_u32() & Self::KIND_MASK == Self::FUNC_KIND + } + + /// Is this a reference to an indexed type? + pub const fn is_indexed_type_ref(&self) -> bool { + self.as_u32() & Self::INDEXED_BIT != 0 + } + + /// If this is a reference to a typed function, get its type index. + pub const fn type_index(&self) -> Option { + if self.is_indexed_type_ref() { + Some(self.as_u32() & Self::INDEX_MASK) + } else { + None + } + } + + /// Is this an untyped function reference aka `(ref null func)` aka `funcref` aka `anyfunc`? + pub const fn is_func_ref(&self) -> bool { + !self.is_indexed_type_ref() && self.as_u32() & Self::TYPE_MASK == Self::FUNC_TYPE + } + + /// Is this a `(ref null extern)` aka `externref`? + pub const fn is_extern_ref(&self) -> bool { + !self.is_indexed_type_ref() && self.as_u32() & Self::TYPE_MASK == Self::EXTERN_TYPE + } + + /// Is this ref type nullable? + pub const fn is_nullable(&self) -> bool { + self.as_u32() & Self::NULLABLE_BIT != 0 + } + + /// Get the non-nullable version of this ref type. + pub const fn as_non_null(&self) -> Self { + Self::from_u32(self.as_u32() & !Self::NULLABLE_BIT) + } + + /// Get the non-nullable version of this ref type. + pub const fn nullable(&self) -> Self { + Self::from_u32(self.as_u32() | Self::NULLABLE_BIT) + } + + /// Get the heap type that this is a reference to. + pub fn heap_type(&self) -> HeapType { + let s = self.as_u32(); + if self.is_indexed_type_ref() { + HeapType::Indexed(self.type_index().unwrap()) + } else { + match s & Self::TYPE_MASK { + Self::FUNC_TYPE => HeapType::Func, + Self::EXTERN_TYPE => HeapType::Extern, + Self::ANY_TYPE => HeapType::Any, + Self::NONE_TYPE => HeapType::None, + Self::NOEXTERN_TYPE => HeapType::NoExtern, + Self::NOFUNC_TYPE => HeapType::NoFunc, + Self::EQ_TYPE => HeapType::Eq, + Self::STRUCT_TYPE => HeapType::Struct, + Self::ARRAY_TYPE => HeapType::Array, + Self::I31_TYPE => HeapType::I31, + _ => unreachable!(), + } + } + } + + // Note that this is similar to `Display for RefType` except that it has + // the indexes stubbed out. + pub(crate) fn wat(&self) -> &'static str { + match (self.is_nullable(), self.heap_type()) { + (true, HeapType::Func) => "funcref", + (true, HeapType::Extern) => "externref", + (true, HeapType::Indexed(_)) => "(ref null $type)", + (true, HeapType::Any) => "anyref", + (true, HeapType::None) => "nullref", + (true, HeapType::NoExtern) => "nullexternref", + (true, HeapType::NoFunc) => "nullfuncref", + (true, HeapType::Eq) => "eqref", + (true, HeapType::Struct) => "structref", + (true, HeapType::Array) => "arrayref", + (true, HeapType::I31) => "i31ref", + (false, HeapType::Func) => "(ref func)", + (false, HeapType::Extern) => "(ref extern)", + (false, HeapType::Indexed(_)) => "(ref $type)", + (false, HeapType::Any) => "(ref any)", + (false, HeapType::None) => "(ref none)", + (false, HeapType::NoExtern) => "(ref noextern)", + (false, HeapType::NoFunc) => "(ref nofunc)", + (false, HeapType::Eq) => "(ref eq)", + (false, HeapType::Struct) => "(ref struct)", + (false, HeapType::Array) => "(ref array)", + (false, HeapType::I31) => "(ref i31)", + } + } +} + +impl Matches for RefType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + self == other + || ((other.is_nullable() || !self.is_nullable()) + && self.heap_type().matches(&other.heap_type(), type_at)) + } +} + +impl<'a> FromReader<'a> for RefType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + match reader.read()? { + 0x70 => Ok(RefType::FUNC.nullable()), + 0x6F => Ok(RefType::EXTERN.nullable()), + 0x6E => Ok(RefType::ANY.nullable()), + 0x71 => Ok(RefType::NONE.nullable()), + 0x72 => Ok(RefType::NOEXTERN.nullable()), + 0x73 => Ok(RefType::NOFUNC.nullable()), + 0x6D => Ok(RefType::EQ.nullable()), + 0x6B => Ok(RefType::STRUCT.nullable()), + 0x6A => Ok(RefType::ARRAY.nullable()), + 0x6C => Ok(RefType::I31.nullable()), + byte @ (0x63 | 0x64) => { + let nullable = byte == 0x63; + let pos = reader.original_position(); + RefType::new(nullable, reader.read()?) + .ok_or_else(|| crate::BinaryReaderError::new("type index too large", pos)) + } + _ => bail!(reader.original_position(), "malformed reference type"), + } + } +} + +impl fmt::Display for RefType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Note that this is similar to `RefType::wat` except that it has the + // indexes filled out. + let s = match (self.is_nullable(), self.heap_type()) { + (true, HeapType::Func) => "funcref", + (true, HeapType::Extern) => "externref", + (true, HeapType::Indexed(i)) => return write!(f, "(ref null {i})"), + (true, HeapType::Any) => "anyref", + (true, HeapType::None) => "nullref", + (true, HeapType::NoExtern) => "nullexternref", + (true, HeapType::NoFunc) => "nullfuncref", + (true, HeapType::Eq) => "eqref", + (true, HeapType::Struct) => "structref", + (true, HeapType::Array) => "arrayref", + (true, HeapType::I31) => "i31ref", + (false, HeapType::Func) => "(ref func)", + (false, HeapType::Extern) => "(ref extern)", + (false, HeapType::Indexed(i)) => return write!(f, "(ref {i})"), + (false, HeapType::Any) => "(ref any)", + (false, HeapType::None) => "(ref none)", + (false, HeapType::NoExtern) => "(ref noextern)", + (false, HeapType::NoFunc) => "(ref nofunc)", + (false, HeapType::Eq) => "(ref eq)", + (false, HeapType::Struct) => "(ref struct)", + (false, HeapType::Array) => "(ref array)", + (false, HeapType::I31) => "(ref i31)", + }; + f.write_str(s) + } +} + +/// A heap type from function references. When the proposal is disabled, Index +/// is an invalid type. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum HeapType { + /// User defined type at the given index. + Indexed(u32), + /// Untyped (any) function. + Func, + /// External heap type. + Extern, + /// The `any` heap type. The common supertype (a.k.a. top) of all internal types. + Any, + /// The `none` heap type. The common subtype (a.k.a. bottom) of all internal types. + None, + /// The `noextern` heap type. The common subtype (a.k.a. bottom) of all external types. + NoExtern, + /// The `nofunc` heap type. The common subtype (a.k.a. bottom) of all function types. + NoFunc, + /// The `eq` heap type. The common supertype of all referenceable types on which comparison + /// (ref.eq) is allowed. + Eq, + /// The `struct` heap type. The common supertype of all struct types. + Struct, + /// The `array` heap type. The common supertype of all array types. + Array, + /// The i31 heap type. + I31, +} + +impl Matches for HeapType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + if self == other { + return true; + } + + use HeapType as HT; + match (self, other) { + (HT::Eq | HT::I31 | HT::Struct | HT::Array | HT::None, HT::Any) => true, + (HT::I31 | HT::Struct | HT::Array | HT::None, HT::Eq) => true, + (HT::NoExtern, HT::Extern) => true, + (HT::NoFunc, HT::Func) => true, + (HT::None, HT::I31 | HT::Array | HT::Struct) => true, + + (HT::Indexed(a), HT::Eq | HT::Any) => matches!( + type_at(*a).structural_type, + StructuralType::Array(_) | StructuralType::Struct(_) + ), + + (HT::Indexed(a), HT::Struct) => { + matches!(type_at(*a).structural_type, StructuralType::Struct(_)) + } + + (HT::Indexed(a), HT::Array) => { + matches!(type_at(*a).structural_type, StructuralType::Array(_)) + } + + (HT::Indexed(a), HT::Func) => { + matches!(type_at(*a).structural_type, StructuralType::Func(_)) + } + + (HT::Indexed(a), HT::Indexed(b)) => type_at(*a) + .structural_type + .matches(&type_at(*b).structural_type, type_at), + + (HT::None, HT::Indexed(b)) => matches!( + type_at(*b).structural_type, + StructuralType::Array(_) | StructuralType::Struct(_) + ), + + (HT::NoFunc, HT::Indexed(b)) => { + matches!(type_at(*b).structural_type, StructuralType::Func(_)) + } + + _ => false, + } + } +} + +impl<'a> FromReader<'a> for HeapType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + match reader.peek()? { + 0x70 => { + reader.position += 1; + Ok(HeapType::Func) + } + 0x6F => { + reader.position += 1; + Ok(HeapType::Extern) + } + 0x6E => { + reader.position += 1; + Ok(HeapType::Any) + } + 0x71 => { + reader.position += 1; + Ok(HeapType::None) + } + 0x72 => { + reader.position += 1; + Ok(HeapType::NoExtern) + } + 0x73 => { + reader.position += 1; + Ok(HeapType::NoFunc) + } + 0x6D => { + reader.position += 1; + Ok(HeapType::Eq) + } + 0x6B => { + reader.position += 1; + Ok(HeapType::Struct) + } + 0x6A => { + reader.position += 1; + Ok(HeapType::Array) + } + 0x6C => { + reader.position += 1; + Ok(HeapType::I31) + } + _ => { + let idx = match u32::try_from(reader.read_var_s33()?) { + Ok(idx) => idx, + Err(_) => { + bail!(reader.original_position(), "invalid indexed ref heap type"); + } + }; + Ok(HeapType::Indexed(idx)) + } + } + } +} + +/// Represents a structural type in a WebAssembly module. #[derive(Debug, Clone)] -pub enum Type { +pub enum StructuralType { /// The type is for a function. Func(FuncType), + /// The type is for an array. + Array(ArrayType), + /// The type is for a struct. + Struct(StructType), +} + +/// Represents a subtype of possible other types in a WebAssembly module. +#[derive(Debug, Clone)] +pub struct SubType { + /// Is the subtype final. + pub is_final: bool, + /// The list of supertype indexes. As of GC MVP, there can be at most one supertype. + pub supertype_idx: Option, + /// The structural type of the subtype. + pub structural_type: StructuralType, +} + +/// Represents a recursive type group in a WebAssembly module. +#[derive(Debug, Clone)] +pub enum RecGroup { + /// The list of subtypes in the recursive type group. + Many(Vec), + /// A single subtype in the recursive type group. + Single(SubType), +} + +impl RecGroup { + /// Returns the list of subtypes in the recursive type group. + pub fn types(&self) -> &[SubType] { + match self { + RecGroup::Many(types) => types, + RecGroup::Single(ty) => slice::from_ref(ty), + } + } + + /// Return an iterator over the types in this rec group, giving ownership of + /// the types. + pub fn into_types(self) -> impl ExactSizeIterator { + return match self { + RecGroup::Single(ty) => IntoIter::Single(Some(ty)), + RecGroup::Many(tys) => IntoIter::Many(tys.into_iter()), + }; + + enum IntoIter { + Single(Option), + Many(std::vec::IntoIter), + } + + impl Iterator for IntoIter { + type Item = SubType; + + fn next(&mut self) -> Option { + match self { + IntoIter::Single(ty) => ty.take(), + IntoIter::Many(tys) => tys.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + IntoIter::Single(None) => (0, Some(0)), + IntoIter::Single(Some(_)) => (1, Some(1)), + IntoIter::Many(tys) => tys.size_hint(), + } + } + } + + impl ExactSizeIterator for IntoIter {} + } +} + +impl Matches for SubType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + !other.is_final + && self + .structural_type + .matches(&other.structural_type, type_at) + } } /// Represents a type of a function in a WebAssembly module. @@ -58,10 +842,44 @@ pub enum Type { pub struct FuncType { /// The combined parameters and result types. params_results: Box<[ValType]>, - /// The number of paramter types. + /// The number of parameter types. len_params: usize, } +/// Represents a type of an array in a WebAssembly module. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct ArrayType(pub FieldType); + +/// Represents a field type of an array or a struct. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct FieldType { + /// Array element type. + pub element_type: StorageType, + /// Are elements mutable. + pub mutable: bool, +} + +/// Represents a type of a struct in a WebAssembly module. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct StructType { + /// Struct fields. + pub fields: Box<[FieldType]>, +} + +impl Matches for StructuralType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + match (self, other) { + (StructuralType::Func(a), StructuralType::Func(b)) => a.matches(b, type_at), + (StructuralType::Array(a), StructuralType::Array(b)) => a.matches(b, type_at), + (StructuralType::Struct(a), StructuralType::Struct(b)) => a.matches(b, type_at), + _ => false, + } + } +} + impl Debug for FuncType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("FuncType") @@ -111,13 +929,100 @@ impl FuncType { pub fn results(&self) -> &[ValType] { &self.params_results[self.len_params..] } + + pub(crate) fn desc(&self) -> String { + let mut s = String::new(); + s.push_str("["); + for (i, param) in self.params().iter().enumerate() { + if i > 0 { + s.push_str(" "); + } + write!(s, "{param}").unwrap(); + } + s.push_str("] -> ["); + for (i, result) in self.results().iter().enumerate() { + if i > 0 { + s.push_str(" "); + } + write!(s, "{result}").unwrap(); + } + s.push_str("]"); + s + } +} + +impl Matches for FuncType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + self.params().len() == other.params().len() + && self.results().len() == other.results().len() + // Note: per GC spec, function subtypes are contravariant in their parameter types. + // Also see https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) + && self + .params() + .iter() + .zip(other.params()) + .all(|(a, b)| b.matches(a, type_at)) + && self + .results() + .iter() + .zip(other.results()) + .all(|(a, b)| a.matches(b, type_at)) + } +} + +impl Matches for ArrayType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + self.0.matches(&other.0, type_at) + } +} + +impl Matches for FieldType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + (other.mutable || !self.mutable) && self.element_type.matches(&other.element_type, type_at) + } +} + +impl Matches for StorageType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + match (self, other) { + (Self::Val(a), Self::Val(b)) => a.matches(b, type_at), + (a @ (Self::I8 | Self::I16 | Self::Val(_)), b) => a == b, + } + } +} + +impl Matches for StructType { + fn matches<'a, F>(&self, other: &Self, type_at: &F) -> bool + where + F: Fn(u32) -> &'a SubType, + { + // Note: Structure types support width and depth subtyping. + self.fields.len() >= other.fields.len() + && self + .fields + .iter() + .zip(other.fields.iter()) + .all(|(a, b)| a.matches(b, type_at)) + } } /// Represents a table's type. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TableType { /// The table's element type. - pub element_type: ValType, + pub element_type: RefType, /// Initial size of this table, in elements. pub initial: u32, /// Optional maximum size of the table, in elements. @@ -191,89 +1096,135 @@ pub struct TagType { } /// A reader for the type section of a WebAssembly module. -#[derive(Clone)] -pub struct TypeSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} +pub type TypeSectionReader<'a> = SectionLimited<'a, RecGroup>; impl<'a> TypeSectionReader<'a> { - /// Constructs a new `TypeSectionReader` for the given data and offset. - pub fn new(data: &'a [u8], offset: usize) -> Result { - let mut reader = BinaryReader::new_with_offset(data, offset); - let count = reader.read_var_u32()?; - Ok(Self { reader, count }) - } - - /// Gets the original position of the reader. - pub fn original_position(&self) -> usize { - self.reader.original_position() - } - - /// Gets a count of items in the section. - pub fn get_count(&self) -> u32 { - self.count + /// Returns an iterator over this type section which will only yield + /// function types and any usage of GC types from the GC proposal will + /// be translated into an error. + pub fn into_iter_err_on_gc_types(self) -> impl Iterator> + 'a { + self.into_iter_with_offsets().map(|item| { + let (offset, group) = item?; + let ty = match group { + RecGroup::Single(ty) => ty, + RecGroup::Many(_) => bail!(offset, "gc proposal not supported"), + }; + if !ty.is_final || ty.supertype_idx.is_some() { + bail!(offset, "gc proposal not supported"); + } + match ty.structural_type { + StructuralType::Func(f) => Ok(f), + StructuralType::Array(_) | StructuralType::Struct(_) => { + bail!(offset, "gc proposal not supported"); + } + } + }) } +} - /// Reads content of the type section. - /// - /// # Examples - /// ``` - /// use wasmparser::TypeSectionReader; - /// let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; - /// let mut reader = TypeSectionReader::new(data, 0).unwrap(); - /// for _ in 0..reader.get_count() { - /// let ty = reader.read().expect("type"); - /// println!("Type {:?}", ty); - /// } - /// ``` - pub fn read(&mut self) -> Result { - self.reader.read_type() +impl<'a> FromReader<'a> for StructuralType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + read_structural_type(reader.read_u8()?, reader) } } -impl<'a> SectionReader for TypeSectionReader<'a> { - type Item = Type; +fn read_structural_type( + opcode: u8, + reader: &mut BinaryReader, +) -> Result { + Ok(match opcode { + 0x60 => StructuralType::Func(reader.read()?), + 0x5e => StructuralType::Array(reader.read()?), + 0x5f => StructuralType::Struct(reader.read()?), + x => return reader.invalid_leading_byte(x, "type"), + }) +} - fn read(&mut self) -> Result { - Self::read(self) +impl<'a> FromReader<'a> for RecGroup { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(match reader.peek()? { + 0x4e => { + reader.read_u8()?; + let types = reader.read_iter(MAX_WASM_TYPES, "rec group types")?; + RecGroup::Many(types.collect::>()?) + } + _ => RecGroup::Single(reader.read()?), + }) } +} - fn eof(&self) -> bool { - self.reader.eof() +impl<'a> FromReader<'a> for SubType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let pos = reader.original_position(); + Ok(match reader.read_u8()? { + opcode @ (0x4f | 0x50) => { + let idx_iter = reader.read_iter(MAX_WASM_SUPERTYPES, "supertype idxs")?; + let idxs = idx_iter.collect::>>()?; + if idxs.len() > 1 { + return Err(BinaryReaderError::new( + "multiple supertypes not supported", + pos, + )); + } + SubType { + is_final: opcode == 0x4f, + supertype_idx: idxs.first().copied(), + structural_type: read_structural_type(reader.read_u8()?, reader)?, + } + } + opcode => SubType { + is_final: true, + supertype_idx: None, + structural_type: read_structural_type(opcode, reader)?, + }, + }) } +} - fn original_position(&self) -> usize { - Self::original_position(self) +impl<'a> FromReader<'a> for FuncType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let mut params_results = reader + .read_iter(MAX_WASM_FUNCTION_PARAMS, "function params")? + .collect::>>()?; + let len_params = params_results.len(); + let results = reader.read_iter(MAX_WASM_FUNCTION_RETURNS, "function returns")?; + params_results.reserve(results.size_hint().0); + for result in results { + params_results.push(result?); + } + Ok(FuncType::from_raw_parts(params_results.into(), len_params)) } +} - fn range(&self) -> Range { - self.reader.range() +impl<'a> FromReader<'a> for FieldType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let element_type = reader.read()?; + let mutable = reader.read_u8()?; + Ok(FieldType { + element_type, + mutable: match mutable { + 0 => false, + 1 => true, + _ => bail!( + reader.original_position(), + "invalid mutability byte for array type" + ), + }, + }) } } -impl<'a> SectionWithLimitedItems for TypeSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) +impl<'a> FromReader<'a> for ArrayType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + Ok(ArrayType(FieldType::from_reader(reader)?)) } } -impl<'a> IntoIterator for TypeSectionReader<'a> { - type Item = Result; - type IntoIter = SectionIteratorLimited; - - /// Implements iterator over the type section. - /// - /// # Examples - /// ``` - /// use wasmparser::TypeSectionReader; - /// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; - /// let mut reader = TypeSectionReader::new(data, 0).unwrap(); - /// for ty in reader { - /// println!("Type {:?}", ty.expect("type")); - /// } - /// ``` - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) +impl<'a> FromReader<'a> for StructType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result { + let fields = reader.read_iter(MAX_WASM_STRUCT_FIELDS, "struct fields")?; + Ok(StructType { + fields: fields.collect::>()?, + }) } } diff --git a/crates/wasmparser/src/resources.rs b/crates/wasmparser/src/resources.rs index 3f6d4c671c..be4fa4ae11 100644 --- a/crates/wasmparser/src/resources.rs +++ b/crates/wasmparser/src/resources.rs @@ -13,7 +13,10 @@ * limitations under the License. */ -use crate::{FuncType, GlobalType, MemoryType, TableType, ValType}; +use crate::{ + BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType, TableType, ValType, + WasmFeatures, +}; use std::ops::Range; /// Types that qualify as Wasm function types for validation purposes. @@ -208,10 +211,47 @@ pub trait WasmModuleResources { fn global_at(&self, at: u32) -> Option; /// Returns the `FuncType` associated with the given type index. fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType>; + /// Returns the type index associated with the given function + /// index. type_of_function = func_type_at(type_index_of_function) + fn type_index_of_function(&self, func_idx: u32) -> Option; /// Returns the `FuncType` associated with the given function index. fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType>; /// Returns the element type at the given index. - fn element_type_at(&self, at: u32) -> Option; + fn element_type_at(&self, at: u32) -> Option; + /// Under the function references proposal, returns whether t1 <= + /// t2. Otherwise, returns whether t1 == t2 + fn matches(&self, t1: ValType, t2: ValType) -> bool; + /// Check a value type. This requires using func_type_at to check references + fn check_value_type( + &self, + t: ValType, + features: &WasmFeatures, + offset: usize, + ) -> Result<(), BinaryReaderError>; + + /// Checks that a `HeapType` is valid, notably its function index if one is + /// used. + fn check_heap_type( + &self, + heap_type: HeapType, + features: &WasmFeatures, + offset: usize, + ) -> Result<(), BinaryReaderError> { + // Delegate to the generic value type validation which will have the + // same validity checks. + self.check_value_type( + RefType::new(true, heap_type) + .ok_or_else(|| { + BinaryReaderError::new( + "heap type index beyond this crate's implementation limits", + offset, + ) + })? + .into(), + features, + offset, + ) + } /// Returns the number of elements. fn element_count(&self) -> u32; @@ -243,12 +283,26 @@ where fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> { T::func_type_at(self, at) } + fn type_index_of_function(&self, func_idx: u32) -> Option { + T::type_index_of_function(self, func_idx) + } fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> { T::type_of_function(self, func_idx) } - fn element_type_at(&self, at: u32) -> Option { + fn check_value_type( + &self, + t: ValType, + features: &WasmFeatures, + offset: usize, + ) -> Result<(), BinaryReaderError> { + T::check_value_type(self, t, features, offset) + } + fn element_type_at(&self, at: u32) -> Option { T::element_type_at(self, at) } + fn matches(&self, t1: ValType, t2: ValType) -> bool { + T::matches(self, t1, t2) + } fn element_count(&self) -> u32 { T::element_count(self) @@ -287,14 +341,31 @@ where T::func_type_at(self, type_idx) } + fn type_index_of_function(&self, func_idx: u32) -> Option { + T::type_index_of_function(self, func_idx) + } + fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> { T::type_of_function(self, func_idx) } - fn element_type_at(&self, at: u32) -> Option { + fn check_value_type( + &self, + t: ValType, + features: &WasmFeatures, + offset: usize, + ) -> Result<(), BinaryReaderError> { + T::check_value_type(self, t, features, offset) + } + + fn element_type_at(&self, at: u32) -> Option { T::element_type_at(self, at) } + fn matches(&self, t1: ValType, t2: ValType) -> bool { + T::matches(self, t1, t2) + } + fn element_count(&self) -> u32 { T::element_count(self) } diff --git a/crates/wasmparser/src/validator.rs b/crates/wasmparser/src/validator.rs index 923890d30b..111824732e 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -14,8 +14,8 @@ */ use crate::{ - limits::*, BinaryReaderError, Encoding, FunctionBody, Parser, Payload, Result, SectionReader, - SectionWithLimitedItems, ValType, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION, + limits::*, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType, Parser, Payload, + Result, SectionLimited, ValType, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION, }; use std::mem; use std::ops::Range; @@ -48,13 +48,14 @@ fn test_validate() { mod component; mod core; mod func; +pub mod names; mod operators; pub mod types; use self::component::*; pub use self::core::ValidatorResources; use self::core::*; -use self::types::{TypeList, Types, TypesRef}; +use self::types::{TypeAlloc, Types, TypesRef}; pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations}; pub use operators::{Frame, FrameKind}; @@ -74,7 +75,7 @@ fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usi Ok(()) } -fn combine_type_sizes(a: usize, b: usize, offset: usize) -> Result { +fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result { match a.checked_add(b) { Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum), _ => Err(format_err!( @@ -115,7 +116,7 @@ pub struct Validator { state: State, /// The global type space used by the validator and any sub-validators. - types: TypeList, + types: TypeAlloc, /// The module state when parsing a WebAssembly module. module: Option, @@ -211,17 +212,26 @@ pub struct WasmFeatures { pub multi_value: bool, /// The WebAssembly bulk memory operations proposal (enabled by default) pub bulk_memory: bool, - /// The WebAssembly SIMD proposal + /// The WebAssembly SIMD proposal (enabled by default) pub simd: bool, - /// The WebAssembly Relaxed SIMD proposal + /// The WebAssembly Relaxed SIMD proposal (enabled by default) pub relaxed_simd: bool, - /// The WebAssembly threads proposal + /// The WebAssembly threads proposal (enabled by default) pub threads: bool, - /// The WebAssembly tail-call proposal + /// The WebAssembly tail-call proposal (enabled by default) pub tail_call: bool, - /// Whether or not only deterministic instructions are allowed - pub deterministic_only: bool, - /// The WebAssembly multi memory proposal + /// Whether or not floating-point instructions are enabled. + /// + /// This is enabled by default can be used to disallow floating-point + /// operators and types. + /// + /// This does not correspond to a WebAssembly proposal but is instead + /// intended for embeddings which have stricter-than-usual requirements + /// about execution. Floats in WebAssembly can have different NaN patterns + /// across hosts which can lead to host-dependent execution which some + /// runtimes may not desire. + pub floats: bool, + /// The WebAssembly multi memory proposal (enabled by default) pub multi_memory: bool, /// The WebAssembly exception handling proposal pub exceptions: bool, @@ -231,17 +241,102 @@ pub struct WasmFeatures { pub extended_const: bool, /// The WebAssembly component model proposal. pub component_model: bool, + /// The WebAssembly typed function references proposal + pub function_references: bool, + /// The WebAssembly memory control proposal + pub memory_control: bool, + /// The WebAssembly gc proposal + pub gc: bool, + /// Support for the `value` type in the component model proposal. + pub component_model_values: bool, } impl WasmFeatures { + /// Returns [`WasmFeatures`] with all features enabled. + pub fn all() -> Self { + WasmFeatures { + mutable_global: true, + saturating_float_to_int: true, + sign_extension: true, + reference_types: true, + multi_value: true, + bulk_memory: true, + simd: true, + relaxed_simd: true, + threads: true, + tail_call: true, + floats: true, + multi_memory: true, + exceptions: true, + memory64: true, + extended_const: true, + component_model: true, + function_references: true, + memory_control: true, + gc: true, + component_model_values: true, + } + } + + /// NOTE: This only checks that the value type corresponds to the feature set!! + /// + /// To check that reference types are valid, we need access to the module + /// types. Use module.check_value_type. pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> { match ty { - ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => Ok(()), - ValType::FuncRef | ValType::ExternRef => { - if self.reference_types { + ValType::I32 | ValType::I64 => Ok(()), + ValType::F32 | ValType::F64 => { + if self.floats { Ok(()) } else { - Err("reference types support is not enabled") + Err("floating-point support is disabled") + } + } + ValType::Ref(r) => { + if !self.reference_types { + return Err("reference types support is not enabled"); + } + match (r.heap_type(), r.is_nullable()) { + // funcref/externref only require `reference-types` + (HeapType::Func, true) | (HeapType::Extern, true) => Ok(()), + + // non-nullable func/extern references requires the + // `function-references` proposal + (HeapType::Func | HeapType::Extern, false) => { + if self.function_references { + Ok(()) + } else { + Err("function references required for non-nullable types") + } + } + // indexed types require at least the function-references + // proposal + (HeapType::Indexed(_), _) => { + if self.function_references { + Ok(()) + } else { + Err("function references required for index reference types") + } + } + + // types added in the gc proposal + ( + HeapType::Any + | HeapType::None + | HeapType::Eq + | HeapType::Struct + | HeapType::Array + | HeapType::I31 + | HeapType::NoExtern + | HeapType::NoFunc, + _, + ) => { + if self.gc { + Ok(()) + } else { + Err("heap types not supported without the gc feature") + } + } } } ValType::V128 => { @@ -258,25 +353,29 @@ impl WasmFeatures { impl Default for WasmFeatures { fn default() -> WasmFeatures { WasmFeatures { - // off-by-default features - relaxed_simd: false, - threads: false, - tail_call: false, - multi_memory: false, + // Off-by-default features. exceptions: false, memory64: false, extended_const: false, component_model: false, - deterministic_only: cfg!(feature = "deterministic"), + function_references: false, + memory_control: false, + gc: false, + component_model_values: false, - // on-by-default features + // On-by-default features (phase 4 or greater). mutable_global: true, saturating_float_to_int: true, sign_extension: true, bulk_memory: true, multi_value: true, reference_types: true, + tail_call: true, simd: true, + floats: true, + relaxed_simd: true, + threads: true, + multi_memory: true, } } } @@ -426,7 +525,7 @@ impl Validator { } => self.code_section_start(*count, range)?, CodeSectionEntry(body) => { let func_validator = self.code_section_entry(body)?; - return Ok(ValidPayload::Func(func_validator, *body)); + return Ok(ValidPayload::Func(func_validator, body.clone())); } DataSection(s) => self.data_section(s)?, @@ -445,7 +544,7 @@ impl Validator { ComponentAliasSection(s) => self.component_alias_section(s)?, ComponentTypeSection(s) => self.component_type_section(s)?, ComponentCanonicalSection(s) => self.component_canonical_section(s)?, - ComponentStartSection(s) => self.component_start_section(s)?, + ComponentStartSection { start, range } => self.component_start_section(start, range)?, ComponentImportSection(s) => self.component_import_section(s)?, ComponentExportSection(s) => self.component_export_section(s)?, @@ -458,7 +557,7 @@ impl Validator { } /// Validates [`Payload::Version`](crate::Payload). - pub fn version(&mut self, num: u32, encoding: Encoding, range: &Range) -> Result<()> { + pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range) -> Result<()> { match &self.state { State::Unparsed(expected) => { if let Some(expected) = expected { @@ -482,28 +581,34 @@ impl Validator { } } - self.state = match (encoding, num) { - (Encoding::Module, WASM_MODULE_VERSION) => { - assert!(self.module.is_none()); - self.module = Some(ModuleState::default()); - State::Module + self.state = match encoding { + Encoding::Module => { + if num == WASM_MODULE_VERSION { + assert!(self.module.is_none()); + self.module = Some(ModuleState::default()); + State::Module + } else { + bail!(range.start, "unknown binary version: {num:#x}"); + } } - (Encoding::Component, WASM_COMPONENT_VERSION) => { + Encoding::Component => { if !self.features.component_model { - return Err(BinaryReaderError::new( - "WebAssembly component model feature not enabled", + bail!( range.start, - )); + "unknown binary version and encoding combination: {num:#x} and 0x1, \ + note: encoded as a component but the WebAssembly component model feature \ + is not enabled - enable the feature to allow component validation", + ); + } + if num == WASM_COMPONENT_VERSION { + self.components + .push(ComponentState::new(ComponentKind::Component)); + State::Component + } else if num < WASM_COMPONENT_VERSION { + bail!(range.start, "unsupported component version: {num:#x}"); + } else { + bail!(range.start, "unknown component version: {num:#x}"); } - - self.components.push(ComponentState::default()); - State::Component - } - _ => { - return Err(BinaryReaderError::new( - "unknown binary version", - range.start, - )); } }; @@ -532,7 +637,8 @@ impl Validator { state .module .assert_mut() - .add_type(def, features, types, offset, false /* checked above */) + .add_types(&def, features, types, offset, true)?; + Ok(()) }, ) } @@ -600,9 +706,7 @@ impl Validator { state.module.assert_mut().tables.reserve(count as usize); Ok(()) }, - |state, features, _, ty, offset| { - state.module.assert_mut().add_table(ty, features, offset) - }, + |state, features, types, table, offset| state.add_table(table, features, types, offset), ) } @@ -710,10 +814,13 @@ impl Validator { state.module.assert_mut().exports.reserve(count as usize); Ok(()) }, - |state, features, _, e, offset| { + |state, features, types, e, offset| { let state = state.module.assert_mut(); let ty = state.export_to_entity_type(&e, offset)?; - state.add_export(e.name, ty, features, offset, false /* checked above */) + state.add_export( + e.name, ty, features, offset, false, /* checked above */ + types, + ) }, ) } @@ -988,11 +1095,11 @@ impl Validator { current.instances.reserve(count as usize); Ok(()) }, - |components, types, _, instance, offset| { + |components, types, features, instance, offset| { components .last_mut() .unwrap() - .add_instance(instance, types, offset) + .add_instance(instance, features, types, offset) }, ) } @@ -1002,14 +1109,14 @@ impl Validator { /// This method should only be called when parsing a component. pub fn component_alias_section( &mut self, - section: &crate::ComponentAliasSectionReader, + section: &crate::ComponentAliasSectionReader<'_>, ) -> Result<()> { self.process_component_section( section, "alias", |_, _, _, _| Ok(()), // maximums checked via `add_alias` - |components, types, _, alias, offset| -> Result<(), BinaryReaderError> { - ComponentState::add_alias(components, alias, types, offset) + |components, types, features, alias, offset| -> Result<(), BinaryReaderError> { + ComponentState::add_alias(components, alias, features, types, offset) }, ) } @@ -1079,6 +1186,15 @@ impl Validator { func_index, options, } => current.lower_function(func_index, options.into_vec(), types, offset), + crate::CanonicalFunction::ResourceNew { resource } => { + current.resource_new(resource, types, offset) + } + crate::CanonicalFunction::ResourceDrop { resource } => { + current.resource_drop(resource, types, offset) + } + crate::CanonicalFunction::ResourceRep { resource } => { + current.resource_rep(resource, types, offset) + } } }, ) @@ -1089,25 +1205,16 @@ impl Validator { /// This method should only be called when parsing a component. pub fn component_start_section( &mut self, - section: &crate::ComponentStartSectionReader, + f: &crate::ComponentStartFunction, + range: &Range, ) -> Result<()> { - let range = section.range(); self.state.ensure_component("start", range.start)?; - let mut section = section.clone(); - let f = section.read()?; - - if !section.eof() { - return Err(BinaryReaderError::new( - "trailing data at the end of the start section", - section.original_position(), - )); - } - self.components.last_mut().unwrap().add_start( f.func_index, &f.arguments, f.results, + &self.features, &self.types, range.start, ) @@ -1124,11 +1231,11 @@ impl Validator { section, "import", |_, _, _, _| Ok(()), // add_import will check limits - |components, types, _, import, offset| { + |components, types, features, import, offset| { components .last_mut() .unwrap() - .add_import(import, types, offset) + .add_import(import, features, types, offset) }, ) } @@ -1155,10 +1262,17 @@ impl Validator { current.exports.reserve(count as usize); Ok(()) }, - |components, _, _, export, offset| { + |components, types, features, export, offset| { let current = components.last_mut().unwrap(); - let ty = current.export_to_entity_type(&export, offset)?; - current.add_export(export.name, ty, offset, false /* checked above */) + let ty = current.export_to_entity_type(&export, features, types, offset)?; + current.add_export( + export.name, + ty, + features, + types, + offset, + false, /* checked above */ + ) }, ) } @@ -1204,16 +1318,18 @@ impl Validator { // Validate that all values were used for the component if let Some(index) = component.values.iter().position(|(_, used)| !*used) { - return Err( - format_err!(offset,"value index {index} was not used as part of an instantiation, start function, or export" - ) + bail!( + offset, + "value index {index} was not used as part of an \ + instantiation, start function, or export" ); } // If there's a parent component, pop the stack, add it to the parent, // and continue to validate the component + let ty = component.finish(&mut self.types, offset)?; if let Some(parent) = self.components.last_mut() { - parent.add_component(&mut component, &mut self.types); + parent.add_component(ty, &mut self.types)?; self.state = State::Component; } @@ -1222,28 +1338,28 @@ impl Validator { } } - fn process_module_section( + fn process_module_section<'a, T>( &mut self, order: Order, - section: &T, + section: &SectionLimited<'a, T>, name: &str, validate_section: impl FnOnce( &mut ModuleState, &WasmFeatures, - &mut TypeList, + &mut TypeAlloc, u32, usize, ) -> Result<()>, mut validate_item: impl FnMut( &mut ModuleState, &WasmFeatures, - &mut TypeList, - T::Item, + &mut TypeAlloc, + T, usize, ) -> Result<()>, ) -> Result<()> where - T: SectionReader + Clone + SectionWithLimitedItems, + T: FromReader<'a>, { let offset = section.range().start; self.state.ensure_module(name, offset)?; @@ -1255,37 +1371,38 @@ impl Validator { state, &self.features, &mut self.types, - section.get_count(), + section.count(), offset, )?; - let mut section = section.clone(); - for _ in 0..section.get_count() { - let offset = section.original_position(); - let item = section.read()?; + for item in section.clone().into_iter_with_offsets() { + let (offset, item) = item?; validate_item(state, &self.features, &mut self.types, item, offset)?; } - section.ensure_end()?; - Ok(()) } - fn process_component_section( + fn process_component_section<'a, T>( &mut self, - section: &T, + section: &SectionLimited<'a, T>, name: &str, - validate_section: impl FnOnce(&mut Vec, &mut TypeList, u32, usize) -> Result<()>, + validate_section: impl FnOnce( + &mut Vec, + &mut TypeAlloc, + u32, + usize, + ) -> Result<()>, mut validate_item: impl FnMut( &mut Vec, - &mut TypeList, + &mut TypeAlloc, &WasmFeatures, - T::Item, + T, usize, ) -> Result<()>, ) -> Result<()> where - T: Clone + SectionWithLimitedItems, + T: FromReader<'a>, { let offset = section.range().start; @@ -1300,14 +1417,12 @@ impl Validator { validate_section( &mut self.components, &mut self.types, - section.get_count(), + section.count(), offset, )?; - let mut section = section.clone(); - for _ in 0..section.get_count() { - let offset = section.original_position(); - let item = section.read()?; + for item in section.clone().into_iter_with_offsets() { + let (offset, item) = item?; validate_item( &mut self.components, &mut self.types, @@ -1317,15 +1432,13 @@ impl Validator { )?; } - section.ensure_end()?; - Ok(()) } } #[cfg(test)] mod tests { - use crate::{GlobalType, MemoryType, TableType, ValType, Validator, WasmFeatures}; + use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures}; use anyhow::Result; #[test] @@ -1363,66 +1476,122 @@ mod tests { assert_eq!(types.instance_count(), 0); assert_eq!(types.value_count(), 0); - match types.func_type_at(0) { - Some(ty) => { - assert_eq!(ty.params(), [ValType::I32, ValType::I64]); - assert_eq!(ty.results(), [ValType::I32]); - } - _ => unreachable!(), - } + let ty = types[types.core_type_at(0)].unwrap_func(); + assert_eq!(ty.params(), [ValType::I32, ValType::I64]); + assert_eq!(ty.results(), [ValType::I32]); - match types.func_type_at(1) { - Some(ty) => { - assert_eq!(ty.params(), [ValType::I64, ValType::I32]); - assert_eq!(ty.results(), []); - } - _ => unreachable!(), - } + let ty = types[types.core_type_at(1)].unwrap_func(); + assert_eq!(ty.params(), [ValType::I64, ValType::I32]); + assert_eq!(ty.results(), []); assert_eq!( types.memory_at(0), - Some(MemoryType { + MemoryType { memory64: false, shared: false, initial: 1, maximum: Some(5) - }) + } ); assert_eq!( types.table_at(0), - Some(TableType { + TableType { initial: 10, maximum: None, - element_type: ValType::FuncRef, - }) + element_type: RefType::FUNCREF, + } ); assert_eq!( types.global_at(0), - Some(GlobalType { + GlobalType { content_type: ValType::I32, mutable: true - }) + } ); - match types.function_at(0) { - Some(ty) => { - assert_eq!(ty.params(), [ValType::I32, ValType::I64]); - assert_eq!(ty.results(), [ValType::I32]); - } - _ => unreachable!(), - } + let id = types.function_at(0); + let ty = types[id].unwrap_func(); + assert_eq!(ty.params(), [ValType::I32, ValType::I64]); + assert_eq!(ty.results(), [ValType::I32]); - match types.tag_at(0) { - Some(ty) => { - assert_eq!(ty.params(), [ValType::I64, ValType::I32]); - assert_eq!(ty.results(), []); - } - _ => unreachable!(), - } + let ty = types.tag_at(0); + let ty = types[ty].unwrap_func(); + assert_eq!(ty.params(), [ValType::I64, ValType::I32]); + assert_eq!(ty.results(), []); + + assert_eq!(types.element_at(0), RefType::FUNCREF); + + Ok(()) + } + + #[test] + fn test_type_id_aliasing() -> Result<()> { + let bytes = wat::parse_str( + r#" + (component + (type $T (list string)) + (alias outer 0 $T (type $A1)) + (alias outer 0 $T (type $A2)) + ) + "#, + )?; + + let mut validator = Validator::new_with_features(WasmFeatures { + component_model: true, + ..Default::default() + }); + + let types = validator.validate_all(&bytes)?; + + let t_id = types.component_type_at(0); + let a1_id = types.component_type_at(1); + let a2_id = types.component_type_at(2); + + // The ids should all be the same + assert!(t_id == a1_id); + assert!(t_id == a2_id); + assert!(a1_id == a2_id); + + // However, they should all point to the same type + assert!(std::ptr::eq(&types[t_id], &types[a1_id],)); + assert!(std::ptr::eq(&types[t_id], &types[a2_id],)); + + Ok(()) + } + + #[test] + fn test_type_id_exports() -> Result<()> { + let bytes = wat::parse_str( + r#" + (component + (type $T (list string)) + (export $A1 "A1" (type $T)) + (export $A2 "A2" (type $T)) + ) + "#, + )?; + + let mut validator = Validator::new_with_features(WasmFeatures { + component_model: true, + ..Default::default() + }); + + let types = validator.validate_all(&bytes)?; + + let t_id = types.component_type_at(0); + let a1_id = types.component_type_at(1); + let a2_id = types.component_type_at(2); + + // The ids should all be the same + assert!(t_id != a1_id); + assert!(t_id != a2_id); + assert!(a1_id != a2_id); - assert_eq!(types.element_at(0), Some(ValType::FuncRef)); + // However, they should all point to the same type + assert!(std::ptr::eq(&types[t_id], &types[a1_id],)); + assert!(std::ptr::eq(&types[t_id], &types[a2_id],)); Ok(()) } diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 5ce0e12c08..f2363b82e0 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -1,28 +1,48 @@ //! State relating to validating a WebAssembly component. use super::{ - check_max, combine_type_sizes, + check_max, core::Module, types::{ - ComponentFuncType, ComponentInstanceType, ComponentInstanceTypeKind, ComponentType, - ComponentValType, EntityType, InstanceType, ModuleType, RecordType, Type, TypeId, TypeList, - VariantCase, + ComponentFuncType, ComponentInstanceType, ComponentType, ComponentValType, EntityType, + InstanceType, ModuleType, RecordType, Remapping, ResourceId, Type, TypeAlloc, TypeId, + TypeList, VariantCase, }, }; +use crate::validator::names::{KebabName, KebabNameKind, KebabStr, KebabString}; use crate::{ limits::*, types::{ - ComponentDefinedType, ComponentEntityType, InstanceTypeKind, LoweringInfo, TupleType, - UnionType, VariantType, + ComponentDefinedType, ComponentEntityType, Context, InstanceTypeKind, LoweringInfo, Remap, + SubtypeCx, TupleType, TypeInfo, VariantType, }, - BinaryReaderError, CanonicalOption, ComponentExternalKind, ComponentOuterAliasKind, - ComponentTypeRef, ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, Result, - TableType, TypeBounds, ValType, WasmFeatures, + BinaryReaderError, CanonicalOption, ComponentExternName, ComponentExternalKind, + ComponentOuterAliasKind, ComponentTypeRef, ExternalKind, FuncType, GlobalType, + InstantiationArgKind, MemoryType, RecGroup, Result, StructuralType, SubType, TableType, + TypeBounds, ValType, WasmFeatures, }; -use indexmap::{IndexMap, IndexSet}; -use std::{collections::HashSet, mem}; +use indexmap::{map::Entry, IndexMap, IndexSet}; +use std::collections::{HashMap, HashSet}; +use std::mem; + +fn to_kebab_str<'a>(s: &'a str, desc: &str, offset: usize) -> Result<&'a KebabStr> { + match KebabStr::new(s) { + Some(s) => Ok(s), + None => { + if s.is_empty() { + bail!(offset, "{desc} name cannot be empty"); + } + + bail!(offset, "{desc} name `{s}` is not in kebab case"); + } + } +} pub(crate) struct ComponentState { + /// Whether this state is a concrete component, an instance type, or a + /// component type. + kind: ComponentKind, + // Core index spaces pub core_types: Vec, pub core_modules: Vec, @@ -42,11 +62,181 @@ pub(crate) struct ComponentState { pub imports: IndexMap, pub exports: IndexMap, + pub kebab_named_externs: IndexSet, + has_start: bool, - type_size: usize, + type_info: TypeInfo, + + /// A mapping of imported resources in this component. + /// + /// This mapping represents all "type variables" imported into the + /// component, or resources. This could be resources imported directly as + /// a top-level type import or additionally transitively through other + /// imported instances. + /// + /// The mapping element here is a "path" which is a list of indexes into + /// the import map that will be generated for this component. Each index + /// is an index into an `IndexMap`, and each list is guaranteed to have at + /// least one element. + /// + /// An example of this map is: + /// + /// ```wasm + /// (component + /// ;; [0] - the first import + /// (import "r" (type (sub resource))) + /// + /// ;; [1] - the second import + /// (import "r2" (type (sub resource))) + /// + /// (import "i" (instance + /// ;; [2, 0] - the third import, and the first export the instance + /// (export "r3" (type (sub resource))) + /// ;; [2, 1] - the third import, and the second export the instance + /// (export "r4" (type (sub resource))) + /// )) + /// + /// ;; ... + /// ) + /// ``` + /// + /// The `Vec` here can be thought of as `Vec` but a + /// (hopefully) more efficient representation. + /// + /// Finally note that this map is listed as an "append only" map because all + /// insertions into it should always succeed. Any insertion which overlaps + /// with a previous entry indicates a bug in the validator which needs to be + /// corrected via other means. + // + // TODO: make these `SkolemResourceId` and then go fix all the compile + // errors, don't add skolem things into the type area + imported_resources: IndexMapAppendOnly>, + + /// A mapping of "defined" resources in this component, or those which + /// are defined within the instantiation of this component. + /// + /// Defined resources, as the name implies, can sort of be thought of as + /// "these are defined within the component". Note though that the means by + /// which a local definition can occur are not simply those defined in the + /// component but also in its transitively instantiated components + /// internally. This means that this set closes over many transitive + /// internal items in addition to those defined immediately in the component + /// itself. + /// + /// The `Option` in this mapping is whether or not the underlying + /// reprsentation of the resource is known to this component. Immediately + /// defined resources, for example, will have `Some(I32)` here. Resources + /// that come from transitively defined components, for example, will have + /// `None`. In the type context all entries here are `None`. + /// + /// Note that like `imported_resources` all insertions into this map are + /// expected to succeed to it's declared as append-only. + defined_resources: IndexMapAppendOnly>, + + /// A mapping of explicitly exported resources from this component in + /// addition to the path that they're exported at. + /// + /// For more information on the path here see the documentation for + /// `imported_resources`. Note that the indexes here index into the + /// list of exports of this component. + explicit_resources: IndexMap>, + + /// The set of types which are considered "exported" from this component. + /// + /// This is added to whenever a type export is found, or an instance export + /// which itself contains a type export. This additionally includes all + /// imported types since those are suitable for export as well. + /// + /// This set is consulted whenever an exported item is added since all + /// referenced types must be members of this set. + exported_types: HashSet, + + /// Same as `exported_types`, but for imports. + imported_types: HashSet, + + /// The set of top-level resource exports and their names. + /// + /// This context is used to validate method names such as `[method]foo.bar` + /// to ensure that `foo` is an exported resource and that the type mentioned + /// in a function type is actually named `foo`. + /// + /// Note that imports/exports have disjoint contexts to ensure that they're + /// validated correctly. Namely you can't retroactively attach methods to an + /// import, for example. + toplevel_exported_resources: KebabNameContext, + + /// Same as `toplevel_exported_resources`, but for imports. + toplevel_imported_resources: KebabNameContext, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ComponentKind { + Component, + InstanceType, + ComponentType, +} + +/// Helper context used to track information about resource names for method +/// name validation. +#[derive(Default)] +struct KebabNameContext { + /// A map from a resource type id to an index in the `all_resource_names` + /// set for the name of that resource. + resource_name_map: HashMap, + + /// All known resource names in this context, used to validate static method + /// names to by ensuring that static methods' resource names are somewhere + /// in this set. + all_resource_names: IndexSet, +} + +#[derive(Debug, Copy, Clone)] +pub enum ExternKind { + Import, + Export, +} + +impl ExternKind { + pub fn desc(&self) -> &'static str { + match self { + ExternKind::Import => "import", + ExternKind::Export => "export", + } + } } impl ComponentState { + pub fn new(kind: ComponentKind) -> Self { + Self { + kind, + core_types: Default::default(), + core_modules: Default::default(), + core_instances: Default::default(), + core_funcs: Default::default(), + core_memories: Default::default(), + core_tables: Default::default(), + core_globals: Default::default(), + core_tags: Default::default(), + types: Default::default(), + funcs: Default::default(), + values: Default::default(), + instances: Default::default(), + components: Default::default(), + imports: Default::default(), + exports: Default::default(), + kebab_named_externs: Default::default(), + has_start: Default::default(), + type_info: TypeInfo::new(), + imported_resources: Default::default(), + defined_resources: Default::default(), + explicit_resources: Default::default(), + exported_types: Default::default(), + imported_types: Default::default(), + toplevel_exported_resources: Default::default(), + toplevel_imported_resources: Default::default(), + } + } + pub fn type_count(&self) -> usize { self.core_types.len() + self.types.len() } @@ -63,19 +253,23 @@ impl ComponentState { components: &mut [Self], ty: crate::CoreType, features: &WasmFeatures, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, check_limit: bool, ) -> Result<()> { let ty = match ty { - crate::CoreType::Func(ty) => Type::Func(ty), - crate::CoreType::Module(decls) => Type::Module(Self::create_module_type( + crate::CoreType::Func(ty) => Type::Sub(SubType { + is_final: false, + supertype_idx: None, + structural_type: StructuralType::Func(ty), + }), + crate::CoreType::Module(decls) => Type::Module(Box::new(Self::create_module_type( components, decls.into_vec(), features, types, offset, - )?), + )?)), }; let current = components.last_mut().unwrap(); @@ -84,11 +278,8 @@ impl ComponentState { check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; } - current.core_types.push(TypeId { - type_size: ty.type_size(), - index: types.len(), - }); - types.push(ty); + let id = types.push_ty(ty); + current.core_types.push(id); Ok(()) } @@ -96,7 +287,7 @@ impl ComponentState { pub fn add_core_module( &mut self, module: &Module, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, ) -> Result<()> { let imports = module.imports_for_module_type(offset)?; @@ -104,18 +295,14 @@ impl ComponentState { // We have to clone the module's imports and exports here // because we cannot take the data out of the `MaybeOwned` // as it might be shared with a function validator. - let ty = Type::Module(ModuleType { - type_size: module.type_size, + let ty = Type::Module(Box::new(ModuleType { + info: TypeInfo::core(module.type_size), imports, exports: module.exports.clone(), - }); + })); - self.core_modules.push(TypeId { - type_size: ty.type_size(), - index: types.len(), - }); - - types.push(ty); + let id = types.push_ty(ty); + self.core_modules.push(id); Ok(()) } @@ -123,7 +310,7 @@ impl ComponentState { pub fn add_core_instance( &mut self, instance: crate::Instance, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, ) -> Result<()> { let instance = match instance { @@ -144,7 +331,7 @@ impl ComponentState { components: &mut Vec, ty: crate::ComponentType, features: &WasmFeatures, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, check_limit: bool, ) -> Result<()> { @@ -162,16 +349,51 @@ impl ComponentState { .unwrap() .create_function_type(ty, types, offset)?, ), - crate::ComponentType::Component(decls) => Type::Component(Self::create_component_type( - components, - decls.into_vec(), - features, - types, - offset, - )?), - crate::ComponentType::Instance(decls) => Type::ComponentInstance( + crate::ComponentType::Component(decls) => Type::Component(Box::new( + Self::create_component_type(components, decls.into_vec(), features, types, offset)?, + )), + crate::ComponentType::Instance(decls) => Type::ComponentInstance(Box::new( Self::create_instance_type(components, decls.into_vec(), features, types, offset)?, - ), + )), + crate::ComponentType::Resource { rep, dtor } => { + let component = components.last_mut().unwrap(); + + // Resource types cannot be declared in a type context, only + // within a component context. + if component.kind != ComponentKind::Component { + bail!( + offset, + "resources can only be defined within a concrete component" + ); + } + + // Current MVP restriction of the component model. + if rep != ValType::I32 { + bail!(offset, "resources can only be represented by `i32`"); + } + + // If specified validate that the destructor is both a valid + // function and has the correct signature. + if let Some(dtor) = dtor { + let ty = component.core_function_at(dtor, offset)?; + let ty = types[ty].unwrap_func(); + if ty.params() != [rep] || ty.results() != [] { + bail!( + offset, + "core function {dtor} has wrong signature for a destructor" + ); + } + } + + // As this is the introduction of a resource create a fresh new + // identifier for the resource. This is then added into the + // list of defined resources for this component, notably with a + // rep listed to enable getting access to various intrinsics + // such as `resource.rep`. + let id = types.alloc_resource_id(); + component.defined_resources.insert(id, Some(rep)); + Type::Resource(id) + } }; let current = components.last_mut().unwrap(); @@ -179,11 +401,8 @@ impl ComponentState { check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; } - current.types.push(TypeId { - type_size: ty.type_size(), - index: types.len(), - }); - types.push(ty); + let id = types.push_ty(ty); + current.types.push(id); Ok(()) } @@ -191,74 +410,490 @@ impl ComponentState { pub fn add_import( &mut self, import: crate::ComponentImport, - types: &TypeList, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, ) -> Result<()> { - let entity = self.check_type_ref(&import.ty, types, offset)?; + let mut entity = self.check_type_ref(&import.ty, features, types, offset)?; + self.add_entity( + &mut entity, + Some((import.name.as_str(), ExternKind::Import)), + features, + types, + offset, + )?; + self.toplevel_imported_resources.validate_extern( + import.name, + "import", + &entity, + types, + offset, + &mut self.kebab_named_externs, + &mut self.imports, + &mut self.type_info, + )?; + Ok(()) + } - let (len, max, desc) = match entity { + fn add_entity( + &mut self, + ty: &mut ComponentEntityType, + name_and_kind: Option<(&str, ExternKind)>, + features: &WasmFeatures, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + let kind = name_and_kind.map(|(_, k)| k); + let (len, max, desc) = match ty { ComponentEntityType::Module(id) => { - self.core_modules.push(id); + self.core_modules.push(*id); (self.core_modules.len(), MAX_WASM_MODULES, "modules") } ComponentEntityType::Component(id) => { - self.components.push(id); + self.components.push(*id); (self.components.len(), MAX_WASM_COMPONENTS, "components") } ComponentEntityType::Instance(id) => { - self.instances.push(id); + match kind { + Some(ExternKind::Import) => self.prepare_instance_import(id, types), + Some(ExternKind::Export) => self.prepare_instance_export(id, types), + None => {} + } + self.instances.push(*id); (self.instance_count(), MAX_WASM_INSTANCES, "instances") } ComponentEntityType::Func(id) => { - self.funcs.push(id); + self.funcs.push(*id); (self.function_count(), MAX_WASM_FUNCTIONS, "functions") } ComponentEntityType::Value(ty) => { - self.values.push((ty, false)); + self.check_value_support(features, offset)?; + let value_used = match kind { + Some(ExternKind::Import) | None => false, + Some(ExternKind::Export) => true, + }; + self.values.push((*ty, value_used)); (self.values.len(), MAX_WASM_VALUES, "values") } - ComponentEntityType::Type(id) => { - self.types.push(id); + ComponentEntityType::Type { + created, + referenced, + } => { + self.types.push(*created); + + // Extra logic here for resources being imported and exported. + // Note that if `created` is the same as `referenced` then this + // is the original introduction of the resource which is where + // `self.{imported,defined}_resources` are updated. + if let Type::Resource(id) = types[*created] { + match kind { + Some(ExternKind::Import) => { + // A fresh new resource is being imported into a + // component. This arises from the import section of + // a component or from the import declaration in a + // component type. In both cases a new imported + // resource is injected with a fresh new identifier + // into our state. + if created == referenced { + self.imported_resources.insert(id, vec![self.imports.len()]); + } + } + + Some(ExternKind::Export) => { + // A fresh resource is being exported from this + // component. This arises as part of the + // declaration of a component type, for example. In + // this situation brand new resource identifier is + // allocated and a definition is added, unlike the + // import case where an imported resource is added. + // Notably the representation of this new resource + // is unknown so it's listed as `None`. + if created == referenced { + self.defined_resources.insert(id, None); + } + + // If this is a type export of a resource type then + // update the `explicit_resources` list. A new + // export path is about to be created for this + // resource and this keeps track of that. + self.explicit_resources.insert(id, vec![self.exports.len()]); + } + + None => {} + } + } (self.types.len(), MAX_WASM_TYPES, "types") } }; check_max(len, 0, max, desc, offset)?; - self.type_size = combine_type_sizes(self.type_size, entity.type_size(), offset)?; + // Before returning perform the final validation of the type of the item + // being imported/exported. This will ensure that everything is + // appropriately named with respect to type definitions, resources, etc. + if let Some((name, kind)) = name_and_kind { + if !self.validate_and_register_named_types(Some(name), kind, ty, types) { + bail!( + offset, + "{} not valid to be used as {}", + ty.desc(), + kind.desc() + ); + } + } + Ok(()) + } + + /// Validates that the `ty` referenced only refers to named types internally + /// and then inserts anything necessary, if applicable, to the defined sets + /// within this component. + /// + /// This function will validate that `ty` only refers to named types. For + /// example if it's a record then all of its fields must refer to named + /// types. This consults either `self.imported_types` or + /// `self.exported_types` as specified by `kind`. Note that this is not + /// inherently recursive itself but it ends up being recursive since if + /// recursive members were named then all their components must also be + /// named. Consequently this check stops at the "one layer deep" position, + /// or more accurately the position where types must be named (e.g. tuples + /// aren't required to be named). + fn validate_and_register_named_types( + &mut self, + toplevel_name: Option<&str>, + kind: ExternKind, + ty: &ComponentEntityType, + types: &TypeAlloc, + ) -> bool { + if let ComponentEntityType::Type { created, .. } = ty { + // If this is a top-level resource then register it in the + // appropriate context so later validation of method-like-names + // works out. + if let Some(name) = toplevel_name { + if let Type::Resource(_) = types[*created] { + let cx = match kind { + ExternKind::Import => &mut self.toplevel_imported_resources, + ExternKind::Export => &mut self.toplevel_exported_resources, + }; + cx.register(name, *created); + } + } + } - if self - .imports - .insert(import.name.to_string(), entity) - .is_some() - { - bail!( - offset, - "duplicate import name `{}` already defined", - import.name, - ); + match self.kind { + ComponentKind::Component | ComponentKind::ComponentType => {} + ComponentKind::InstanceType => return true, + } + let set = match kind { + ExternKind::Import => &self.imported_types, + ExternKind::Export => &self.exported_types, + }; + match ty { + // When a type is imported or exported than any recursive type + // referred to by that import/export must additionally be exported + // or imported. Here this walks the "first layer" of the type which + // delegates to `TypeAlloc::type_named_type_id` to determine whether + // the components of the type being named here are indeed all they + // themselves named. + ComponentEntityType::Type { + created, + referenced, + } => { + if !self.all_valtypes_named(types, *referenced, set) { + return false; + } + match kind { + // Imported types are both valid for import and valid for + // export. + ExternKind::Import => { + self.imported_types.insert(*created); + self.exported_types.insert(*created); + } + ExternKind::Export => { + self.exported_types.insert(*created); + } + } + + true + } + + // Instances are slightly nuanced here. The general idea is that if + // an instance is imported, then any type exported by the instance + // is then also exported. Additionally for exports. To get this to + // work out this arm will recursively call + // `validate_and_register_named_types` which means that types are + // inserted into `self.{imported,exported}_types` as-we-go rather + // than all at once. + // + // This then recursively validates that all items in the instance + // itself are valid to import/export, recursive instances are + // captured, and everything is appropriately added to the right + // imported/exported set. + ComponentEntityType::Instance(i) => { + let ty = types[*i].unwrap_component_instance(); + ty.exports + .values() + .all(|ty| self.validate_and_register_named_types(None, kind, ty, types)) + } + + // All types referred to by a function must be named. + ComponentEntityType::Func(id) => self.all_valtypes_named(types, *id, set), + + ComponentEntityType::Value(ty) => types.type_named_valtype(ty, set), + + // Components/modules are always "closed" or "standalone" and don't + // need validation with respect to their named types. + ComponentEntityType::Component(_) | ComponentEntityType::Module(_) => true, } + } + fn all_valtypes_named(&self, types: &TypeAlloc, id: TypeId, set: &HashSet) -> bool { + match &types[id] { + Type::Defined(i) => match i { + // These types do not contain anything which must be + // named. + ComponentDefinedType::Primitive(_) + | ComponentDefinedType::Flags(_) + | ComponentDefinedType::Enum(_) => true, + + // Referenced types of all these aggregates must all be + // named. + ComponentDefinedType::Record(r) => { + r.fields.values().all(|t| types.type_named_valtype(t, set)) + } + ComponentDefinedType::Tuple(r) => { + r.types.iter().all(|t| types.type_named_valtype(t, set)) + } + ComponentDefinedType::Variant(r) => r + .cases + .values() + .filter_map(|t| t.ty.as_ref()) + .all(|t| types.type_named_valtype(t, set)), + ComponentDefinedType::Result { ok, err } => { + ok.as_ref() + .map(|t| types.type_named_valtype(t, set)) + .unwrap_or(true) + && err + .as_ref() + .map(|t| types.type_named_valtype(t, set)) + .unwrap_or(true) + } + ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + types.type_named_valtype(ty, set) + } - Ok(()) + // The resource referred to by own/borrow must be named. + ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => { + set.contains(id) + } + }, + + // Core wasm constructs are always valid with respect to + // exported types, since they have none. + Type::Module(_) | Type::Instance(_) | Type::Sub(_) => true, + + // Resource types, in isolation, are always valid to import + // or export since they're either attached to an import or + // being exported. + // + // Note that further validation of this happens in `finish`, + // too. + Type::Resource(_) => true, + + // Component types are validated as they are constructed, + // so all component types are valid to export if they've + // already been constructed. + Type::Component(_) => true, + + // Function types must have all their parameters/results named. + Type::ComponentFunc(ty) => ty + .params + .iter() + .map(|(_, ty)| ty) + .chain(ty.results.iter().map(|(_, ty)| ty)) + .all(|ty| types.type_named_valtype(ty, set)), + + // Instances must recursively have all referenced types named. + Type::ComponentInstance(ty) => ty.exports.values().all(|ty| { + let id = match ty { + ComponentEntityType::Module(id) + | ComponentEntityType::Func(id) + | ComponentEntityType::Value(ComponentValType::Type(id)) + | ComponentEntityType::Type { created: id, .. } + | ComponentEntityType::Instance(id) + | ComponentEntityType::Component(id) => *id, + ComponentEntityType::Value(ComponentValType::Primitive(_)) => return true, + }; + self.all_valtypes_named(types, id, set) + }), + } + } + + /// Updates the type `id` specified, an identifier for a component instance + /// type, to be imported into this component. + /// + /// Importing an instance type into a component specially handles the + /// defined resources registered in the instance type. Notably all + /// defined resources are "freshened" into brand new type variables and + /// these new variables are substituted within the type. This is what + /// creates a new `TypeId` and may update the `id` specified. + /// + /// One side effect of this operation, for example, is that if an instance + /// type is used twice to import two different instances then the instances + /// do not share resource types despite sharing the same original instance + /// type. + fn prepare_instance_import(&mut self, id: &mut TypeId, types: &mut TypeAlloc) { + let ty = types[*id].unwrap_component_instance(); + + // No special treatment for imports of instances which themselves have + // no defined resources + if ty.defined_resources.is_empty() { + return; + } + + let mut new_ty = ComponentInstanceType { + // Copied from the input verbatim + info: ty.info, + + // Copied over as temporary storage for now, and both of these are + // filled out and expanded below. + exports: ty.exports.clone(), + explicit_resources: ty.explicit_resources.clone(), + + // Explicitly discard this field since the + // defined resources are lifted into `self` + defined_resources: Default::default(), + }; + + // Create brand new resources for all defined ones in the instance. + let resources = (0..ty.defined_resources.len()) + .map(|_| types.alloc_resource_id()) + .collect::>(); + + // Build a map from the defined resources in `ty` to those in `new_ty`. + // + // As part of this same loop the new resources, which were previously + // defined in `ty`, now become imported variables in `self`. Their + // path for where they're imported is updated as well with + // `self.next_import_index` as the import-to-be soon. + let mut mapping = Remapping::default(); + let ty = types[*id].unwrap_component_instance(); + for (old, new) in ty.defined_resources.iter().zip(&resources) { + let prev = mapping.resources.insert(*old, *new); + assert!(prev.is_none()); + + let mut base = vec![self.imports.len()]; + base.extend(ty.explicit_resources[old].iter().copied()); + self.imported_resources.insert(*new, base); + } + + // Using the old-to-new resource mapping perform a substitution on + // the `exports` and `explicit_resources` fields of `new_ty` + for ty in new_ty.exports.values_mut() { + types.remap_component_entity(ty, &mut mapping); + } + for (id, path) in mem::take(&mut new_ty.explicit_resources) { + let id = *mapping.resources.get(&id).unwrap_or(&id); + new_ty.explicit_resources.insert(id, path); + } + + // Now that `new_ty` is complete finish its registration and then + // update `id` on the way out. + *id = types.push_ty(Type::ComponentInstance(Box::new(new_ty))); + } + + /// Prepares an instance type, pointed to `id`, for being exported as a + /// concrete instance from `self`. + /// + /// This will internally perform any resource "freshening" as required and + /// then additionally update metadata within `self` about resources being + /// exported or defined. + fn prepare_instance_export(&mut self, id: &mut TypeId, types: &mut TypeAlloc) { + // Exports of an instance mean that the enclosing context + // is inheriting the resources that the instance + // encapsulates. This means that the instance type + // recorded for this export will itself have no + // defined resources. + let ty = types[*id].unwrap_component_instance(); + + // Check to see if `defined_resources` is non-empty, and if so then + // "freshen" all the resources and inherit them to our own defined + // resources, updating `id` in the process. + // + // Note though that this specifically is not rewriting the resources of + // exported instances. The `defined_resources` set on instance types is + // a little subtle (see its documentation for more info), but the + // general idea is that for a concrete instance it's always empty. Only + // for instance type definitions does it ever have elements in it. + // + // That means that if this set is non-empty then what's happening is + // that we're in a type context an exporting an instance of a previously + // specified type. In this case all resources are required to be + // "freshened" to ensure that multiple exports of the same type all + // export different types of resources. + // + // And finally note that this operation empties out the + // `defined_resources` set of the type that is registered for the + // instance, as this export is modeled as producing a concrete instance. + if !ty.defined_resources.is_empty() { + let mut new_ty = ty.clone(); + let mut mapping = Remapping::default(); + for old in mem::take(&mut new_ty.defined_resources) { + let new = types.alloc_resource_id(); + mapping.resources.insert(old, new); + self.defined_resources.insert(new, None); + } + for ty in new_ty.exports.values_mut() { + types.remap_component_entity(ty, &mut mapping); + } + for (id, path) in mem::take(&mut new_ty.explicit_resources) { + let id = mapping.resources.get(&id).copied().unwrap_or(id); + new_ty.explicit_resources.insert(id, path); + } + *id = types.push_ty(Type::ComponentInstance(Box::new(new_ty))); + } + + // Any explicit resources in the instance are now additionally explicit + // in this component since it's exported. + // + // The path to each explicit resources gets one element prepended which + // is `self.next_export_index`, the index of the export about to be + // generated. + let ty = types[*id].unwrap_component_instance(); + for (id, path) in ty.explicit_resources.iter() { + let mut new_path = vec![self.exports.len()]; + new_path.extend(path); + self.explicit_resources.insert(*id, new_path); + } } pub fn add_export( &mut self, - name: &str, - ty: ComponentEntityType, + name: ComponentExternName<'_>, + mut ty: ComponentEntityType, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, check_limit: bool, ) -> Result<()> { if check_limit { check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?; } - - self.type_size = combine_type_sizes(self.type_size, ty.type_size(), offset)?; - - if self.exports.insert(name.to_string(), ty).is_some() { - bail!(offset, "duplicate export name `{name}` already defined"); - } - + self.add_entity( + &mut ty, + Some((name.as_str(), ExternKind::Export)), + features, + types, + offset, + )?; + self.toplevel_exported_resources.validate_extern( + name.into(), + "export", + &ty, + types, + offset, + &mut self.kebab_named_externs, + &mut self.exports, + &mut self.type_info, + )?; Ok(()) } @@ -271,9 +906,7 @@ impl ComponentState { offset: usize, ) -> Result<()> { let ty = self.function_type_at(type_index, types, offset)?; - let core_ty = types[self.core_function_at(core_func_index, offset)?] - .as_func_type() - .unwrap(); + let core_ty = types[self.core_function_at(core_func_index, offset)?].unwrap_func(); // Lifting a function is for an export, so match the expected canonical ABI // export signature @@ -309,12 +942,10 @@ impl ComponentState { &mut self, func_index: u32, options: Vec, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, ) -> Result<()> { - let ty = types[self.function_at(func_index, offset)?] - .as_component_func_type() - .unwrap(); + let ty = types[self.function_at(func_index, offset)?].unwrap_component_func(); // Lowering a function is for an import, so use a function type that matches // the expected canonical ABI import signature. @@ -322,46 +953,110 @@ impl ComponentState { self.check_options(None, &info, &options, types, offset)?; - let lowered_ty = Type::Func(info.into_func_type()); - - self.core_funcs.push(TypeId { - type_size: lowered_ty.type_size(), - index: types.len(), + let lowered_ty = Type::Sub(SubType { + is_final: false, + supertype_idx: None, + structural_type: StructuralType::Func(info.into_func_type()), }); - types.push(lowered_ty); + let id = types.push_ty(lowered_ty); + self.core_funcs.push(id); + + Ok(()) + } + pub fn resource_new( + &mut self, + resource: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + let rep = self.check_local_resource(resource, types, offset)?; + let core_ty = Type::Sub(SubType { + is_final: false, + supertype_idx: None, + structural_type: StructuralType::Func(FuncType::new([rep], [ValType::I32])), + }); + self.core_funcs.push(types.push_ty(core_ty)); Ok(()) } - pub fn add_component(&mut self, component: &mut Self, types: &mut TypeList) { - let ty = Type::Component(ComponentType { - type_size: component.type_size, - imports: mem::take(&mut component.imports), - exports: mem::take(&mut component.exports), + pub fn resource_drop( + &mut self, + resource: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + self.resource_at(resource, types, offset)?; + let core_ty = Type::Sub(SubType { + is_final: false, + supertype_idx: None, + structural_type: StructuralType::Func(FuncType::new([ValType::I32], [])), }); + self.core_funcs.push(types.push_ty(core_ty)); + Ok(()) + } - self.components.push(TypeId { - type_size: ty.type_size(), - index: types.len(), + pub fn resource_rep( + &mut self, + resource: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + let rep = self.check_local_resource(resource, types, offset)?; + let core_ty = Type::Sub(SubType { + is_final: false, + supertype_idx: None, + structural_type: StructuralType::Func(FuncType::new([ValType::I32], [rep])), }); + self.core_funcs.push(types.push_ty(core_ty)); + Ok(()) + } + + fn check_local_resource(&self, idx: u32, types: &TypeList, offset: usize) -> Result { + let id = self.resource_at(idx, types, offset)?; + let resource = types[id].unwrap_resource(); + match self.defined_resources.get(&resource).and_then(|rep| *rep) { + Some(ty) => Ok(ty), + None => bail!(offset, "type {idx} is not a local resource"), + } + } + + fn resource_at<'a>(&self, idx: u32, types: &'a TypeList, offset: usize) -> Result { + let id = self.type_at(idx, false, offset)?; + match &types[id] { + Type::Resource(_) => Ok(id), + _ => bail!(offset, "type index {} is not a resource type", idx), + } + } - types.push(ty); + pub fn add_component(&mut self, component: ComponentType, types: &mut TypeAlloc) -> Result<()> { + let ty = Type::Component(Box::new(component)); + let id = types.push_ty(ty); + self.components.push(id); + Ok(()) } pub fn add_instance( &mut self, instance: crate::ComponentInstance, - types: &mut TypeList, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, ) -> Result<()> { let instance = match instance { crate::ComponentInstance::Instantiate { component_index, args, - } => self.instantiate_component(component_index, args.into_vec(), types, offset)?, + } => self.instantiate_component( + component_index, + args.into_vec(), + features, + types, + offset, + )?, crate::ComponentInstance::FromExports(exports) => { - self.instantiate_exports(exports.into_vec(), types, offset)? + self.instantiate_exports(exports.into_vec(), features, types, offset)? } }; @@ -373,7 +1068,8 @@ impl ComponentState { pub fn add_alias( components: &mut [Self], alias: crate::ComponentAlias, - types: &TypeList, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, ) -> Result<()> { match alias { @@ -385,6 +1081,7 @@ impl ComponentState { instance_index, kind, name, + features, types, offset, ), @@ -406,7 +1103,9 @@ impl ComponentState { ComponentOuterAliasKind::CoreType => { Self::alias_core_type(components, count, index, offset) } - ComponentOuterAliasKind::Type => Self::alias_type(components, count, index, offset), + ComponentOuterAliasKind::Type => { + Self::alias_type(components, count, index, types, offset) + } ComponentOuterAliasKind::Component => { Self::alias_component(components, count, index, offset) } @@ -419,9 +1118,16 @@ impl ComponentState { func_index: u32, args: &[u32], results: u32, + features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<()> { + if !features.component_model_values { + bail!( + offset, + "support for component model `value`s is not enabled" + ); + } if self.has_start { return Err(BinaryReaderError::new( "component cannot have more than one start function", @@ -429,9 +1135,7 @@ impl ComponentState { )); } - let ft = types[self.function_at(func_index, offset)?] - .as_component_func_type() - .unwrap(); + let ft = types[self.function_at(func_index, offset)?].unwrap_component_func(); if ft.params.len() != args.len() { bail!( @@ -451,19 +1155,13 @@ impl ComponentState { ); } + let cx = SubtypeCx::new(types, types); for (i, ((_, ty), arg)) in ft.params.iter().zip(args).enumerate() { // Ensure the value's type is a subtype of the parameter type - if !ComponentValType::internal_is_subtype_of( - self.value_at(*arg, offset)?, - types, - ty, - types, - ) { - bail!( - offset, - "value type mismatch for component start function argument {i}" - ); - } + cx.component_val_type(self.value_at(*arg, offset)?, ty, offset) + .with_context(|| { + format!("value type mismatch for component start function argument {i}") + })?; } for (_, ty) in ft.results.iter() { @@ -531,9 +1229,7 @@ impl ComponentState { CanonicalOption::Realloc(idx) => { realloc = match realloc { None => { - let ty = types[self.core_function_at(*idx, offset)?] - .as_func_type() - .unwrap(); + let ty = types[self.core_function_at(*idx, offset)?].unwrap_func(); if ty.params() != [ValType::I32, ValType::I32, ValType::I32, ValType::I32] || ty.results() != [ValType::I32] @@ -563,9 +1259,7 @@ impl ComponentState { ) })?; - let ty = types[self.core_function_at(*idx, offset)?] - .as_func_type() - .unwrap(); + let ty = types[self.core_function_at(*idx, offset)?].unwrap_func(); if ty.params() != core_ty.results() || !ty.results().is_empty() { return Err(BinaryReaderError::new( @@ -603,28 +1297,32 @@ impl ComponentState { Ok(()) } - pub fn check_type_ref( - &self, + fn check_type_ref( + &mut self, ty: &ComponentTypeRef, - types: &TypeList, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, ) -> Result { Ok(match ty { ComponentTypeRef::Module(index) => { let id = self.type_at(*index, true, offset)?; - types[id].as_module_type().ok_or_else(|| { - format_err!(offset, "core type index {index} is not a module type") - })?; + match &types[id] { + Type::Module(_) => {} + _ => bail!(offset, "core type index {index} is not a module type"), + } ComponentEntityType::Module(id) } ComponentTypeRef::Func(index) => { let id = self.type_at(*index, false, offset)?; - types[id].as_component_func_type().ok_or_else(|| { - format_err!(offset, "type index {index} is not a function type") - })?; + match &types[id] { + Type::ComponentFunc(_) => {} + _ => bail!(offset, "type index {index} is not a function type"), + } ComponentEntityType::Func(id) } ComponentTypeRef::Value(ty) => { + self.check_value_support(features, offset)?; let ty = match ty { crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty), crate::ComponentValType::Type(index) => { @@ -633,21 +1331,36 @@ impl ComponentState { }; ComponentEntityType::Value(ty) } - ComponentTypeRef::Type(TypeBounds::Eq, index) => { - ComponentEntityType::Type(self.type_at(*index, false, offset)?) + ComponentTypeRef::Type(TypeBounds::Eq(index)) => { + let referenced = self.type_at(*index, false, offset)?; + let created = types.with_unique(referenced); + ComponentEntityType::Type { + referenced, + created, + } + } + ComponentTypeRef::Type(TypeBounds::SubResource) => { + let id = types.alloc_resource_id(); + let id = types.push_ty(Type::Resource(id)); + ComponentEntityType::Type { + referenced: id, + created: id, + } } ComponentTypeRef::Instance(index) => { let id = self.type_at(*index, false, offset)?; - types[id].as_component_instance_type().ok_or_else(|| { - format_err!(offset, "type index {index} is not an instance type") - })?; + match &types[id] { + Type::ComponentInstance(_) => {} + _ => bail!(offset, "type index {index} is not an instance type"), + } ComponentEntityType::Instance(id) } ComponentTypeRef::Component(index) => { let id = self.type_at(*index, false, offset)?; - types[id].as_component_type().ok_or_else(|| { - format_err!(offset, "type index {index} is not a component type") - })?; + match &types[id] { + Type::Component(_) => {} + _ => bail!(offset, "type index {index} is not a component type"), + } ComponentEntityType::Component(id) } }) @@ -656,9 +1369,11 @@ impl ComponentState { pub fn export_to_entity_type( &mut self, export: &crate::ComponentExport, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, ) -> Result { - Ok(match export.kind { + let actual = match export.kind { ComponentExternalKind::Module => { ComponentEntityType::Module(self.module_at(export.index, offset)?) } @@ -666,10 +1381,16 @@ impl ComponentState { ComponentEntityType::Func(self.function_at(export.index, offset)?) } ComponentExternalKind::Value => { + self.check_value_support(features, offset)?; ComponentEntityType::Value(*self.value_at(export.index, offset)?) } ComponentExternalKind::Type => { - ComponentEntityType::Type(self.type_at(export.index, false, offset)?) + let referenced = self.type_at(export.index, false, offset)?; + let created = types.with_unique(referenced); + ComponentEntityType::Type { + referenced, + created, + } } ComponentExternalKind::Instance => { ComponentEntityType::Instance(self.instance_at(export.index, offset)?) @@ -677,14 +1398,25 @@ impl ComponentState { ComponentExternalKind::Component => { ComponentEntityType::Component(self.component_at(export.index, offset)?) } - }) + }; + + let ascribed = match &export.ty { + Some(ty) => self.check_type_ref(ty, features, types, offset)?, + None => return Ok(actual), + }; + + SubtypeCx::new(types, types) + .component_entity_type(&actual, &ascribed, offset) + .with_context(|| "ascribed type of export is not compatible with item's type")?; + + Ok(ascribed) } fn create_module_type( components: &[Self], decls: Vec, features: &WasmFeatures, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, ) -> Result { let mut state = Module::default(); @@ -692,11 +1424,11 @@ impl ComponentState { for decl in decls { match decl { crate::ModuleTypeDeclaration::Type(ty) => { - state.add_type(ty, features, types, offset, true)?; + state.add_types(&RecGroup::Single(ty), features, types, offset, true)?; } crate::ModuleTypeDeclaration::Export { name, ty } => { let ty = state.check_type_ref(&ty, features, types, offset)?; - state.add_export(name, ty, features, offset, true)?; + state.add_export(name, ty, features, offset, true, types)?; } crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => { if count > 1 { @@ -709,7 +1441,7 @@ impl ComponentState { crate::OuterAliasKind::Type => { let ty = if count == 0 { // Local alias, check the local module state - state.type_at(index, offset)? + state.type_id_at(index, offset)? } else { // Otherwise, check the enclosing component state let component = @@ -732,7 +1464,7 @@ impl ComponentState { let imports = state.imports_for_module_type(offset)?; Ok(ModuleType { - type_size: state.type_size, + info: TypeInfo::core(state.type_size), imports, exports: state.exports, }) @@ -742,10 +1474,10 @@ impl ComponentState { components: &mut Vec, decls: Vec, features: &WasmFeatures, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, ) -> Result { - components.push(ComponentState::default()); + components.push(ComponentState::new(ComponentKind::ComponentType)); for decl in decls { match decl { @@ -757,57 +1489,32 @@ impl ComponentState { } crate::ComponentTypeDeclaration::Export { name, ty } => { let current = components.last_mut().unwrap(); - let ty = current.check_type_ref(&ty, types, offset)?; - current.add_export(name, ty, offset, true)?; + let ty = current.check_type_ref(&ty, features, types, offset)?; + current.add_export(name, ty, features, types, offset, true)?; } crate::ComponentTypeDeclaration::Import(import) => { components .last_mut() .unwrap() - .add_import(import, types, offset)?; + .add_import(import, features, types, offset)?; } crate::ComponentTypeDeclaration::Alias(alias) => { - match alias { - crate::ComponentAlias::Outer { kind, count, index } - if kind == ComponentOuterAliasKind::CoreType - || kind == ComponentOuterAliasKind::Type => - { - match kind { - ComponentOuterAliasKind::CoreType => { - Self::alias_core_type(components, count, index, offset)? - } - ComponentOuterAliasKind::Type => { - Self::alias_type(components, count, index, offset)? - } - _ => unreachable!(), - } - } - _ => return Err(BinaryReaderError::new( - "only outer type aliases are allowed in component type declarations", - offset, - )), - } + Self::add_alias(components, alias, features, types, offset)?; } }; } - let state = components.pop().unwrap(); - - Ok(ComponentType { - type_size: state.type_size, - imports: state.imports, - exports: state.exports, - }) + components.pop().unwrap().finish(types, offset) } fn create_instance_type( components: &mut Vec, decls: Vec, features: &WasmFeatures, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, ) -> Result { - components.push(ComponentState::default()); + components.push(ComponentState::new(ComponentKind::InstanceType)); for decl in decls { match decl { @@ -819,39 +1526,44 @@ impl ComponentState { } crate::InstanceTypeDeclaration::Export { name, ty } => { let current = components.last_mut().unwrap(); - let ty = current.check_type_ref(&ty, types, offset)?; - current.add_export(name, ty, offset, true)?; - } - crate::InstanceTypeDeclaration::Alias(alias) => match alias { - crate::ComponentAlias::Outer { kind, count, index } - if kind == ComponentOuterAliasKind::CoreType - || kind == ComponentOuterAliasKind::Type => - { - match kind { - ComponentOuterAliasKind::CoreType => { - Self::alias_core_type(components, count, index, offset)? - } - ComponentOuterAliasKind::Type => { - Self::alias_type(components, count, index, offset)? - } - _ => unreachable!(), - } - } - _ => { - return Err(BinaryReaderError::new( - "only outer type aliases are allowed in instance type declarations", - offset, - )) - } - }, + let ty = current.check_type_ref(&ty, features, types, offset)?; + current.add_export(name, ty, features, types, offset, true)?; + } + crate::InstanceTypeDeclaration::Alias(alias) => { + Self::add_alias(components, alias, features, types, offset)?; + } }; } - let state = components.pop().unwrap(); + let mut state = components.pop().unwrap(); + + assert!(state.imported_resources.is_empty()); Ok(ComponentInstanceType { - type_size: state.type_size, - kind: ComponentInstanceTypeKind::Defined(state.exports), + info: state.type_info, + + // The defined resources for this instance type are those listed on + // the component state. The path to each defined resource is + // guaranteed to live within the `explicit_resources` map since, + // when in the type context, the introduction of any defined + // resource must have been done with `(export "x" (type (sub + // resource)))` which, in a sense, "fuses" the introduction of the + // variable with the export. This means that all defined resources, + // if any, should be guaranteed to have an `explicit_resources` path + // listed. + defined_resources: mem::take(&mut state.defined_resources) + .into_iter() + .map(|(id, rep)| { + assert!(rep.is_none()); + id + }) + .collect(), + + // The map of what resources are explicitly exported and where + // they're exported is plumbed through as-is. + explicit_resources: mem::take(&mut state.explicit_resources), + + exports: mem::take(&mut state.exports), }) } @@ -861,23 +1573,27 @@ impl ComponentState { types: &TypeList, offset: usize, ) -> Result { - let mut type_size = 1; + let mut info = TypeInfo::new(); - let mut set = HashSet::with_capacity(std::cmp::max(ty.params.len(), ty.results.len())); + let mut set = + HashSet::with_capacity(std::cmp::max(ty.params.len(), ty.results.type_count())); let params = ty .params .iter() .map(|(name, ty)| { - if let Some(name) = name { - Self::check_name(name, "function parameter", offset)?; - if !set.insert(name) { - return Err(BinaryReaderError::new("duplicate parameter name", offset)); - } + let name = to_kebab_str(name, "function parameter", offset)?; + if !set.insert(name) { + bail!( + offset, + "function parameter name `{name}` conflicts with previous parameter name `{prev}`", + prev = set.get(&name).unwrap(), + ); } + let ty = self.create_component_val_type(*ty, types, offset)?; - type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; - Ok((name.map(ToOwned::to_owned), ty)) + info.combine(ty.info(types), offset)?; + Ok((name.to_owned(), ty)) }) .collect::>()?; @@ -887,38 +1603,43 @@ impl ComponentState { .results .iter() .map(|(name, ty)| { - if let Some(name) = name { - Self::check_name(name, "function result", offset)?; - if !set.insert(name) { - return Err(BinaryReaderError::new("duplicate result name", offset)); - } - } + let name = name + .map(|name| { + let name = to_kebab_str(name, "function result", offset)?; + if !set.insert(name) { + bail!( + offset, + "function result name `{name}` conflicts with previous result name `{prev}`", + prev = set.get(name).unwrap(), + ); + } + + Ok(name.to_owned()) + }) + .transpose()?; + let ty = self.create_component_val_type(*ty, types, offset)?; - type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; - Ok((name.map(ToOwned::to_owned), ty)) + let ty_info = ty.info(types); + if ty_info.contains_borrow() { + bail!(offset, "function result cannot contain a `borrow` type"); + } + info.combine(ty.info(types), offset)?; + Ok((name, ty)) }) .collect::>()?; Ok(ComponentFuncType { - type_size, + info, params, results, }) } - fn check_name(name: &str, desc: &str, offset: usize) -> Result<()> { - if name.is_empty() { - bail!(offset, "{desc} name cannot be empty"); - } - - Ok(()) - } - fn instantiate_module( &self, module_index: u32, module_args: Vec, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, ) -> Result { fn insert_arg<'a>( @@ -944,16 +1665,16 @@ impl ComponentState { for module_arg in module_args { match module_arg.kind { InstantiationArgKind::Instance => { - let instance_type = types[self.core_instance_at(module_arg.index, offset)?] - .as_instance_type() - .unwrap(); + let instance_type = + types[self.core_instance_at(module_arg.index, offset)?].unwrap_instance(); insert_arg(module_arg.name, instance_type, &mut args, offset)?; } } } // Validate the arguments - let module_type = types[module_type_id].as_module_type().unwrap(); + let module_type = types[module_type_id].unwrap_module(); + let cx = SubtypeCx::new(types, types); for ((module, name), expected) in module_type.imports.iter() { let instance = args.get(module.as_str()).ok_or_else(|| { format_err!( @@ -973,300 +1694,437 @@ impl ComponentState { ) })?; - match (arg, expected) { - (EntityType::Func(_), EntityType::Func(_)) - | (EntityType::Table(_), EntityType::Table(_)) - | (EntityType::Memory(_), EntityType::Memory(_)) - | (EntityType::Global(_), EntityType::Global(_)) - | (EntityType::Tag(_), EntityType::Tag(_)) => {} - _ => { - bail!( - offset, - "module instantiation argument `{module}` exports \ - an item named `{name}` but it is not a {}", - expected.desc() - ) - } - } + cx.entity_type(arg, expected, offset).with_context(|| { + format!( + "type mismatch for export `{name}` of module \ + instantiation argument `{module}`" + ) + })?; + } - if !EntityType::internal_is_subtype_of(arg, types, expected, types) { - bail!( - offset, - "{} type mismatch for export `{name}` of module \ - instantiation argument `{module}`", - expected.desc(), - ); - } + let mut info = TypeInfo::new(); + for (_, ty) in module_type.exports.iter() { + info.combine(ty.info(types), offset)?; } - let ty = Type::Instance(InstanceType { - type_size: module_type - .exports - .iter() - .fold(1, |acc, (_, ty)| acc + ty.type_size()), + let ty = Type::Instance(Box::new(InstanceType { + info, kind: InstanceTypeKind::Instantiated(module_type_id), - }); - - let id = TypeId { - type_size: ty.type_size(), - index: types.len(), - }; + })); - types.push(ty); - - Ok(id) + Ok(types.push_ty(ty)) } fn instantiate_component( &mut self, component_index: u32, component_args: Vec, - types: &mut TypeList, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, ) -> Result { - fn insert_arg<'a>( - name: &'a str, - arg: ComponentEntityType, - args: &mut IndexMap<&'a str, ComponentEntityType>, - offset: usize, - ) -> Result<()> { - if args.insert(name, arg).is_some() { - bail!( - offset, - "duplicate component instantiation argument named `{name}`" - ); - } - - Ok(()) - } - let component_type_id = self.component_at(component_index, offset)?; let mut args = IndexMap::new(); // Populate the arguments for component_arg in component_args { - match component_arg.kind { + let ty = match component_arg.kind { ComponentExternalKind::Module => { - insert_arg( - component_arg.name, - ComponentEntityType::Module(self.module_at(component_arg.index, offset)?), - &mut args, - offset, - )?; + ComponentEntityType::Module(self.module_at(component_arg.index, offset)?) } ComponentExternalKind::Component => { - insert_arg( - component_arg.name, - ComponentEntityType::Component( - self.component_at(component_arg.index, offset)?, - ), - &mut args, - offset, - )?; + ComponentEntityType::Component(self.component_at(component_arg.index, offset)?) } ComponentExternalKind::Instance => { - insert_arg( - component_arg.name, - ComponentEntityType::Instance( - self.instance_at(component_arg.index, offset)?, - ), - &mut args, - offset, - )?; + ComponentEntityType::Instance(self.instance_at(component_arg.index, offset)?) } ComponentExternalKind::Func => { - insert_arg( - component_arg.name, - ComponentEntityType::Func(self.function_at(component_arg.index, offset)?), - &mut args, - offset, - )?; + ComponentEntityType::Func(self.function_at(component_arg.index, offset)?) } ComponentExternalKind::Value => { - insert_arg( - component_arg.name, - ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?), - &mut args, - offset, - )?; + self.check_value_support(features, offset)?; + ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?) } ComponentExternalKind::Type => { - // Type arguments are ignored - } - } - } - - // Validate the arguments - let component_type = types[component_type_id].as_component_type().unwrap(); - for (name, expected) in component_type.imports.iter() { - match args.get(name.as_str()) { - Some(arg) => { - match (arg, expected) { - (ComponentEntityType::Module(_), ComponentEntityType::Module(_)) - | (ComponentEntityType::Component(_), ComponentEntityType::Component(_)) - | (ComponentEntityType::Instance(_), ComponentEntityType::Instance(_)) - | (ComponentEntityType::Func(_), ComponentEntityType::Func(_)) - | (ComponentEntityType::Value(_), ComponentEntityType::Value(_)) => {} - _ => { - bail!( - offset, - "expected component instantiation argument \ - `{name}` to be of type `{}`", - expected.desc() - ) - } - }; - - if !ComponentEntityType::internal_is_subtype_of(arg, types, expected, types) { - bail!( - offset, - "{} type mismatch for component instantiation argument `{name}`", - expected.desc(), - ); + let ty = self.type_at(component_arg.index, false, offset)?; + ComponentEntityType::Type { + referenced: ty, + created: ty, } } - None => { + }; + match args.entry(component_arg.name.to_string()) { + Entry::Occupied(e) => { bail!( offset, - "missing component instantiation argument named `{name}`" + "instantiation argument `{name}` conflicts with previous argument `{prev}`", + prev = e.key(), + name = component_arg.name ); } + Entry::Vacant(e) => { + e.insert(ty); + } } } - let ty = Type::ComponentInstance(ComponentInstanceType { - type_size: component_type - .exports - .iter() - .fold(1, |acc, (_, ty)| acc + ty.type_size()), - kind: ComponentInstanceTypeKind::Instantiated(component_type_id), - }); + // Here comes the fun part of the component model, we're instantiating + // the component with type `component_type_id` with the `args` + // specified. Easy enough! + // + // This operation, however, is one of the lynchpins of safety in the + // component model. Additionally what this ends up implementing ranges + // from "well just check the types are equal" to "let's have a + // full-blown ML-style module type system in the component model". There + // are primarily two major tricky pieces to the component model which + // make this operation, instantiating components, hard: + // + // 1. Components can import and exports other components. This means + // that arguments to instantiation are along the lines of functions + // being passed to functions or similar. Effectively this means that + // the term "variance" comes into play with either contravariance + // or covariance depending on where you are in typechecking. This is + // one of the main rationales, however, that this check below is a + // check for subtyping as opposed to exact type equivalence. For + // example an instance that exports something is a subtype of an + // instance that exports nothing. Components get a bit trick since + // they both have imports and exports. My way of thinking about it + // is "who's asking for what". If you're asking for imports then + // I need to at least supply those imports, but I can possibly + // supply more. If you're asking for a thing which you'll give a set + // of imports, then I can give you something which takes less imports + // because what you give still suffices. (things like that). The + // real complication with components, however, comes with... + // + // 2. Resources. Resources in the component model are akin to "abstract + // types". They're not abstract in the sense that they have no + // representation, they're always backed by a 32-bit integer right + // now. Instead they're abstract in the sense that some components + // aren't allowed to understand the representation of a resource. + // For example if you import a resource you can't get the underlying + // internals of it. Furthermore the resource is strictly tracked + // within the component with `own` and `borrow` runtime semantics. + // The hardest part about resources, though, is handling them as + // part of instantiation and subtyping. + // + // For example one major aspect of resources is that if a component + // exports a resource then each instantiation of the component + // produces a fresh resource type. This means that the type recorded + // for the instantiation here can't simply be "I instantiated + // component X" since in such a situation the type of all + // instantiations would be the same, which they aren't. + // + // This sort of subtelty comes up quite frequently for resources. + // This file contains references to `imported_resources` and + // `defined_resources` for example which refer to the formal + // nature of components and their abstract variables. Specifically + // for instantiation though we're eventually faced with the problem + // of subtype checks where resource subtyping is defined as "does + // your id equal mine". Naively implemented that means anything with + // resources isn't subtypes of anything else since resource ids are + // unique between components. Instead what actually needs to happen + // is types need to be substituted. + // + // Much of the complexity here is not actually apparent here in this + // literal one function. Instead it's spread out across validation + // in this file and type-checking in the `types.rs` module. Note that + // the "spread out" nature isn't because we're bad maintainers + // (hopefully), but rather it's quite infectious how many parts need + // to handle resources and account for defined/imported variables. + // + // For example only one subtyping method is called here where `args` is + // passed in. This method is quite recursive in its nature though and + // will internally touch all the fields that this file maintains to + // end up putting into various bits and pieces of type information. + // + // Unfortunately there's probably not really a succinct way to read + // this method and understand everything. If you've written ML module + // type systems this will probably look quite familiar, but otherwise + // the whole system is not really easily approachable at this time. It's + // hoped in the future that there's a formalism to refer to which will + // make things more clear as the code would be able to reference this + // hypothetical formalism. Until that's the case, though, these + // comments are hopefully enough when augmented with communication with + // the authors. + + let component_type = types[component_type_id].unwrap_component(); + let mut exports = component_type.exports.clone(); + let mut info = TypeInfo::new(); + for (_, ty) in component_type.exports.iter() { + info.combine(ty.info(types), offset)?; + } - let id = TypeId { - type_size: ty.type_size(), - index: types.len(), - }; + // Perform the subtype check that `args` matches the imports of + // `component_type_id`. The result of this subtype check is the + // production of a mapping of resource types from the imports to the + // arguments provided. This is a substitution map which is then used + // below to perform a substitution into the exports of the instance + // since the types of the exports are now in terms of whatever was + // supplied as imports. + let mut mapping = SubtypeCx::new(types, types).open_instance_type( + &args, + component_type_id, + ExternKind::Import, + offset, + )?; + + // Part of the instantiation of a component is that all of its + // defined resources become "fresh" on each instantiation. This + // means that each instantiation of a component gets brand new type + // variables representing its defined resources, modeling that each + // instantiation produces distinct types. The freshening is performed + // here by allocating new ids and inserting them into `mapping`. + // + // Note that technically the `mapping` from subtyping should be applied + // first and then the mapping for freshening should be applied + // afterwards. The keys of the map from subtyping are the imported + // resources from this component which are disjoint from its defined + // resources. That means it should be possible to place everything + // into one large map which maps from: + // + // * the component's imported resources go to whatever was explicitly + // supplied in the import map + // * the component's defined resources go to fresh new resources + // + // These two remapping operations can then get folded into one by + // placing everything in the same `mapping` and using that for a remap + // only once. + let fresh_defined_resources = (0..component_type.defined_resources.len()) + .map(|_| types.alloc_resource_id()) + .collect::>(); + let component_type = types[component_type_id].unwrap_component(); + for ((old, _path), new) in component_type + .defined_resources + .iter() + .zip(&fresh_defined_resources) + { + let prev = mapping.resources.insert(*old, *new); + assert!(prev.is_none()); + } + + // Perform the remapping operation over all the exports that will be + // listed for the final instance type. Note that this is performed + // both for all the export types in addition to the explicitly exported + // resources list. + // + // Note that this is a crucial step of the instantiation process which + // is intentionally transforming the type of a component based on the + // variables provided by imports and additionally ensuring that all + // references to the component's defined resources are rebound to the + // fresh ones introduced just above. + for entity in exports.values_mut() { + types.remap_component_entity(entity, &mut mapping); + } + let component_type = types[component_type_id].unwrap_component(); + let explicit_resources = component_type + .explicit_resources + .iter() + .map(|(id, path)| { + ( + mapping.resources.get(id).copied().unwrap_or(*id), + path.clone(), + ) + }) + .collect::>(); + + // Technically in the last formalism that was consulted in writing this + // implementation there are two further steps that are part of the + // instantiation process: + // + // 1. The set of defined resources from the instance created, which are + // added to the outer component, is the subset of the instance's + // original defined resources and the free variables of the exports. + // + // 2. Each element of this subset is required to be "explicit in" the + // instance, or otherwise explicitly exported somewhere within the + // instance. + // + // With the syntactic structure of the component model, however, neither + // of these conditions should be necessary. The main reason for this is + // that this function is specifically dealing with instantiation of + // components which should already have these properties validated + // about them. Subsequently we shouldn't have to re-check them. + // + // In debug mode, however, do a sanity check. + if cfg!(debug_assertions) { + let mut free = IndexSet::new(); + for ty in exports.values() { + types.free_variables_component_entity(ty, &mut free); + } + assert!(fresh_defined_resources.is_subset(&free)); + for resource in fresh_defined_resources.iter() { + assert!(explicit_resources.contains_key(resource)); + } + } - types.push(ty); + // And as the final step of the instantiation process all of the + // new defined resources from this component instantiation are moved + // onto `self`. Note that concrete instances never have defined + // resources (see more comments in `instantiate_exports`) so the + // `defined_resources` listing in the final type is always empty. This + // represents how by having a concrete instance the definitions + // referred to in that instance are now problems for the outer + // component rather than the inner instance since the instance is bound + // to the component. + // + // All defined resources here have no known representation, so they're + // all listed with `None`. Also note that none of the resources were + // exported yet so `self.explicit_resources` is not updated yet. If + // this instance is exported, however, it'll consult the type's + // `explicit_resources` array and use that appropriately. + for resource in fresh_defined_resources { + self.defined_resources.insert(resource, None); + } - Ok(id) + let ty = Type::ComponentInstance(Box::new(ComponentInstanceType { + info, + defined_resources: Default::default(), + explicit_resources, + exports, + })); + Ok(types.push_ty(ty)) } fn instantiate_exports( &mut self, exports: Vec, - types: &mut TypeList, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, ) -> Result { - fn insert_export( - name: &str, - export: ComponentEntityType, - exports: &mut IndexMap, - type_size: &mut usize, - offset: usize, - ) -> Result<()> { - *type_size = combine_type_sizes(*type_size, export.type_size(), offset)?; - - if exports.insert(name.to_string(), export).is_some() { - bail!( - offset, - "duplicate instantiation export name `{name}` already defined", - ) - } + let mut info = TypeInfo::new(); + let mut inst_exports = IndexMap::new(); + let mut explicit_resources = IndexMap::new(); + let mut kebab_names = IndexSet::new(); - Ok(()) - } + // NB: It's intentional that this context is empty since no indices are + // introduced in the bag-of-exports construct which means there's no + // way syntactically to register something inside of this. + let names = KebabNameContext::default(); - let mut type_size = 1; - let mut inst_exports = IndexMap::new(); for export in exports { - match export.kind { + assert!(export.ty.is_none()); + let ty = match export.kind { ComponentExternalKind::Module => { - insert_export( - export.name, - ComponentEntityType::Module(self.module_at(export.index, offset)?), - &mut inst_exports, - &mut type_size, - offset, - )?; + ComponentEntityType::Module(self.module_at(export.index, offset)?) } ComponentExternalKind::Component => { - insert_export( - export.name, - ComponentEntityType::Component(self.component_at(export.index, offset)?), - &mut inst_exports, - &mut type_size, - offset, - )?; + ComponentEntityType::Component(self.component_at(export.index, offset)?) } ComponentExternalKind::Instance => { - insert_export( - export.name, - ComponentEntityType::Instance(self.instance_at(export.index, offset)?), - &mut inst_exports, - &mut type_size, - offset, - )?; + let ty = self.instance_at(export.index, offset)?; + + // When an instance is exported from an instance then + // all explicitly exported resources on the sub-instance are + // now also listed as exported resources on the outer + // instance, just with one more element in their path. + explicit_resources.extend( + types[ty] + .unwrap_component_instance() + .explicit_resources + .iter() + .map(|(id, path)| { + let mut new_path = vec![inst_exports.len()]; + new_path.extend(path); + (*id, new_path) + }), + ); + ComponentEntityType::Instance(ty) } ComponentExternalKind::Func => { - insert_export( - export.name, - ComponentEntityType::Func(self.function_at(export.index, offset)?), - &mut inst_exports, - &mut type_size, - offset, - )?; + ComponentEntityType::Func(self.function_at(export.index, offset)?) } ComponentExternalKind::Value => { - insert_export( - export.name, - ComponentEntityType::Value(*self.value_at(export.index, offset)?), - &mut inst_exports, - &mut type_size, - offset, - )?; + self.check_value_support(features, offset)?; + ComponentEntityType::Value(*self.value_at(export.index, offset)?) } ComponentExternalKind::Type => { - insert_export( - export.name, - ComponentEntityType::Type(self.type_at(export.index, false, offset)?), - &mut inst_exports, - &mut type_size, - offset, - )?; + let ty = self.type_at(export.index, false, offset)?; + // If this is an export of a resource type be sure to + // record that in the explicit list with the appropriate + // path because if this instance ends up getting used + // it'll count towards the "explicit in" check. + if let Type::Resource(id) = &types[ty] { + explicit_resources.insert(*id, vec![inst_exports.len()]); + } + ComponentEntityType::Type { + referenced: ty, + // The created type index here isn't used anywhere + // in index spaces because a "bag of exports" + // doesn't build up its own index spaces. Just fill + // in the same index here in this case as what's + // referenced. + created: ty, + } } - } - } - - let ty = Type::ComponentInstance(ComponentInstanceType { - type_size, - kind: ComponentInstanceTypeKind::Exports(inst_exports), - }); - - let id = TypeId { - type_size: ty.type_size(), - index: types.len(), - }; + }; - types.push(ty); + names.validate_extern( + export.name.into(), + "instance export", + &ty, + types, + offset, + &mut kebab_names, + &mut inst_exports, + &mut info, + )?; + } - Ok(id) + let ty = Type::ComponentInstance(Box::new(ComponentInstanceType { + info, + explicit_resources, + exports: inst_exports, + + // NB: the list of defined resources for this instance itself + // is always empty. Even if this instance exports resources, + // it's empty. + // + // The reason for this is a bit subtle. The general idea, though, is + // that the defined resources list here is only used for instance + // types that are sort of "floating around" and haven't actually + // been attached to something yet. For example when an instance type + // is simply declared it can have defined resources introduced + // through `(export "name" (type (sub resource)))`. These + // definitions, however, are local to the instance itself and aren't + // defined elsewhere. + // + // Here, though, no new definitions were introduced. The instance + // created here is a "bag of exports" which could only refer to + // preexisting items. This means that inherently no new resources + // were created so there's nothing to put in this list. Any + // resources referenced by the instance must be bound by the outer + // component context or further above. + // + // Furthermore, however, actual instances of instances, which this + // is, aren't allowed to have defined resources. Instead the + // resources would have to be injected into the outer component + // enclosing the instance. That means that even if bag-of-exports + // could declare a new resource then the resource would be moved + // from here to `self.defined_resources`. This doesn't exist at this + // time, though, so this still remains empty and + // `self.defined_resources` remains unperturbed. + defined_resources: Default::default(), + })); + + Ok(types.push_ty(ty)) } fn instantiate_core_exports( &mut self, exports: Vec, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, ) -> Result { fn insert_export( + types: &TypeList, name: &str, export: EntityType, exports: &mut IndexMap, - type_size: &mut usize, + info: &mut TypeInfo, offset: usize, ) -> Result<()> { - *type_size = combine_type_sizes(*type_size, export.type_size(), offset)?; + info.combine(export.info(types), offset)?; if exports.insert(name.to_string(), export).is_some() { bail!( @@ -1278,65 +2136,63 @@ impl ComponentState { Ok(()) } - let mut type_size = 1; + let mut info = TypeInfo::new(); let mut inst_exports = IndexMap::new(); for export in exports { match export.kind { ExternalKind::Func => { insert_export( + types, export.name, EntityType::Func(self.core_function_at(export.index, offset)?), &mut inst_exports, - &mut type_size, + &mut info, offset, )?; } ExternalKind::Table => insert_export( + types, export.name, EntityType::Table(*self.table_at(export.index, offset)?), &mut inst_exports, - &mut type_size, + &mut info, offset, )?, ExternalKind::Memory => insert_export( + types, export.name, EntityType::Memory(*self.memory_at(export.index, offset)?), &mut inst_exports, - &mut type_size, + &mut info, offset, )?, ExternalKind::Global => { insert_export( + types, export.name, EntityType::Global(*self.global_at(export.index, offset)?), &mut inst_exports, - &mut type_size, + &mut info, offset, )?; } ExternalKind::Tag => insert_export( + types, export.name, EntityType::Tag(self.core_function_at(export.index, offset)?), &mut inst_exports, - &mut type_size, + &mut info, offset, )?, } } - let ty = Type::Instance(InstanceType { - type_size, + let ty = Type::Instance(Box::new(InstanceType { + info, kind: InstanceTypeKind::Exports(inst_exports), - }); - - let id = TypeId { - type_size: ty.type_size(), - index: types.len(), - }; + })); - types.push(ty); - - Ok(id) + Ok(types.push_ty(ty)) } fn alias_core_instance_export( @@ -1412,86 +2268,49 @@ impl ComponentState { instance_index: u32, kind: ComponentExternalKind, name: &str, - types: &TypeList, + features: &WasmFeatures, + types: &mut TypeAlloc, offset: usize, ) -> Result<()> { - macro_rules! push_component_export { - ($expected:path, $collection:ident, $ty:literal) => {{ - match self.instance_export(instance_index, name, types, offset)? { - $expected(ty) => { - self.$collection.push(*ty); - Ok(()) - } - _ => { - bail!( - offset, - "export `{name}` for instance {instance_index} is not a {}", - $ty - ) - } - } - }}; + if let ComponentExternalKind::Value = kind { + self.check_value_support(features, offset)?; } + let mut ty = match types[self.instance_at(instance_index, offset)?] + .unwrap_component_instance() + .exports + .get(name) + { + Some(ty) => *ty, + None => bail!( + offset, + "instance {instance_index} has no export named `{name}`" + ), + }; - match kind { - ComponentExternalKind::Module => { - check_max( - self.core_modules.len(), - 1, - MAX_WASM_MODULES, - "modules", - offset, - )?; - push_component_export!(ComponentEntityType::Module, core_modules, "module") - } - ComponentExternalKind::Component => { - check_max( - self.components.len(), - 1, - MAX_WASM_COMPONENTS, - "components", - offset, - )?; - push_component_export!(ComponentEntityType::Component, components, "component") - } - ComponentExternalKind::Instance => { - check_max( - self.instance_count(), - 1, - MAX_WASM_INSTANCES, - "instances", - offset, - )?; - push_component_export!(ComponentEntityType::Instance, instances, "instance") - } - ComponentExternalKind::Func => { - check_max( - self.function_count(), - 1, - MAX_WASM_FUNCTIONS, - "functions", - offset, - )?; - push_component_export!(ComponentEntityType::Func, funcs, "function") - } - ComponentExternalKind::Value => { - check_max(self.values.len(), 1, MAX_WASM_VALUES, "values", offset)?; - match self.instance_export(instance_index, name, types, offset)? { - ComponentEntityType::Value(ty) => { - self.values.push((*ty, false)); - Ok(()) - } - _ => bail!( - offset, - "export `{name}` for instance {instance_index} is not a value", - ), - } - } - ComponentExternalKind::Type => { - check_max(self.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; - push_component_export!(ComponentEntityType::Type, types, "type") - } + let ok = match (&ty, kind) { + (ComponentEntityType::Module(_), ComponentExternalKind::Module) => true, + (ComponentEntityType::Module(_), _) => false, + (ComponentEntityType::Component(_), ComponentExternalKind::Component) => true, + (ComponentEntityType::Component(_), _) => false, + (ComponentEntityType::Func(_), ComponentExternalKind::Func) => true, + (ComponentEntityType::Func(_), _) => false, + (ComponentEntityType::Instance(_), ComponentExternalKind::Instance) => true, + (ComponentEntityType::Instance(_), _) => false, + (ComponentEntityType::Value(_), ComponentExternalKind::Value) => true, + (ComponentEntityType::Value(_), _) => false, + (ComponentEntityType::Type { .. }, ComponentExternalKind::Type) => true, + (ComponentEntityType::Type { .. }, _) => false, + }; + if !ok { + bail!( + offset, + "export `{name}` for instance {instance_index} is not a {}", + kind.desc(), + ); } + + self.add_entity(&mut ty, None, features, types, offset)?; + Ok(()) } fn alias_module(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> { @@ -1546,17 +2365,62 @@ impl ComponentState { check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; current.core_types.push(ty); + Ok(()) } - fn alias_type(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> { + fn alias_type( + components: &mut [Self], + count: u32, + index: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; let ty = component.type_at(index, false, offset)?; + // If `count` "crossed a component boundary", meaning that it went from + // one component to another, then this must additionally verify that + // `ty` has no free variables with respect to resources. This is + // intended to preserve the property for components where each component + // is an isolated unit that can theoretically be extracted from other + // components. If resources from other components were allowed to leak + // in then it would prevent that. + // + // This check is done by calculating the `pos` within `components` that + // our target `component` above was selected at. Once this is acquired + // the component to the "right" is checked, and if that's a component + // then it's considered as crossing a component boundary meaning the + // free variables check runs. + // + // The reason this works is that in the list of `ComponentState` types + // it's guaranteed that any `is_type` components are contiguous at the + // end of the array. This means that if state one level deeper than the + // target of this alias is a `!is_type` component, then the target must + // be a component as well. If the one-level deeper state `is_type` then + // the target is either a type or a component, both of which are valid + // (as aliases can reach the enclosing component and have as many free + // variables as they want). + let pos_after_component = components.len() - (count as usize); + if let Some(component) = components.get(pos_after_component) { + if component.kind == ComponentKind::Component { + let mut free = IndexSet::new(); + types.free_variables_type_id(ty, &mut free); + if !free.is_empty() { + bail!( + offset, + "cannot alias outer type which transitively refers \ + to resources not defined in the current component" + ); + } + } + } + let current = components.last_mut().unwrap(); check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; current.types.push(ty); + Ok(()) } @@ -1595,9 +2459,6 @@ impl ComponentState { crate::ComponentDefinedType::Enum(cases) => { self.create_enum_type(cases.as_ref(), offset) } - crate::ComponentDefinedType::Union(tys) => { - self.create_union_type(tys.as_ref(), types, offset) - } crate::ComponentDefinedType::Option(ty) => Ok(ComponentDefinedType::Option( self.create_component_val_type(ty, types, offset)?, )), @@ -1609,6 +2470,12 @@ impl ComponentState { .map(|ty| self.create_component_val_type(ty, types, offset)) .transpose()?, }), + crate::ComponentDefinedType::Own(idx) => Ok(ComponentDefinedType::Own( + self.resource_at(idx, types, offset)?, + )), + crate::ComponentDefinedType::Borrow(idx) => Ok(ComponentDefinedType::Borrow( + self.resource_at(idx, types, offset)?, + )), } } @@ -1618,21 +2485,32 @@ impl ComponentState { types: &TypeList, offset: usize, ) -> Result { - let mut type_size = 1; + let mut info = TypeInfo::new(); let mut field_map = IndexMap::with_capacity(fields.len()); + if fields.is_empty() { + bail!(offset, "record type must have at least one field"); + } + for (name, ty) in fields { - Self::check_name(name, "record field", offset)?; + let name = to_kebab_str(name, "record field", offset)?; let ty = self.create_component_val_type(*ty, types, offset)?; - type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; - if field_map.insert(name.to_string(), ty).is_some() { - bail!(offset, "duplicate field named `{name}` in record type"); + match field_map.entry(name.to_owned()) { + Entry::Occupied(e) => bail!( + offset, + "record field name `{name}` conflicts with previous field name `{prev}`", + prev = e.key() + ), + Entry::Vacant(e) => { + info.combine(ty.info(types), offset)?; + e.insert(ty); + } } } Ok(ComponentDefinedType::Record(RecordType { - type_size, + info, fields: field_map, })) } @@ -1643,14 +2521,11 @@ impl ComponentState { types: &TypeList, offset: usize, ) -> Result { - let mut type_size = 1; - let mut case_map = IndexMap::with_capacity(cases.len()); + let mut info = TypeInfo::new(); + let mut case_map: IndexMap = IndexMap::with_capacity(cases.len()); if cases.is_empty() { - return Err(BinaryReaderError::new( - "variant type must have at least one case", - offset, - )); + bail!(offset, "variant type must have at least one case"); } if cases.len() > u32::MAX as usize { @@ -1661,7 +2536,6 @@ impl ComponentState { } for (i, case) in cases.iter().enumerate() { - Self::check_name(case.name, "variant case", offset)?; if let Some(refines) = case.refines { if refines >= i as u32 { return Err(BinaryReaderError::new( @@ -1670,34 +2544,40 @@ impl ComponentState { )); } } + + let name = to_kebab_str(case.name, "variant case", offset)?; + let ty = case .ty .map(|ty| self.create_component_val_type(ty, types, offset)) .transpose()?; - type_size = - combine_type_sizes(type_size, ty.map(|ty| ty.type_size()).unwrap_or(1), offset)?; + match case_map.entry(name.to_owned()) { + Entry::Occupied(e) => bail!( + offset, + "variant case name `{name}` conflicts with previous case name `{prev}`", + name = case.name, + prev = e.key() + ), + Entry::Vacant(e) => { + if let Some(ty) = ty { + info.combine(ty.info(types), offset)?; + } - if case_map - .insert( - case.name.to_string(), - VariantCase { + // Safety: the use of `KebabStr::new_unchecked` here is safe because the string + // was already verified to be kebab case. + e.insert(VariantCase { ty, - refines: case.refines.map(|i| cases[i as usize].name.to_string()), - }, - ) - .is_some() - { - bail!( - offset, - "duplicate case named `{}` in variant type", - case.name, - ); + refines: case + .refines + .map(|i| KebabStr::new_unchecked(cases[i as usize].name).to_owned()), + }); + } } } Ok(ComponentDefinedType::Variant(VariantType { - type_size, + info, cases: case_map, })) } @@ -1708,26 +2588,37 @@ impl ComponentState { types: &TypeList, offset: usize, ) -> Result { - let mut type_size = 1; + let mut info = TypeInfo::new(); + if tys.is_empty() { + bail!(offset, "tuple type must have at least one type"); + } let types = tys .iter() .map(|ty| { let ty = self.create_component_val_type(*ty, types, offset)?; - type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; + info.combine(ty.info(types), offset)?; Ok(ty) }) .collect::>()?; - Ok(ComponentDefinedType::Tuple(TupleType { type_size, types })) + Ok(ComponentDefinedType::Tuple(TupleType { info, types })) } fn create_flags_type(&self, names: &[&str], offset: usize) -> Result { let mut names_set = IndexSet::with_capacity(names.len()); + if names.is_empty() { + bail!(offset, "flags must have at least one entry"); + } + for name in names { - Self::check_name(name, "flag", offset)?; - if !names_set.insert(name.to_string()) { - bail!(offset, "duplicate flag named `{name}`"); + let name = to_kebab_str(name, "flag", offset)?; + if !names_set.insert(name.to_owned()) { + bail!( + offset, + "flag name `{name}` conflicts with previous flag name `{prev}`", + prev = names_set.get(name).unwrap() + ); } } @@ -1742,37 +2633,26 @@ impl ComponentState { )); } + if cases.is_empty() { + bail!(offset, "enum type must have at least one variant"); + } + let mut tags = IndexSet::with_capacity(cases.len()); for tag in cases { - Self::check_name(tag, "enum tag", offset)?; - if !tags.insert(tag.to_string()) { - bail!(offset, "duplicate enum tag named `{tag}`"); + let tag = to_kebab_str(tag, "enum tag", offset)?; + if !tags.insert(tag.to_owned()) { + bail!( + offset, + "enum tag name `{tag}` conflicts with previous tag name `{prev}`", + prev = tags.get(tag).unwrap() + ); } } Ok(ComponentDefinedType::Enum(tags)) } - fn create_union_type( - &self, - tys: &[crate::ComponentValType], - types: &TypeList, - offset: usize, - ) -> Result { - let mut type_size = 1; - let types = tys - .iter() - .map(|ty| { - let ty = self.create_component_val_type(*ty, types, offset)?; - type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; - Ok(ty) - }) - .collect::>()?; - - Ok(ComponentDefinedType::Union(UnionType { type_size, types })) - } - fn create_component_val_type( &self, ty: crate::ComponentValType, @@ -1801,9 +2681,10 @@ impl ComponentState { types: &'a TypeList, offset: usize, ) -> Result<&'a ComponentFuncType> { - types[self.type_at(idx, false, offset)?] - .as_component_func_type() - .ok_or_else(|| format_err!(offset, "type index {idx} is not a function type")) + match &types[self.type_at(idx, false, offset)?] { + Type::ComponentFunc(f) => Ok(f), + _ => bail!(offset, "type index {idx} is not a function type"), + } } fn function_at(&self, idx: u32, offset: usize) -> Result { @@ -1833,27 +2714,6 @@ impl ComponentState { }) } - fn instance_export<'a>( - &self, - instance_index: u32, - name: &str, - types: &'a TypeList, - offset: usize, - ) -> Result<&'a ComponentEntityType> { - match types[self.instance_at(instance_index, offset)?] - .as_component_instance_type() - .unwrap() - .internal_exports(types) - .get(name) - { - Some(export) => Ok(export), - None => bail!( - offset, - "instance {instance_index} has no export named `{name}`" - ), - } - } - fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> { match self.values.get_mut(idx as usize) { Some((ty, used)) if !*used => { @@ -1869,7 +2729,7 @@ impl ComponentState { let id = self.type_at(idx, false, offset)?; match &types[id] { Type::Defined(_) => Ok(id), - _ => bail!(offset, "type index {} is not a defined type", id.index), + _ => bail!(offset, "type index {} is not a defined type", idx), } } @@ -1908,8 +2768,7 @@ impl ComponentState { offset: usize, ) -> Result<&'a EntityType> { match types[self.core_instance_at(instance_index, offset)?] - .as_instance_type() - .unwrap() + .unwrap_instance() .internal_exports(types) .get(name) { @@ -1941,28 +2800,327 @@ impl ComponentState { None => bail!(offset, "unknown memory {idx}: memory index out of bounds"), } } + + /// Completes the translation of this component, performing final + /// validation of its structure. + /// + /// This method is required to be called for translating all components. + /// Internally this will convert local data structures into a + /// `ComponentType` which is suitable to use to describe the type of this + /// component. + pub fn finish(&mut self, types: &TypeAlloc, offset: usize) -> Result { + let mut ty = ComponentType { + // Inherit some fields based on translation of the component. + info: self.type_info, + imports: self.imports.clone(), + exports: self.exports.clone(), + + // This is filled in as a subset of `self.defined_resources` + // depending on what's actually used by the exports. See the + // bottom of this function. + defined_resources: Default::default(), + + // These are inherited directly from what was calculated for this + // component. + imported_resources: mem::take(&mut self.imported_resources) + .into_iter() + .collect(), + explicit_resources: mem::take(&mut self.explicit_resources), + }; + + // Collect all "free variables", or resources, from the imports of this + // component. None of the resources defined within this component can + // be used as part of the exports. This set is then used to reject any + // of `self.defined_resources` which show up. + let mut free = IndexSet::default(); + for ty in ty.imports.values() { + types.free_variables_component_entity(ty, &mut free); + } + for (resource, _path) in self.defined_resources.iter() { + // FIXME: this error message is quite opaque and doesn't indicate + // more contextual information such as: + // + // * what was the exported resource found in the imports + // * which import was the resource found within + // + // These are possible to calculate here if necessary, however. + if free.contains(resource) { + bail!(offset, "local resource type found in imports"); + } + } + + // The next step in validation a component, with respect to resources, + // is to minimize the set of defined resources to only those that + // are actually used by the exports. This weeds out resources that are + // defined, used within a component, and never exported, for example. + // + // The free variables of all exports are inserted into the `free` set + // (which is reused from the imports after clearing it). The defined + // resources calculated for this component are then inserted into this + // type's list of defined resources if it's contained somewhere in + // the free variables. + // + // Note that at the same time all defined resources must be exported, + // somehow, transitively from this component. The `explicit_resources` + // map is consulted for this purpose which lists all explicitly + // exported resources in the component, regardless from whence they + // came. If not present in this map then it's not exported and an error + // is returned. + // + // NB: the "types are exported" check is probably sufficient nowadays + // that the check of the `explicit_resources` map is probably not + // necessary, but it's left here for completeness and out of an + // abundance of caution. + free.clear(); + for ty in ty.exports.values() { + types.free_variables_component_entity(ty, &mut free); + } + for (id, _rep) in mem::take(&mut self.defined_resources) { + if !free.contains(&id) { + continue; + } + + let path = match ty.explicit_resources.get(&id).cloned() { + Some(path) => path, + // FIXME: this error message is quite opaque and doesn't + // indicate more contextual information such as: + // + // * which resource wasn't found in an export + // * which export has a reference to the resource + // + // These are possible to calculate here if necessary, however. + None => bail!( + offset, + "local resource type found in export but not exported itself" + ), + }; + + ty.defined_resources.push((id, path)); + } + + Ok(ty) + } + + fn check_value_support(&self, features: &WasmFeatures, offset: usize) -> Result<()> { + if !features.component_model_values { + bail!( + offset, + "support for component model `value`s is not enabled" + ); + } + Ok(()) + } } -impl Default for ComponentState { - fn default() -> Self { - Self { - core_types: Default::default(), - core_modules: Default::default(), - core_instances: Default::default(), - core_funcs: Default::default(), - core_memories: Default::default(), - core_tables: Default::default(), - core_globals: Default::default(), - core_tags: Default::default(), - types: Default::default(), - funcs: Default::default(), - values: Default::default(), - instances: Default::default(), - components: Default::default(), - imports: Default::default(), - exports: Default::default(), - has_start: Default::default(), - type_size: 1, +impl KebabNameContext { + /// Registers that the resource `id` is named `name` within this context. + fn register(&mut self, name: &str, id: TypeId) { + let idx = self.all_resource_names.len(); + let prev = self.resource_name_map.insert(id, idx); + assert!(prev.is_none()); + self.all_resource_names.insert(name.to_string()); + } + + fn validate_extern( + &self, + name: ComponentExternName<'_>, + desc: &str, + ty: &ComponentEntityType, + types: &TypeAlloc, + offset: usize, + kebab_names: &mut IndexSet, + items: &mut IndexMap, + info: &mut TypeInfo, + ) -> Result<()> { + // First validate that `name` is even a valid kebab name, meaning it's + // in kebab-case, is an ID, etc. + let kebab = KebabName::new(name, offset).with_context(|| { + format!("{desc} name `{}` is not a valid extern name", name.as_str()) + })?; + + // Validate that the kebab name, if it has structure such as + // `[method]a.b`, is indeed valid with respect to known resources. + self.validate(&kebab, ty, types, offset) + .with_context(|| format!("{desc} name `{kebab}` is not valid"))?; + + // Top-level kebab-names must all be unique, even between both imports + // and exports ot a component. For those names consult the `kebab_names` + // set. + if let ComponentExternName::Kebab(_) = name { + if let Some(prev) = kebab_names.replace(kebab.clone()) { + bail!( + offset, + "{desc} name `{kebab}` conflicts with previous name `{prev}`", + ); + } + } + + // Otherwise all strings must be unique, regardless of their name, so + // consult the `items` set to ensure that we're not for example + // importing the same interface ID twice. + match items.entry(kebab.into()) { + Entry::Occupied(e) => { + bail!( + offset, + "{desc} name `{name}` conflicts with previous name `{prev}`", + name = name.as_str(), + prev = e.key(), + ); + } + Entry::Vacant(e) => { + e.insert(*ty); + info.combine(ty.info(types), offset)?; + } + } + Ok(()) + } + + /// Validates that the `name` provided is allowed to have the type `ty`. + fn validate( + &self, + name: &KebabName, + ty: &ComponentEntityType, + types: &TypeAlloc, + offset: usize, + ) -> Result<()> { + let func = || { + let id = match ty { + ComponentEntityType::Func(id) => *id, + _ => bail!(offset, "item is not a func"), + }; + Ok(types[id].unwrap_component_func()) + }; + match name.kind() { + // Normal kebab name or id? No validation necessary. + KebabNameKind::Normal(_) | KebabNameKind::Id { .. } => {} + + // Constructors must return `(own $resource)` and the `$resource` + // must be named within this context to match `rname` + KebabNameKind::Constructor(rname) => { + let ty = func()?; + if ty.results.len() != 1 { + bail!(offset, "function should return one value"); + } + let ty = ty.results[0].1; + let resource = match ty { + ComponentValType::Primitive(_) => None, + ComponentValType::Type(ty) => match &types[ty] { + Type::Defined(ComponentDefinedType::Own(id)) => Some(id), + _ => None, + }, + }; + let resource = match resource { + Some(id) => id, + None => bail!(offset, "function should return `(own $T)`"), + }; + self.validate_resource_name(*resource, rname, offset)?; + } + + // Methods must take `(param "self" (borrow $resource))` as the + // first argument where `$resources` matches the name `resource` as + // named in this context. + KebabNameKind::Method { resource, .. } => { + let ty = func()?; + if ty.params.len() == 0 { + bail!(offset, "function should have at least one argument"); + } + let (pname, pty) = &ty.params[0]; + if pname.as_str() != "self" { + bail!( + offset, + "function should have a first argument called `self`", + ); + } + let id = match pty { + ComponentValType::Primitive(_) => None, + ComponentValType::Type(ty) => match &types[*ty] { + Type::Defined(ComponentDefinedType::Borrow(id)) => Some(id), + _ => None, + }, + }; + let id = match id { + Some(id) => id, + None => bail!( + offset, + "function should take a first argument of `(borrow $T)`" + ), + }; + self.validate_resource_name(*id, resource, offset)?; + } + + // Static methods don't have much validation beyond that they must + // be a function and the resource name referred to must already be + // in this context. + KebabNameKind::Static { resource, .. } => { + func()?; + if !self.all_resource_names.contains(resource.as_str()) { + bail!(offset, "static resource name is not known in this context"); + } + } + } + + Ok(()) + } + + fn validate_resource_name(&self, id: TypeId, name: &KebabStr, offset: usize) -> Result<()> { + let expected_name_idx = match self.resource_name_map.get(&id) { + Some(idx) => *idx, + None => { + bail!( + offset, + "resource used in function does not have a name in this context" + ) + } + }; + let expected_name = &self.all_resource_names[expected_name_idx]; + if name.as_str() != expected_name { + bail!( + offset, + "function does not match expected \ + resource name `{expected_name}`" + ); + } + Ok(()) + } +} + +use self::append_only::*; + +mod append_only { + use indexmap::IndexMap; + use std::hash::Hash; + use std::ops::Deref; + + pub struct IndexMapAppendOnly(IndexMap); + + impl IndexMapAppendOnly + where + K: Hash + Eq + PartialEq, + { + pub fn insert(&mut self, key: K, value: V) { + let prev = self.0.insert(key, value); + assert!(prev.is_none()); + } + } + + impl Deref for IndexMapAppendOnly { + type Target = IndexMap; + fn deref(&self) -> &IndexMap { + &self.0 + } + } + + impl Default for IndexMapAppendOnly { + fn default() -> Self { + Self(Default::default()) + } + } + + impl IntoIterator for IndexMapAppendOnly { + type IntoIter = as IntoIterator>::IntoIter; + type Item = as IntoIterator>::Item; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() } } } diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index 933ea49555..c63a81c52e 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -1,26 +1,25 @@ //! State relating to validating a WebAssembly module. //! -use super::{ - check_max, combine_type_sizes, - operators::{OperatorValidator, OperatorValidatorAllocations}, - types::{EntityType, Type, TypeId, TypeList}, -}; +use std::mem; +use std::{collections::HashSet, sync::Arc}; + +use indexmap::IndexMap; + +use crate::limits::*; +use crate::readers::Matches; use crate::validator::core::arc::MaybeOwned; use crate::{ - limits::*, BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementItem, ElementKind, - ExternalKind, FuncType, Global, GlobalType, MemoryType, Result, TableType, TagType, TypeRef, - ValType, VisitOperator, WasmFeatures, WasmModuleResources, + BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementKind, ExternalKind, FuncType, + Global, GlobalType, HeapType, MemoryType, RecGroup, RefType, Result, StorageType, + StructuralType, SubType, Table, TableInit, TableType, TagType, TypeRef, ValType, VisitOperator, + WasmFeatures, WasmModuleResources, }; -use indexmap::IndexMap; -use std::mem; -use std::{collections::HashSet, sync::Arc}; -fn check_value_type(ty: ValType, features: &WasmFeatures, offset: usize) -> Result<()> { - match features.check_value_type(ty) { - Ok(()) => Ok(()), - Err(e) => Err(BinaryReaderError::new(e, offset)), - } -} +use super::{ + check_max, combine_type_sizes, + operators::{ty_to_str, OperatorValidator, OperatorValidatorAllocations}, + types::{EntityType, Type, TypeAlloc, TypeId, TypeList}, +}; // Section order for WebAssembly modules. // @@ -145,6 +144,36 @@ impl ModuleState { Ok(()) } + pub fn add_table( + &mut self, + table: Table<'_>, + features: &WasmFeatures, + types: &TypeList, + offset: usize, + ) -> Result<()> { + self.module.check_table_type(&table.ty, features, offset)?; + + match &table.init { + TableInit::RefNull => { + if !table.ty.element_type.is_nullable() { + bail!(offset, "type mismatch: non-defaultable element type"); + } + } + TableInit::Expr(expr) => { + if !features.function_references { + bail!( + offset, + "tables with expression initializers require \ + the function-references proposal" + ); + } + self.check_const_expr(expr, table.ty.element_type.into(), features, types)?; + } + } + self.module.assert_mut().tables.push(table.ty); + Ok(()) + } + pub fn add_data_segment( &mut self, data: Data, @@ -173,21 +202,32 @@ impl ModuleState { ) -> Result<()> { // the `funcref` value type is allowed all the way back to the MVP, so // don't check it here - if e.ty != ValType::FuncRef { - check_value_type(e.ty, features, offset)?; - } - if !e.ty.is_reference_type() { - return Err(BinaryReaderError::new("malformed reference type", offset)); - } + let element_ty = match &e.items { + crate::ElementItems::Functions(_) => RefType::FUNC, + crate::ElementItems::Expressions(ty, _) => { + self.module + .check_value_type(ValType::Ref(*ty), features, offset)?; + *ty + } + }; + match e.kind { ElementKind::Active { table_index, offset_expr, } => { - let table = self.module.table_at(table_index, offset)?; - if e.ty != table.element_type { + let table = self.module.table_at(table_index.unwrap_or(0), offset)?; + if !self.module.matches( + ValType::Ref(element_ty), + ValType::Ref(table.element_type), + types, + ) { return Err(BinaryReaderError::new( - "invalid element type for table type", + format!( + "type mismatch: invalid element type `{}` for table type `{}`", + ty_to_str(element_ty.into()), + ty_to_str(table.element_type.into()), + ), offset, )); } @@ -203,33 +243,35 @@ impl ModuleState { } } } - let mut items = e.items.get_items_reader()?; - if items.get_count() > MAX_WASM_TABLE_ENTRIES as u32 { - return Err(BinaryReaderError::new( - "number of elements is out of bounds", - offset, - )); - } - for _ in 0..items.get_count() { - let offset = items.original_position(); - match items.read()? { - ElementItem::Expr(expr) => { - self.check_const_expr(&expr, e.ty, features, types)?; - } - ElementItem::Func(f) => { - if e.ty != ValType::FuncRef { - return Err(BinaryReaderError::new( - "type mismatch: segment does not have funcref type", - offset, - )); - } + + let validate_count = |count: u32| -> Result<(), BinaryReaderError> { + if count > MAX_WASM_TABLE_ENTRIES as u32 { + Err(BinaryReaderError::new( + "number of elements is out of bounds", + offset, + )) + } else { + Ok(()) + } + }; + match e.items { + crate::ElementItems::Functions(reader) => { + let count = reader.count(); + validate_count(count)?; + for f in reader.into_iter_with_offsets() { + let (offset, f) = f?; self.module.get_func_type(f, types, offset)?; self.module.assert_mut().function_references.insert(f); } } + crate::ElementItems::Expressions(ty, reader) => { + validate_count(reader.count())?; + for expr in reader { + self.check_const_expr(&expr?, ValType::Ref(ty), features, types)?; + } + } } - - self.module.assert_mut().element_types.push(e.ty); + self.module.assert_mut().element_types.push(element_ty); Ok(()) } @@ -241,6 +283,7 @@ impl ModuleState { types: &TypeList, ) -> Result<()> { let mut validator = VisitConstOperator { + offset: 0, order: self.order, uninserted_funcref: false, ops: OperatorValidator::new_const_expr( @@ -256,7 +299,8 @@ impl ModuleState { let mut ops = expr.get_operators_reader(); while !ops.eof() { - ops.visit_with_offset(&mut validator)??; + validator.offset = ops.original_position(); + ops.visit_operator(&mut validator)??; } validator.ops.finish(ops.original_position())?; @@ -268,6 +312,7 @@ impl ModuleState { return Ok(()); struct VisitConstOperator<'a> { + offset: usize, uninserted_funcref: bool, ops: OperatorValidator, resources: OperatorValidatorResources<'a>, @@ -276,33 +321,33 @@ impl ModuleState { impl VisitConstOperator<'_> { fn validator(&mut self) -> impl VisitOperator<'_, Output = Result<()>> { - self.ops.with_resources(&self.resources) + self.ops.with_resources(&self.resources, self.offset) } - fn validate_extended_const(&mut self, offset: usize) -> Result<()> { + fn validate_extended_const(&mut self) -> Result<()> { if self.ops.features.extended_const { Ok(()) } else { Err(BinaryReaderError::new( "constant expression required: non-constant operator", - offset, + self.offset, )) } } - fn validate_global(&mut self, offset: usize, index: u32) -> Result<()> { + fn validate_global(&mut self, index: u32) -> Result<()> { let module = &self.resources.module; - let global = module.global_at(index, offset)?; + let global = module.global_at(index, self.offset)?; if index >= module.num_imported_globals { return Err(BinaryReaderError::new( "constant expression required: global.get of locally defined global", - offset, + self.offset, )); } if global.mutable { return Err(BinaryReaderError::new( "constant expression required: global.get of mutable global", - offset, + self.offset, )); } Ok(()) @@ -342,79 +387,79 @@ impl ModuleState { ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { $( #[allow(unused_variables)] - fn $visit(&mut self, pos: usize $($(,$arg: $argty)*)?) -> Self::Output { - define_visit_operator!(@visit self $visit pos $($($arg)*)?) + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { + define_visit_operator!(@visit self $visit $($($arg)*)?) } )* }; // These are always valid in const expressions - (@visit $self:ident visit_i32_const $pos:ident $val:ident) => {{ - $self.validator().visit_i32_const($pos, $val) + (@visit $self:ident visit_i32_const $val:ident) => {{ + $self.validator().visit_i32_const($val) }}; - (@visit $self:ident visit_i64_const $pos:ident $val:ident) => {{ - $self.validator().visit_i64_const($pos, $val) + (@visit $self:ident visit_i64_const $val:ident) => {{ + $self.validator().visit_i64_const($val) }}; - (@visit $self:ident visit_f32_const $pos:ident $val:ident) => {{ - $self.validator().visit_f32_const($pos, $val) + (@visit $self:ident visit_f32_const $val:ident) => {{ + $self.validator().visit_f32_const($val) }}; - (@visit $self:ident visit_f64_const $pos:ident $val:ident) => {{ - $self.validator().visit_f64_const($pos, $val) + (@visit $self:ident visit_f64_const $val:ident) => {{ + $self.validator().visit_f64_const($val) }}; - (@visit $self:ident visit_v128_const $pos:ident $val:ident) => {{ - $self.validator().visit_v128_const($pos, $val) + (@visit $self:ident visit_v128_const $val:ident) => {{ + $self.validator().visit_v128_const($val) }}; - (@visit $self:ident visit_ref_null $pos:ident $val:ident) => {{ - $self.validator().visit_ref_null($pos, $val) + (@visit $self:ident visit_ref_null $val:ident) => {{ + $self.validator().visit_ref_null($val) }}; - (@visit $self:ident visit_end $pos:ident) => {{ - $self.validator().visit_end($pos) + (@visit $self:ident visit_end) => {{ + $self.validator().visit_end() }}; // These are valid const expressions when the extended-const proposal is enabled. - (@visit $self:ident visit_i32_add $pos:ident) => {{ - $self.validate_extended_const($pos)?; - $self.validator().visit_i32_add($pos) + (@visit $self:ident visit_i32_add) => {{ + $self.validate_extended_const()?; + $self.validator().visit_i32_add() }}; - (@visit $self:ident visit_i32_sub $pos:ident) => {{ - $self.validate_extended_const($pos)?; - $self.validator().visit_i32_sub($pos) + (@visit $self:ident visit_i32_sub) => {{ + $self.validate_extended_const()?; + $self.validator().visit_i32_sub() }}; - (@visit $self:ident visit_i32_mul $pos:ident) => {{ - $self.validate_extended_const($pos)?; - $self.validator().visit_i32_mul($pos) + (@visit $self:ident visit_i32_mul) => {{ + $self.validate_extended_const()?; + $self.validator().visit_i32_mul() }}; - (@visit $self:ident visit_i64_add $pos:ident) => {{ - $self.validate_extended_const($pos)?; - $self.validator().visit_i64_add($pos) + (@visit $self:ident visit_i64_add) => {{ + $self.validate_extended_const()?; + $self.validator().visit_i64_add() }}; - (@visit $self:ident visit_i64_sub $pos:ident) => {{ - $self.validate_extended_const($pos)?; - $self.validator().visit_i64_sub($pos) + (@visit $self:ident visit_i64_sub) => {{ + $self.validate_extended_const()?; + $self.validator().visit_i64_sub() }}; - (@visit $self:ident visit_i64_mul $pos:ident) => {{ - $self.validate_extended_const($pos)?; - $self.validator().visit_i64_mul($pos) + (@visit $self:ident visit_i64_mul) => {{ + $self.validate_extended_const()?; + $self.validator().visit_i64_mul() }}; // `global.get` is a valid const expression for imported, immutable // globals. - (@visit $self:ident visit_global_get $pos:ident $idx:ident) => {{ - $self.validate_global($pos, $idx)?; - $self.validator().visit_global_get($pos, $idx) + (@visit $self:ident visit_global_get $idx:ident) => {{ + $self.validate_global($idx)?; + $self.validator().visit_global_get($idx) }}; // `ref.func`, if it's in a `global` initializer, will insert into // the set of referenced functions so it's processed here. - (@visit $self:ident visit_ref_func $pos:ident $idx:ident) => {{ + (@visit $self:ident visit_ref_func $idx:ident) => {{ $self.insert_ref_func($idx); - $self.validator().visit_ref_func($pos, $idx) + $self.validator().visit_ref_func($idx) }}; - (@visit $self:ident $op:ident $pos:ident $($args:tt)*) => {{ + (@visit $self:ident $op:ident $($args:tt)*) => {{ Err(BinaryReaderError::new( "constant expression required: non-constant operator", - $pos, + $self.offset, )) }} } @@ -437,7 +482,7 @@ pub(crate) struct Module { pub tables: Vec, pub memories: Vec, pub globals: Vec, - pub element_types: Vec, + pub element_types: Vec, pub data_count: Option, // Stores indexes into `types`. pub functions: Vec, @@ -445,24 +490,117 @@ pub(crate) struct Module { pub function_references: HashSet, pub imports: IndexMap<(String, String), Vec>, pub exports: IndexMap, - pub type_size: usize, + pub type_size: u32, num_imported_globals: u32, num_imported_functions: u32, } impl Module { - pub fn add_type( + pub fn add_types( &mut self, - ty: crate::Type, + rec_group: &RecGroup, features: &WasmFeatures, - types: &mut TypeList, + types: &mut TypeAlloc, offset: usize, check_limit: bool, ) -> Result<()> { - let ty = match ty { - crate::Type::Func(t) => { + if matches!(&rec_group, RecGroup::Many(_)) && !features.gc { + bail!( + offset, + "rec group usage requires `gc` proposal to be enabled" + ); + } + + if check_limit { + check_max( + self.types.len(), + rec_group.types().len() as u32, + MAX_WASM_TYPES, + "types", + offset, + )?; + } + + let idx_types: Vec<_> = rec_group + .types() + .iter() + .map(|ty| { + let id = types.push_ty(Type::Sub(ty.clone())); + if features.gc { + // make types in a rec group resolvable by index before validation: + // this is needed to support recursive types in the GC proposal + self.types.push(id); + } + (id, ty) + }) + .collect(); + + for (id, ty) in idx_types { + self.check_subtype(id.index() as u32, ty.clone(), features, types, offset)?; + if !features.gc { + self.types.push(id); + } + } + Ok(()) + } + + fn check_subtype( + &mut self, + type_index: u32, + ty: SubType, + features: &WasmFeatures, + types: &mut TypeAlloc, + offset: usize, + ) -> Result { + if !features.gc && (!ty.is_final || ty.supertype_idx.is_some()) { + bail!(offset, "gc proposal must be enabled to use subtypes"); + } + + self.check_structural_type(&ty.structural_type, features, offset)?; + + if let Some(supertype_index) = ty.supertype_idx { + // Check the supertype exists, is not final, and the subtype matches it. + if supertype_index >= type_index { + bail!( + offset, + "unknown type {type_index}: type index out of bounds" + ); + } + match self.type_at(types, supertype_index, offset)? { + Type::Sub(st) => { + if !&ty.matches(st, &|idx| self.subtype_at(types, idx, offset).unwrap()) { + bail!(offset, "subtype must match supertype"); + } + } + _ => { + bail!(offset, "supertype must be a non-final subtype itself"); + } + }; + } + + Ok(Type::Sub(ty)) + } + + fn subtype_at<'a>(&self, types: &'a TypeList, idx: u32, offset: usize) -> Result<&'a SubType> { + match self.type_at(types, idx, offset)? { + Type::Sub(ty) => Ok(ty), + _ => bail!( + offset, + "subtype with index {idx} not found, offset: {offset}" + ), + } + } + + fn check_structural_type( + &mut self, + ty: &StructuralType, + features: &WasmFeatures, + offset: usize, + ) -> Result<()> { + match ty { + StructuralType::Func(t) => { for ty in t.params().iter().chain(t.results()) { - check_value_type(*ty, features, offset)?; + self.check_value_type(*ty, features, offset)?; } if t.results().len() > 1 && !features.multi_value { return Err(BinaryReaderError::new( @@ -470,19 +608,33 @@ impl Module { offset, )); } - Type::Func(t) } - }; - - if check_limit { - check_max(self.types.len(), 1, MAX_WASM_TYPES, "types", offset)?; + StructuralType::Array(t) => { + if !features.gc { + return Err(BinaryReaderError::new( + "array indexed types not supported without the gc feature", + offset, + )); + } + match t.0.element_type { + StorageType::I8 | StorageType::I16 => {} + StorageType::Val(value_type) => { + self.check_value_type(value_type, features, offset)?; + } + }; + } + StructuralType::Struct(t) => { + if !features.gc { + return Err(BinaryReaderError::new( + "struct indexed types not supported without the gc feature", + offset, + )); + } + for ty in t.fields.iter() { + self.check_storage_type(ty.element_type, features, offset)?; + } + } } - - self.types.push(TypeId { - type_size: ty.type_size(), - index: types.len(), - }); - types.push(ty); Ok(()) } @@ -528,7 +680,7 @@ impl Module { check_max(len, 0, max, desc, offset)?; - self.type_size = combine_type_sizes(self.type_size, entity.type_size(), offset)?; + self.type_size = combine_type_sizes(self.type_size, entity.info(types).size(), offset)?; self.imports .entry((import.module.to_string(), import.name.to_string())) @@ -545,6 +697,7 @@ impl Module { features: &WasmFeatures, offset: usize, check_limit: bool, + types: &TypeList, ) -> Result<()> { if !features.mutable_global { if let EntityType::Global(global_type) = ty { @@ -561,7 +714,7 @@ impl Module { check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?; } - self.type_size = combine_type_sizes(self.type_size, ty.type_size(), offset)?; + self.type_size = combine_type_sizes(self.type_size, ty.info(types).size(), offset)?; match self.exports.insert(name.to_string(), ty) { Some(_) => Err(format_err!( @@ -578,17 +731,6 @@ impl Module { Ok(()) } - pub fn add_table( - &mut self, - ty: TableType, - features: &WasmFeatures, - offset: usize, - ) -> Result<()> { - self.check_table_type(&ty, features, offset)?; - self.tables.push(ty); - Ok(()) - } - pub fn add_memory( &mut self, ty: MemoryType, @@ -612,22 +754,30 @@ impl Module { Ok(()) } - pub fn type_at(&self, idx: u32, offset: usize) -> Result { + pub fn type_id_at(&self, idx: u32, offset: usize) -> Result { self.types .get(idx as usize) .copied() .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds")) } + fn type_at<'a>(&self, types: &'a TypeList, idx: u32, offset: usize) -> Result<&'a Type> { + self.type_id_at(idx, offset).map(|type_id| &types[type_id]) + } + fn func_type_at<'a>( &self, type_index: u32, types: &'a TypeList, offset: usize, ) -> Result<&'a FuncType> { - types[self.type_at(type_index, offset)?] - .as_func_type() - .ok_or_else(|| format_err!(offset, "type index {type_index} is not a function type")) + match &types[self.type_id_at(type_index, offset)?] { + Type::Sub(SubType { + structural_type: StructuralType::Func(f), + .. + }) => Ok(f), + _ => bail!(offset, "type index {type_index} is not a function type"), + } } pub fn check_type_ref( @@ -669,16 +819,10 @@ impl Module { ) -> Result<()> { // the `funcref` value type is allowed all the way back to the MVP, so // don't check it here - if ty.element_type != ValType::FuncRef { - check_value_type(ty.element_type, features, offset)?; + if ty.element_type != RefType::FUNCREF { + self.check_value_type(ValType::Ref(ty.element_type), features, offset)? } - if !ty.element_type.is_reference_type() { - return Err(BinaryReaderError::new( - "element is not reference type", - offset, - )); - } self.check_limits(ty.initial, ty.maximum, offset)?; if ty.initial > MAX_WASM_TABLE_ENTRIES as u32 { return Err(BinaryReaderError::new( @@ -758,6 +902,65 @@ impl Module { .collect::>() } + fn check_storage_type( + &self, + ty: StorageType, + features: &WasmFeatures, + offset: usize, + ) -> Result<()> { + match ty { + StorageType::I8 | StorageType::I16 => {} + StorageType::Val(value_type) => { + self.check_value_type(value_type, features, offset)?; + } + } + Ok(()) + } + + fn check_value_type(&self, ty: ValType, features: &WasmFeatures, offset: usize) -> Result<()> { + match features.check_value_type(ty) { + Ok(()) => Ok(()), + Err(e) => Err(BinaryReaderError::new(e, offset)), + }?; + // The above only checks the value type for features. + // We must check it if it's a reference. + match ty { + ValType::Ref(rt) => { + self.check_ref_type(rt, offset)?; + } + _ => (), + } + Ok(()) + } + + fn check_ref_type(&self, ty: RefType, offset: usize) -> Result<()> { + // Check that the heap type is valid + match ty.heap_type() { + HeapType::Func + | HeapType::Extern + | HeapType::Any + | HeapType::None + | HeapType::NoExtern + | HeapType::NoFunc + | HeapType::Eq + | HeapType::Struct + | HeapType::Array + | HeapType::I31 => (), + HeapType::Indexed(type_index) => { + // Just check that the index is valid + self.type_id_at(type_index, offset)?; + } + } + Ok(()) + } + + /// Check that a value of type ty1 is assignable to a variable / table element of type ty2. + /// E.g. a non-nullable reference can be assigned to a nullable reference, but not vice versa. + /// Or an indexed func ref is assignable to a generic func ref, but not vice versa. + pub(crate) fn matches(&self, ty1: ValType, ty2: ValType, types: &TypeList) -> bool { + ty1.matches(&ty2, &|idx| self.subtype_at(types, idx, 0).unwrap()) + } + fn check_tag_type( &self, ty: &TagType, @@ -787,7 +990,7 @@ impl Module { features: &WasmFeatures, offset: usize, ) -> Result<()> { - check_value_type(ty.content_type, features, offset) + self.check_value_type(ty.content_type, features, offset) } fn check_limits(&self, initial: T, maximum: Option, offset: usize) -> Result<()> @@ -947,11 +1150,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { } fn tag_at(&self, at: u32) -> Option<&Self::FuncType> { - Some( - self.types[*self.module.tags.get(at as usize)?] - .as_func_type() - .unwrap(), - ) + Some(self.types[*self.module.tags.get(at as usize)?].unwrap_func()) } fn global_at(&self, at: u32) -> Option { @@ -959,21 +1158,29 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { } fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> { - Some( - self.types[*self.module.types.get(at as usize)?] - .as_func_type() - .unwrap(), - ) + Some(self.types[*self.module.types.get(at as usize)?].unwrap_func()) + } + + fn type_index_of_function(&self, at: u32) -> Option { + self.module.functions.get(at as usize).cloned() } fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> { - self.func_type_at(*self.module.functions.get(at as usize)?) + self.func_type_at(self.type_index_of_function(at)?) } - fn element_type_at(&self, at: u32) -> Option { + fn check_value_type(&self, t: ValType, features: &WasmFeatures, offset: usize) -> Result<()> { + self.module.check_value_type(t, features, offset) + } + + fn element_type_at(&self, at: u32) -> Option { self.module.element_types.get(at as usize).cloned() } + fn matches(&self, t1: ValType, t2: ValType) -> bool { + self.module.matches(t1, t2, self.types) + } + fn element_count(&self) -> u32 { self.module.element_types.len() as u32 } @@ -1003,11 +1210,7 @@ impl WasmModuleResources for ValidatorResources { } fn tag_at(&self, at: u32) -> Option<&Self::FuncType> { - Some( - self.0.snapshot.as_ref().unwrap()[*self.0.tags.get(at as usize)?] - .as_func_type() - .unwrap(), - ) + Some(self.0.snapshot.as_ref().unwrap()[*self.0.tags.get(at as usize)?].unwrap_func()) } fn global_at(&self, at: u32) -> Option { @@ -1015,21 +1218,29 @@ impl WasmModuleResources for ValidatorResources { } fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> { - Some( - self.0.snapshot.as_ref().unwrap()[*self.0.types.get(at as usize)?] - .as_func_type() - .unwrap(), - ) + Some(self.0.snapshot.as_ref().unwrap()[*self.0.types.get(at as usize)?].unwrap_func()) + } + + fn type_index_of_function(&self, at: u32) -> Option { + self.0.functions.get(at as usize).cloned() } fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> { - self.func_type_at(*self.0.functions.get(at as usize)?) + self.func_type_at(self.type_index_of_function(at)?) + } + + fn check_value_type(&self, t: ValType, features: &WasmFeatures, offset: usize) -> Result<()> { + self.0.check_value_type(t, features, offset) } - fn element_type_at(&self, at: u32) -> Option { + fn element_type_at(&self, at: u32) -> Option { self.0.element_types.get(at as usize).cloned() } + fn matches(&self, t1: ValType, t2: ValType) -> bool { + self.0.matches(t1, t2, self.0.snapshot.as_ref().unwrap()) + } + fn element_count(&self) -> u32 { self.0.element_types.len() as u32 } diff --git a/crates/wasmparser/src/validator/func.rs b/crates/wasmparser/src/validator/func.rs index 6284758f17..4d405f9615 100644 --- a/crates/wasmparser/src/validator/func.rs +++ b/crates/wasmparser/src/validator/func.rs @@ -94,7 +94,7 @@ impl FuncValidator { self.read_locals(&mut reader)?; reader.allow_memarg64(self.validator.features.memory64); while !reader.eof() { - reader.visit_operator(self)??; + reader.visit_operator(&mut self.visitor(reader.original_position()))??; } self.finish(reader.original_position()) } @@ -107,8 +107,8 @@ impl FuncValidator { pub fn read_locals(&mut self, reader: &mut BinaryReader<'_>) -> Result<()> { for _ in 0..reader.read_var_u32()? { let offset = reader.original_position(); - let cnt = reader.read_var_u32()?; - let ty = reader.read_val_type()?; + let cnt = reader.read()?; + let ty = reader.read()?; self.define_locals(offset, cnt, ty)?; } Ok(()) @@ -119,7 +119,8 @@ impl FuncValidator { /// This should be used if the application is already reading local /// definitions and there's no need to re-parse the function again. pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> { - self.validator.define_locals(offset, count, ty) + self.validator + .define_locals(offset, count, ty, &self.resources) } /// Validates the next operator in a function. @@ -129,9 +130,33 @@ impl FuncValidator { /// the operator itself are passed to this function to provide more useful /// error messages. pub fn op(&mut self, offset: usize, operator: &Operator<'_>) -> Result<()> { - self.validator - .with_resources(&self.resources) - .visit_operator(offset, operator) + self.visitor(offset).visit_operator(operator) + } + + /// Get the operator visitor for the next operator in the function. + /// + /// The returned visitor is intended to visit just one instruction at the `offset`. + /// + /// # Example + /// + /// ``` + /// # use wasmparser::{WasmModuleResources, FuncValidator, FunctionBody, Result}; + /// pub fn validate(validator: &mut FuncValidator, body: &FunctionBody<'_>) -> Result<()> + /// where R: WasmModuleResources + /// { + /// let mut operator_reader = body.get_binary_reader(); + /// while !operator_reader.eof() { + /// let mut visitor = validator.visitor(operator_reader.original_position()); + /// operator_reader.visit_operator(&mut visitor)??; + /// } + /// validator.finish(operator_reader.original_position()) + /// } + /// ``` + pub fn visitor<'this, 'a: 'this>( + &'this mut self, + offset: usize, + ) -> impl VisitOperator<'a, Output = Result<()>> + 'this { + self.validator.with_resources(&self.resources, offset) } /// Function that must be called after the last opcode has been processed. @@ -245,10 +270,24 @@ mod tests { fn func_type_at(&self, _type_idx: u32) -> Option<&Self::FuncType> { Some(&EmptyFuncType) } + fn type_index_of_function(&self, _at: u32) -> Option { + todo!() + } fn type_of_function(&self, _func_idx: u32) -> Option<&Self::FuncType> { todo!() } - fn element_type_at(&self, _at: u32) -> Option { + fn check_value_type( + &self, + _t: ValType, + _features: &WasmFeatures, + _offset: usize, + ) -> Result<()> { + Ok(()) + } + fn element_type_at(&self, _at: u32) -> Option { + todo!() + } + fn matches(&self, _t1: ValType, _t2: ValType) -> bool { todo!() } fn element_count(&self) -> u32 { @@ -296,7 +335,7 @@ mod tests { .op( 1, &Operator::Block { - ty: crate::BlockType::Empty + blockty: crate::BlockType::Empty } ) .is_ok()); @@ -307,24 +346,3 @@ mod tests { assert_eq!(v.operand_stack_height(), 2); } } - -macro_rules! define_visit_operator { - ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { - $( - fn $visit(&mut self, offset: usize $($(,$arg: $argty)*)?) -> Result<()> { - self.validator.with_resources(&self.resources) - .$visit(offset $($(,$arg)*)?) - } - )* - } -} - -#[allow(unused_variables)] -impl<'a, T> VisitOperator<'a> for FuncValidator -where - T: WasmModuleResources, -{ - type Output = Result<()>; - - for_each_operator!(define_visit_operator); -} diff --git a/crates/wasmparser/src/validator/names.rs b/crates/wasmparser/src/validator/names.rs new file mode 100644 index 0000000000..0c3263b35a --- /dev/null +++ b/crates/wasmparser/src/validator/names.rs @@ -0,0 +1,606 @@ +//! Definitions of name-related helpers and newtypes, primarily for the +//! component model. + +use crate::{ComponentExternName, Result}; +use semver::Version; +use std::borrow::Borrow; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; + +/// Represents a kebab string slice used in validation. +/// +/// This is a wrapper around `str` that ensures the slice is +/// a valid kebab case string according to the component model +/// specification. +/// +/// It also provides an equality and hashing implementation +/// that ignores ASCII case. +#[derive(Debug, Eq)] +#[repr(transparent)] +pub struct KebabStr(str); + +impl KebabStr { + /// Creates a new kebab string slice. + /// + /// Returns `None` if the given string is not a valid kebab string. + pub fn new<'a>(s: impl AsRef + 'a) -> Option<&'a Self> { + let s = Self::new_unchecked(s); + if s.is_kebab_case() { + Some(s) + } else { + None + } + } + + pub(crate) fn new_unchecked<'a>(s: impl AsRef + 'a) -> &'a Self { + // Safety: `KebabStr` is a transparent wrapper around `str` + // Therefore transmuting `&str` to `&KebabStr` is safe. + unsafe { std::mem::transmute::<_, &Self>(s.as_ref()) } + } + + /// Gets the underlying string slice. + pub fn as_str(&self) -> &str { + &self.0 + } + + /// Converts the slice to an owned string. + pub fn to_kebab_string(&self) -> KebabString { + KebabString(self.to_string()) + } + + fn is_kebab_case(&self) -> bool { + let mut lower = false; + let mut upper = false; + for c in self.chars() { + match c { + 'a'..='z' if !lower && !upper => lower = true, + 'A'..='Z' if !lower && !upper => upper = true, + 'a'..='z' if lower => {} + 'A'..='Z' if upper => {} + '0'..='9' if lower || upper => {} + '-' if lower || upper => { + lower = false; + upper = false; + } + _ => return false, + } + } + + !self.is_empty() && !self.ends_with('-') + } +} + +impl Deref for KebabStr { + type Target = str; + + fn deref(&self) -> &str { + self.as_str() + } +} + +impl PartialEq for KebabStr { + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.chars() + .zip(other.chars()) + .all(|(a, b)| a.to_ascii_lowercase() == b.to_ascii_lowercase()) + } +} + +impl PartialEq for KebabStr { + fn eq(&self, other: &KebabString) -> bool { + self.eq(other.as_kebab_str()) + } +} + +impl Hash for KebabStr { + fn hash(&self, state: &mut H) { + self.len().hash(state); + + for b in self.chars() { + b.to_ascii_lowercase().hash(state); + } + } +} + +impl fmt::Display for KebabStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self as &str).fmt(f) + } +} + +impl ToOwned for KebabStr { + type Owned = KebabString; + + fn to_owned(&self) -> Self::Owned { + self.to_kebab_string() + } +} + +/// Represents an owned kebab string for validation. +/// +/// This is a wrapper around `String` that ensures the string is +/// a valid kebab case string according to the component model +/// specification. +/// +/// It also provides an equality and hashing implementation +/// that ignores ASCII case. +#[derive(Debug, Clone, Eq)] +pub struct KebabString(String); + +impl KebabString { + /// Creates a new kebab string. + /// + /// Returns `None` if the given string is not a valid kebab string. + pub fn new(s: impl Into) -> Option { + let s = s.into(); + if KebabStr::new(&s).is_some() { + Some(Self(s)) + } else { + None + } + } + + /// Gets the underlying string. + pub fn as_str(&self) -> &str { + self.0.as_str() + } + + /// Converts the kebab string to a kebab string slice. + pub fn as_kebab_str(&self) -> &KebabStr { + // Safety: internal string is always valid kebab-case + KebabStr::new_unchecked(self.as_str()) + } +} + +impl Deref for KebabString { + type Target = KebabStr; + + fn deref(&self) -> &Self::Target { + self.as_kebab_str() + } +} + +impl Borrow for KebabString { + fn borrow(&self) -> &KebabStr { + self.as_kebab_str() + } +} + +impl PartialEq for KebabString { + fn eq(&self, other: &Self) -> bool { + self.as_kebab_str().eq(other.as_kebab_str()) + } +} + +impl PartialEq for KebabString { + fn eq(&self, other: &KebabStr) -> bool { + self.as_kebab_str().eq(other) + } +} + +impl Hash for KebabString { + fn hash(&self, state: &mut H) { + self.as_kebab_str().hash(state) + } +} + +impl fmt::Display for KebabString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_kebab_str().fmt(f) + } +} + +impl From for String { + fn from(s: KebabString) -> String { + s.0 + } +} + +/// A "kebab name" in the component model which is backed by `T`, which defaults +/// to `String`. +/// +/// This name can be either: +/// +/// * a `KebabStr`: `a-b-c` +/// * a method name : `[method]a-b.c-d` +/// * a static method name : `[static]a-b.c-d` +/// * a constructor: `[constructor]a-b` +/// +/// # Equality and hashing +/// +/// Note that this type the `Method` and `Static` variants are considered equal +/// and hash to the same value. This enables disallowing clashes between the two +/// where method name overlap cannot happen. +#[derive(Clone)] +pub struct KebabName { + raw: String, + parsed: ParsedKebabName, +} + +#[derive(Copy, Clone)] +enum ParsedKebabName { + Normal, + Constructor, + Method { + dot: u32, + }, + Static { + dot: u32, + }, + Id { + colon: u32, + slash: u32, + at: Option, + }, +} + +/// Created via [`KebabName::kind`] and classifies a name. +#[derive(Debug, Clone)] +pub enum KebabNameKind<'a> { + /// `a-b-c` + Normal(&'a KebabStr), + /// `[constructor]a-b` + Constructor(&'a KebabStr), + /// `[method]a-b.c-d` + #[allow(missing_docs)] + Method { + resource: &'a KebabStr, + name: &'a KebabStr, + }, + /// `[static]a-b.c-d` + #[allow(missing_docs)] + Static { + resource: &'a KebabStr, + name: &'a KebabStr, + }, + /// `wasi:http/types@2.0` + #[allow(missing_docs)] + Id { + namespace: &'a KebabStr, + package: &'a KebabStr, + interface: &'a KebabStr, + version: Option, + }, +} + +const CONSTRUCTOR: &str = "[constructor]"; +const METHOD: &str = "[method]"; +const STATIC: &str = "[static]"; + +impl KebabName { + /// Attempts to parse `name` as a kebab name, returning `None` if it's not + /// valid. + pub fn new(name: ComponentExternName<'_>, offset: usize) -> Result { + let validate_kebab = |s: &str| { + if KebabStr::new(s).is_none() { + bail!(offset, "`{s}` is not in kebab case") + } else { + Ok(()) + } + }; + let find = |s: &str, c: char| match s.find(c) { + Some(i) => Ok(i), + None => bail!(offset, "failed to find `{c}` character"), + }; + let parsed = match name { + ComponentExternName::Kebab(s) => { + if let Some(s) = s.strip_prefix(CONSTRUCTOR) { + validate_kebab(s)?; + ParsedKebabName::Constructor + } else if let Some(s) = s.strip_prefix(METHOD) { + let dot = find(s, '.')?; + validate_kebab(&s[..dot])?; + validate_kebab(&s[dot + 1..])?; + ParsedKebabName::Method { dot: dot as u32 } + } else if let Some(s) = s.strip_prefix(STATIC) { + let dot = find(s, '.')?; + validate_kebab(&s[..dot])?; + validate_kebab(&s[dot + 1..])?; + ParsedKebabName::Static { dot: dot as u32 } + } else { + validate_kebab(s)?; + ParsedKebabName::Normal + } + } + ComponentExternName::Interface(s) => { + let colon = find(s, ':')?; + validate_kebab(&s[..colon])?; + let slash = find(s, '/')?; + let at = s[slash..].find('@').map(|i| i + slash); + validate_kebab(&s[colon + 1..slash])?; + validate_kebab(&s[slash + 1..at.unwrap_or(s.len())])?; + if let Some(at) = at { + let version = &s[at + 1..]; + if let Err(e) = version.parse::() { + bail!(offset, "failed to parse version: {e}") + } + } + ParsedKebabName::Id { + colon: colon as u32, + slash: slash as u32, + at: at.map(|i| i as u32), + } + } + }; + Ok(KebabName { + raw: name.as_str().to_string(), + parsed, + }) + } + + /// Returns the [`KebabNameKind`] corresponding to this name. + pub fn kind(&self) -> KebabNameKind<'_> { + match self.parsed { + ParsedKebabName::Normal => KebabNameKind::Normal(KebabStr::new_unchecked(&self.raw)), + ParsedKebabName::Constructor => { + let kebab = &self.raw[CONSTRUCTOR.len()..]; + KebabNameKind::Constructor(KebabStr::new_unchecked(kebab)) + } + ParsedKebabName::Method { dot } => { + let dotted = &self.raw[METHOD.len()..]; + let resource = KebabStr::new_unchecked(&dotted[..dot as usize]); + let name = KebabStr::new_unchecked(&dotted[dot as usize + 1..]); + KebabNameKind::Method { resource, name } + } + ParsedKebabName::Static { dot } => { + let dotted = &self.raw[METHOD.len()..]; + let resource = KebabStr::new_unchecked(&dotted[..dot as usize]); + let name = KebabStr::new_unchecked(&dotted[dot as usize + 1..]); + KebabNameKind::Static { resource, name } + } + ParsedKebabName::Id { colon, slash, at } => { + let colon = colon as usize; + let slash = slash as usize; + let at = at.map(|i| i as usize); + let namespace = KebabStr::new_unchecked(&self.raw[..colon]); + let package = KebabStr::new_unchecked(&self.raw[colon + 1..slash]); + let interface = + KebabStr::new_unchecked(&self.raw[slash + 1..at.unwrap_or(self.raw.len())]); + let version = at.map(|i| Version::parse(&self.raw[i + 1..]).unwrap()); + KebabNameKind::Id { + namespace, + package, + interface, + version, + } + } + } + } + + /// Returns the raw underlying name as a string. + pub fn as_str(&self) -> &str { + &self.raw + } +} + +impl From for String { + fn from(name: KebabName) -> String { + name.raw + } +} + +impl Hash for KebabName { + fn hash(&self, hasher: &mut H) { + self.kind().hash(hasher) + } +} + +impl PartialEq for KebabName { + fn eq(&self, other: &KebabName) -> bool { + self.kind().eq(&other.kind()) + } +} + +impl Eq for KebabName {} + +impl fmt::Display for KebabName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.raw.fmt(f) + } +} + +impl fmt::Debug for KebabName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.raw.fmt(f) + } +} + +impl Hash for KebabNameKind<'_> { + fn hash(&self, hasher: &mut H) { + match self { + KebabNameKind::Normal(name) => { + hasher.write_u8(0); + name.hash(hasher); + } + KebabNameKind::Constructor(name) => { + hasher.write_u8(1); + name.hash(hasher); + } + // for hashing method == static + KebabNameKind::Method { resource, name } | KebabNameKind::Static { resource, name } => { + hasher.write_u8(2); + resource.hash(hasher); + name.hash(hasher); + } + KebabNameKind::Id { + namespace, + package, + interface, + version, + } => { + hasher.write_u8(3); + namespace.hash(hasher); + package.hash(hasher); + interface.hash(hasher); + version.hash(hasher); + } + } + } +} + +impl PartialEq for KebabNameKind<'_> { + fn eq(&self, other: &KebabNameKind<'_>) -> bool { + match (self, other) { + (KebabNameKind::Normal(a), KebabNameKind::Normal(b)) => a == b, + (KebabNameKind::Normal(_), _) => false, + (KebabNameKind::Constructor(a), KebabNameKind::Constructor(b)) => a == b, + (KebabNameKind::Constructor(_), _) => false, + + // method == static for the purposes of hashing so equate them here + // as well. + ( + KebabNameKind::Method { + resource: ar, + name: an, + }, + KebabNameKind::Method { + resource: br, + name: bn, + }, + ) + | ( + KebabNameKind::Static { + resource: ar, + name: an, + }, + KebabNameKind::Static { + resource: br, + name: bn, + }, + ) + | ( + KebabNameKind::Method { + resource: ar, + name: an, + }, + KebabNameKind::Static { + resource: br, + name: bn, + }, + ) + | ( + KebabNameKind::Static { + resource: ar, + name: an, + }, + KebabNameKind::Method { + resource: br, + name: bn, + }, + ) => ar == br && an == bn, + + (KebabNameKind::Method { .. }, _) => false, + (KebabNameKind::Static { .. }, _) => false, + + ( + KebabNameKind::Id { + namespace: an, + package: ap, + interface: ai, + version: av, + }, + KebabNameKind::Id { + namespace: bn, + package: bp, + interface: bi, + version: bv, + }, + ) => an == bn && ap == bp && ai == bi && av == bv, + (KebabNameKind::Id { .. }, _) => false, + } + } +} + +impl Eq for KebabNameKind<'_> {} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashSet; + + fn parse_kebab_name(s: &str) -> Option { + KebabName::new(ComponentExternName::Kebab(s), 0).ok() + } + + #[test] + fn kebab_smoke() { + assert!(KebabStr::new("").is_none()); + assert!(KebabStr::new("a").is_some()); + assert!(KebabStr::new("aB").is_none()); + assert!(KebabStr::new("a-B").is_some()); + assert!(KebabStr::new("a-").is_none()); + assert!(KebabStr::new("-").is_none()); + assert!(KebabStr::new("¶").is_none()); + assert!(KebabStr::new("0").is_none()); + assert!(KebabStr::new("a0").is_some()); + assert!(KebabStr::new("a-0").is_none()); + } + + #[test] + fn name_smoke() { + assert!(parse_kebab_name("a").is_some()); + assert!(parse_kebab_name("[foo]a").is_none()); + assert!(parse_kebab_name("[constructor]a").is_some()); + assert!(parse_kebab_name("[method]a").is_none()); + assert!(parse_kebab_name("[method]a.b").is_some()); + assert!(parse_kebab_name("[method]a.b.c").is_none()); + assert!(parse_kebab_name("[static]a.b").is_some()); + assert!(parse_kebab_name("[static]a").is_none()); + } + + #[test] + fn name_equality() { + assert_eq!(parse_kebab_name("a"), parse_kebab_name("a")); + assert_ne!(parse_kebab_name("a"), parse_kebab_name("b")); + assert_eq!( + parse_kebab_name("[constructor]a"), + parse_kebab_name("[constructor]a") + ); + assert_ne!( + parse_kebab_name("[constructor]a"), + parse_kebab_name("[constructor]b") + ); + assert_eq!( + parse_kebab_name("[method]a.b"), + parse_kebab_name("[method]a.b") + ); + assert_ne!( + parse_kebab_name("[method]a.b"), + parse_kebab_name("[method]b.b") + ); + assert_eq!( + parse_kebab_name("[static]a.b"), + parse_kebab_name("[static]a.b") + ); + assert_ne!( + parse_kebab_name("[static]a.b"), + parse_kebab_name("[static]b.b") + ); + + assert_eq!( + parse_kebab_name("[static]a.b"), + parse_kebab_name("[method]a.b") + ); + assert_eq!( + parse_kebab_name("[method]a.b"), + parse_kebab_name("[static]a.b") + ); + + assert_ne!( + parse_kebab_name("[method]b.b"), + parse_kebab_name("[static]a.b") + ); + + let mut s = HashSet::new(); + assert!(s.insert(parse_kebab_name("a"))); + assert!(s.insert(parse_kebab_name("[constructor]a"))); + assert!(s.insert(parse_kebab_name("[method]a.b"))); + assert!(!s.insert(parse_kebab_name("[static]a.b"))); + assert!(s.insert(parse_kebab_name("[static]b.b"))); + } +} diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 0c776a0430..308a464b73 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -23,25 +23,30 @@ // the various methods here. use crate::{ - limits::MAX_WASM_FUNCTION_LOCALS, BinaryReaderError, BlockType, BrTable, Ieee32, Ieee64, - MemArg, Result, ValType, VisitOperator, WasmFeatures, WasmFuncType, WasmModuleResources, V128, + limits::MAX_WASM_FUNCTION_LOCALS, BinaryReaderError, BlockType, BrTable, HeapType, Ieee32, + Ieee64, MemArg, RefType, Result, ValType, VisitOperator, WasmFeatures, WasmFuncType, + WasmModuleResources, V128, }; use std::ops::{Deref, DerefMut}; pub(crate) struct OperatorValidator { pub(super) locals: Locals, + pub(super) local_inits: Vec, // This is a list of flags for wasm features which are used to gate various // instructions. pub(crate) features: WasmFeatures, // Temporary storage used during the validation of `br_table`. - br_table_tmp: Vec>, + br_table_tmp: Vec, /// The `control` list is the list of blocks that we're currently in. control: Vec, /// The `operands` is the current type stack. - operands: Vec>, + operands: Vec, + /// When local_inits is modified, the relevant index is recorded here to be + /// undone when control pops + inits: Vec, /// Offset of the `end` instruction which emptied the `control` stack, which /// must be the end of the function. @@ -92,6 +97,8 @@ pub struct Frame { pub height: usize, /// Whether this frame is unreachable so far. pub unreachable: bool, + /// The number of initializations in the stack at the time of its creation + pub init_height: usize, } /// The kind of a control flow [`Frame`]. @@ -126,31 +133,69 @@ pub enum FrameKind { } struct OperatorValidatorTemp<'validator, 'resources, T> { + offset: usize, inner: &'validator mut OperatorValidator, resources: &'resources T, } #[derive(Default)] pub struct OperatorValidatorAllocations { - br_table_tmp: Vec>, + br_table_tmp: Vec, control: Vec, - operands: Vec>, + operands: Vec, + local_inits: Vec, + inits: Vec, locals_first: Vec, locals_all: Vec<(u32, ValType)>, } +/// Type storage within the validator. +/// +/// This is used to manage the operand stack and notably isn't just `ValType` to +/// handle unreachable code and the "bottom" type. +#[derive(Debug, Copy, Clone)] +enum MaybeType { + Bot, + HeapBot, + Type(ValType), +} + +// The validator is pretty performance-sensitive and `MaybeType` is the main +// unit of storage, so assert that it doesn't exceed 4 bytes which is the +// current expected size. +const _: () = { + assert!(std::mem::size_of::() == 4); +}; + +impl From for MaybeType { + fn from(ty: ValType) -> MaybeType { + MaybeType::Type(ty) + } +} + +impl From for MaybeType { + fn from(ty: RefType) -> MaybeType { + let ty: ValType = ty.into(); + ty.into() + } +} + impl OperatorValidator { fn new(features: &WasmFeatures, allocs: OperatorValidatorAllocations) -> Self { let OperatorValidatorAllocations { br_table_tmp, control, operands, + local_inits, + inits, locals_first, locals_all, } = allocs; debug_assert!(br_table_tmp.is_empty()); debug_assert!(control.is_empty()); debug_assert!(operands.is_empty()); + debug_assert!(local_inits.is_empty()); + debug_assert!(inits.is_empty()); debug_assert!(locals_first.is_empty()); debug_assert!(locals_all.is_empty()); OperatorValidator { @@ -159,6 +204,8 @@ impl OperatorValidator { first: locals_first, all: locals_all, }, + local_inits, + inits, features: *features, br_table_tmp, operands, @@ -188,15 +235,19 @@ impl OperatorValidator { block_type: BlockType::FuncType(ty), height: 0, unreachable: false, + init_height: 0, }); let params = OperatorValidatorTemp { + // This offset is used by the `func_type_at` and `inputs`. + offset, inner: &mut ret, resources, } - .func_type_at(ty, offset)? + .func_type_at(ty)? .inputs(); for ty in params { ret.locals.define(1, ty); + ret.local_inits.push(true); } Ok(ret) } @@ -215,14 +266,19 @@ impl OperatorValidator { block_type: BlockType::Type(ty), height: 0, unreachable: false, + init_height: 0, }); ret } - pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> { - self.features - .check_value_type(ty) - .map_err(|e| BinaryReaderError::new(e, offset))?; + pub fn define_locals( + &mut self, + offset: usize, + count: u32, + ty: ValType, + resources: &impl WasmModuleResources, + ) -> Result<()> { + resources.check_value_type(ty, &self.features, offset)?; if count == 0 { return Ok(()); } @@ -232,6 +288,8 @@ impl OperatorValidator { offset, )); } + self.local_inits + .resize(self.local_inits.len() + count as usize, ty.is_defaultable()); Ok(()) } @@ -251,7 +309,10 @@ impl OperatorValidator { /// /// A `depth` of 0 will refer to the last operand on the stack. pub fn peek_operand_at(&self, depth: usize) -> Option> { - self.operands.iter().rev().nth(depth).copied() + Some(match self.operands.iter().rev().nth(depth)? { + MaybeType::Type(t) => Some(*t), + MaybeType::Bot | MaybeType::HeapBot => None, + }) } /// Returns the number of frames on the control flow stack. @@ -264,18 +325,20 @@ impl OperatorValidator { } /// Create a temporary [`OperatorValidatorTemp`] for validation. - pub fn with_resources<'validator, 'resources, T>( + pub fn with_resources<'a, 'validator, 'resources, T>( &'validator mut self, resources: &'resources T, - ) -> impl VisitOperator> + 'validator + offset: usize, + ) -> impl VisitOperator<'a, Output = Result<()>> + 'validator where T: WasmModuleResources, 'resources: 'validator, { - OperatorValidatorTemp { + WasmProposalValidator(OperatorValidatorTemp { + offset, inner: self, resources, - } + }) } pub fn finish(&mut self, offset: usize) -> Result<()> { @@ -309,6 +372,8 @@ impl OperatorValidator { br_table_tmp: truncate(self.br_table_tmp), control: truncate(self.control), operands: truncate(self.operands), + local_inits: truncate(self.local_inits), + inits: truncate(self.inits), locals_first: truncate(self.locals.first), locals_all: truncate(self.locals.all), } @@ -324,7 +389,7 @@ impl Deref for OperatorValidatorTemp<'_, '_, R> { impl DerefMut for OperatorValidatorTemp<'_, '_, R> { fn deref_mut(&mut self) -> &mut OperatorValidator { - &mut self.inner + self.inner } } @@ -336,7 +401,7 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R /// Otherwise the push operation always succeeds. fn push_operand(&mut self, ty: T) -> Result<()> where - T: Into>, + T: Into, { let maybe_ty = ty.into(); self.operands.push(maybe_ty); @@ -350,7 +415,7 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R /// simply that something is needed to be popped. /// /// If `expected` is `Some(T)` then this will be guaranteed to return - /// `Some(T)`, and it will only return success if the current block is + /// `T`, and it will only return success if the current block is /// unreachable or if `T` was found at the top of the operand stack. /// /// If `expected` is `None` then it indicates that something must be on the @@ -361,7 +426,7 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R /// matches `expected`. If `None` is returned then it means that `None` was /// expected and a type was successfully popped, but its exact type is /// indeterminate because the current block is unreachable. - fn pop_operand(&mut self, offset: usize, expected: Option) -> Result> { + fn pop_operand(&mut self, expected: Option) -> Result { // This method is one of the hottest methods in the validator so to // improve codegen this method contains a fast-path success case where // if the top operand on the stack is as expected it's returned @@ -373,20 +438,21 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R // matched against the state of the world to see if we could actually // pop it. If we shouldn't have popped it then it's passed to the slow // path to get pushed back onto the stack. - let popped = if let Some(actual_ty) = self.operands.pop() { - if actual_ty == expected { - if let Some(control) = self.control.last() { - if self.operands.len() >= control.height { - return Ok(actual_ty); + let popped = match self.operands.pop() { + Some(MaybeType::Type(actual_ty)) => { + if Some(actual_ty) == expected { + if let Some(control) = self.control.last() { + if self.operands.len() >= control.height { + return Ok(MaybeType::Type(actual_ty)); + } } } + Some(MaybeType::Type(actual_ty)) } - Some(actual_ty) - } else { - None + other => other, }; - self._pop_operand(offset, expected, popped) + self._pop_operand(expected, popped) } // This is the "real" implementation of `pop_operand` which is 100% @@ -395,59 +461,98 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R #[cold] fn _pop_operand( &mut self, - offset: usize, expected: Option, - popped: Option>, - ) -> Result> { + popped: Option, + ) -> Result { self.operands.extend(popped); let control = match self.control.last() { Some(c) => c, - None => return Err(self.err_beyond_end(offset)), + None => return Err(self.err_beyond_end(self.offset)), }; - let actual = if self.operands.len() == control.height { - if control.unreachable { - None - } else { + let actual = if self.operands.len() == control.height && control.unreachable { + MaybeType::Bot + } else { + if self.operands.len() == control.height { let desc = match expected { Some(ty) => ty_to_str(ty), - None => "a type", + None => "a type".into(), }; bail!( - offset, + self.offset, "type mismatch: expected {desc} but nothing on stack" ) + } else { + self.operands.pop().unwrap() } - } else { - self.operands.pop().unwrap() }; - if let (Some(actual_ty), Some(expected_ty)) = (actual, expected) { - if actual_ty != expected_ty { - bail!( - offset, - "type mismatch: expected {}, found {}", - ty_to_str(expected_ty), - ty_to_str(actual_ty) - ) + if let Some(expected) = expected { + match (actual, expected) { + // The bottom type matches all expectations + (MaybeType::Bot, _) + // The "heap bottom" type only matches other references types, + // but not any integer types. + | (MaybeType::HeapBot, ValType::Ref(_)) => {} + + // Use the `matches` predicate to test if a found type matches + // the expectation. + (MaybeType::Type(actual), expected) => { + if !self.resources.matches(actual, expected) { + bail!( + self.offset, + "type mismatch: expected {}, found {}", + ty_to_str(expected), + ty_to_str(actual) + ); + } + } + + // A "heap bottom" type cannot match any numeric types. + ( + MaybeType::HeapBot, + ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128, + ) => { + bail!( + self.offset, + "type mismatch: expected {}, found heap type", + ty_to_str(expected) + ) + } } } Ok(actual) } + fn pop_ref(&mut self) -> Result> { + match self.pop_operand(None)? { + MaybeType::Bot | MaybeType::HeapBot => Ok(None), + MaybeType::Type(ValType::Ref(rt)) => Ok(Some(rt)), + MaybeType::Type(ty) => bail!( + self.offset, + "type mismatch: expected ref but found {}", + ty_to_str(ty) + ), + } + } + /// Fetches the type for the local at `idx`, returning an error if it's out /// of bounds. - fn local(&self, offset: usize, idx: u32) -> Result { + fn local(&self, idx: u32) -> Result { match self.locals.get(idx) { Some(ty) => Ok(ty), - None => bail!(offset, "unknown local {}: local index out of bounds", idx), + None => bail!( + self.offset, + "unknown local {}: local index out of bounds", + idx + ), } } /// Flags the current control frame as unreachable, additionally truncating /// the currently active operand stack. - fn unreachable(&mut self, offset: usize) -> Result<()> { + fn unreachable(&mut self) -> Result<()> { let control = match self.control.last_mut() { Some(frame) => frame, - None => return Err(self.err_beyond_end(offset)), + None => return Err(self.err_beyond_end(self.offset)), }; control.unreachable = true; let new_height = control.height; @@ -461,19 +566,21 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R /// or block itself. The `kind` of block is specified which indicates how /// breaks interact with this block's type. Additionally the type signature /// of the block is specified by `ty`. - fn push_ctrl(&mut self, offset: usize, kind: FrameKind, ty: BlockType) -> Result<()> { + fn push_ctrl(&mut self, kind: FrameKind, ty: BlockType) -> Result<()> { // Push a new frame which has a snapshot of the height of the current // operand stack. let height = self.operands.len(); + let init_height = self.inits.len(); self.control.push(Frame { kind, block_type: ty, height, unreachable: false, + init_height, }); // All of the parameters are now also available in this control frame, // so we push them here in order. - for ty in self.params(offset, ty)? { + for ty in self.params(ty)? { self.push_operand(ty)?; } Ok(()) @@ -483,27 +590,33 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R /// /// This function is used when exiting a block and leaves a block scope. /// Internally this will validate that blocks have the correct result type. - fn pop_ctrl(&mut self, offset: usize) -> Result { + fn pop_ctrl(&mut self) -> Result { // Read the expected type and expected height of the operand stack the // end of the frame. let frame = match self.control.last() { Some(f) => f, - None => return Err(self.err_beyond_end(offset)), + None => return Err(self.err_beyond_end(self.offset)), }; let ty = frame.block_type; let height = frame.height; + let init_height = frame.init_height; + + // reset_locals in the spec + for init in self.inits.split_off(init_height) { + self.local_inits[init as usize] = false; + } // Pop all the result types, in reverse order, from the operand stack. // These types will, possibly, be transferred to the next frame. - for ty in self.results(offset, ty)?.rev() { - self.pop_operand(offset, Some(ty))?; + for ty in self.results(ty)?.rev() { + self.pop_operand(Some(ty))?; } // Make sure that the operand stack has returned to is original // height... if self.operands.len() != height { bail!( - offset, + self.offset, "type mismatch: values remaining on stack at end of block" ); } @@ -516,142 +629,81 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R /// /// Returns the type signature of the block that we're jumping to as well /// as the kind of block if the jump is valid. Otherwise returns an error. - fn jump(&self, offset: usize, depth: u32) -> Result<(BlockType, FrameKind)> { + fn jump(&self, depth: u32) -> Result<(BlockType, FrameKind)> { if self.control.is_empty() { - return Err(self.err_beyond_end(offset)); + return Err(self.err_beyond_end(self.offset)); } match (self.control.len() - 1).checked_sub(depth as usize) { Some(i) => { let frame = &self.control[i]; Ok((frame.block_type, frame.kind)) } - None => bail!(offset, "unknown label: branch depth too large"), + None => bail!(self.offset, "unknown label: branch depth too large"), } } /// Validates that `memory_index` is valid in this module, and returns the /// type of address used to index the memory specified. - fn check_memory_index(&self, offset: usize, memory_index: u32) -> Result { + fn check_memory_index(&self, memory_index: u32) -> Result { match self.resources.memory_at(memory_index) { Some(mem) => Ok(mem.index_type()), - None => bail!(offset, "unknown memory {}", memory_index), + None => bail!(self.offset, "unknown memory {}", memory_index), } } /// Validates a `memarg for alignment and such (also the memory it /// references), and returns the type of index used to address the memory. - fn check_memarg(&self, memarg: MemArg, max_align: u8, offset: usize) -> Result { - let index_ty = self.check_memory_index(offset, memarg.memory)?; - let align = memarg.align; - if align > max_align { - bail!(offset, "alignment must not be larger than natural"); + fn check_memarg(&self, memarg: MemArg) -> Result { + let index_ty = self.check_memory_index(memarg.memory)?; + if memarg.align > memarg.max_align { + bail!(self.offset, "alignment must not be larger than natural"); } if index_ty == ValType::I32 && memarg.offset > u64::from(u32::MAX) { - bail!(offset, "offset out of range: must be <= 2**32"); + bail!(self.offset, "offset out of range: must be <= 2**32"); } Ok(index_ty) } - #[cfg_attr(not(feature = "deterministic"), inline(always))] - fn check_non_deterministic_enabled(&self, offset: usize) -> Result<()> { - if cfg!(feature = "deterministic") && !self.features.deterministic_only { - bail!(offset, "deterministic_only support is not enabled"); - } - Ok(()) - } - - fn check_threads_enabled(&self, offset: usize) -> Result<()> { - if !self.features.threads { - bail!(offset, "threads support is not enabled") - } - Ok(()) - } - - fn check_reference_types_enabled(&self, offset: usize) -> Result<()> { - if !self.features.reference_types { - bail!(offset, "reference types support is not enabled") + fn check_floats_enabled(&self) -> Result<()> { + if !self.features.floats { + bail!(self.offset, "floating-point instruction disallowed"); } Ok(()) } - /// Checks if Wasm proposal `saturating_float_to_int` is enabled. - fn check_saturating_float_to_int_enabled(&self, offset: usize) -> Result<()> { - if !self.features.saturating_float_to_int { + fn check_shared_memarg(&self, memarg: MemArg) -> Result { + if memarg.align != memarg.max_align { bail!( - offset, - "saturating float to int conversions support is not enabled" + self.offset, + "atomic instructions must always specify maximum alignment" ); } - Ok(()) - } - - /// Checks if Wasm proposal `sign_extension` is enabled. - fn check_sign_extension_enabled(&self, offset: usize) -> Result<()> { - if !self.features.sign_extension { - bail!(offset, "sign extension operations support is not enabled"); - } - Ok(()) - } - - fn check_simd_enabled(&self, offset: usize) -> Result<()> { - if !self.features.simd { - bail!(offset, "SIMD support is not enabled"); - } - Ok(()) + self.check_memory_index(memarg.memory) } - fn check_relaxed_simd_enabled(&self, offset: usize) -> Result<()> { - // Relaxed SIMD operators make sense only with SIMD and be non-deterministic. - self.check_non_deterministic_enabled(offset)?; - self.check_simd_enabled(offset)?; - if !self.features.relaxed_simd { - bail!(offset, "Relaxed SIMD support is not enabled"); - } - Ok(()) - } - - fn check_exceptions_enabled(&self, offset: usize) -> Result<()> { - if !self.features.exceptions { - bail!(offset, "Exceptions support is not enabled"); - } - Ok(()) - } - - fn check_bulk_memory_enabled(&self, offset: usize) -> Result<()> { - if !self.features.bulk_memory { - bail!(offset, "bulk memory support is not enabled"); - } - Ok(()) - } - - fn check_shared_memarg_wo_align(&self, offset: usize, memarg: MemArg) -> Result { - self.check_memory_index(offset, memarg.memory) - } - - fn check_simd_lane_index(&self, offset: usize, index: u8, max: u8) -> Result<()> { + fn check_simd_lane_index(&self, index: u8, max: u8) -> Result<()> { if index >= max { - bail!(offset, "SIMD index out of bounds"); + bail!(self.offset, "SIMD index out of bounds"); } Ok(()) } /// Validates a block type, primarily with various in-flight proposals. - fn check_block_type(&self, offset: usize, ty: BlockType) -> Result<()> { + fn check_block_type(&self, ty: BlockType) -> Result<()> { match ty { BlockType::Empty => Ok(()), - BlockType::Type(ty) => self - .features - .check_value_type(ty) - .map_err(|e| BinaryReaderError::new(e, offset)), + BlockType::Type(t) => self + .resources + .check_value_type(t, &self.features, self.offset), BlockType::FuncType(idx) => { if !self.features.multi_value { bail!( - offset, + self.offset, "blocks, loops, and ifs may only produce a resulttype \ when multi-value is not enabled", ); } - self.func_type_at(idx, offset)?; + self.func_type_at(idx)?; Ok(()) } } @@ -659,19 +711,31 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R /// Validates a `call` instruction, ensuring that the function index is /// in-bounds and the right types are on the stack to call the function. - fn check_call(&mut self, offset: usize, function_index: u32) -> Result<()> { - let ty = match self.resources.type_of_function(function_index) { + fn check_call(&mut self, function_index: u32) -> Result<()> { + let ty = match self.resources.type_index_of_function(function_index) { + Some(i) => i, + None => { + bail!( + self.offset, + "unknown function {function_index}: function index out of bounds", + ); + } + }; + self.check_call_ty(ty) + } + + fn check_call_ty(&mut self, type_index: u32) -> Result<()> { + let ty = match self.resources.func_type_at(type_index) { Some(i) => i, None => { bail!( - offset, - "unknown function {}: function index out of bounds", - function_index + self.offset, + "unknown type {type_index}: type index out of bounds", ); } }; for ty in ty.inputs().rev() { - self.pop_operand(offset, Some(ty))?; + self.pop_operand(Some(ty))?; } for ty in ty.outputs() { self.push_operand(ty)?; @@ -680,21 +744,27 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R } /// Validates a call to an indirect function, very similar to `check_call`. - fn check_call_indirect(&mut self, offset: usize, index: u32, table_index: u32) -> Result<()> { + fn check_call_indirect(&mut self, index: u32, table_index: u32) -> Result<()> { match self.resources.table_at(table_index) { None => { - bail!(offset, "unknown table: table index out of bounds"); + bail!(self.offset, "unknown table: table index out of bounds"); } Some(tab) => { - if tab.element_type != ValType::FuncRef { - bail!(offset, "indirect calls must go through a table of funcref"); + if !self + .resources + .matches(ValType::Ref(tab.element_type), ValType::FUNCREF) + { + bail!( + self.offset, + "indirect calls must go through a table with type <= funcref", + ); } } } - let ty = self.func_type_at(index, offset)?; - self.pop_operand(offset, Some(ValType::I32))?; + let ty = self.func_type_at(index)?; + self.pop_operand(Some(ValType::I32))?; for ty in ty.inputs().rev() { - self.pop_operand(offset, Some(ty))?; + self.pop_operand(Some(ty))?; } for ty in ty.outputs() { self.push_operand(ty)?; @@ -704,470 +774,478 @@ impl<'resources, R: WasmModuleResources> OperatorValidatorTemp<'_, 'resources, R /// Validates a `return` instruction, popping types from the operand /// stack that the function needs. - fn check_return(&mut self, offset: usize) -> Result<()> { + fn check_return(&mut self) -> Result<()> { if self.control.is_empty() { - return Err(self.err_beyond_end(offset)); + return Err(self.err_beyond_end(self.offset)); } - for ty in self.results(offset, self.control[0].block_type)?.rev() { - self.pop_operand(offset, Some(ty))?; + for ty in self.results(self.control[0].block_type)?.rev() { + self.pop_operand(Some(ty))?; } - self.unreachable(offset)?; + self.unreachable()?; Ok(()) } /// Checks the validity of a common comparison operator. - fn check_cmp_op(&mut self, offset: usize, ty: ValType) -> Result<()> { - self.pop_operand(offset, Some(ty))?; - self.pop_operand(offset, Some(ty))?; + fn check_cmp_op(&mut self, ty: ValType) -> Result<()> { + self.pop_operand(Some(ty))?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I32)?; Ok(()) } /// Checks the validity of a common float comparison operator. - fn check_fcmp_op(&mut self, offset: usize, ty: ValType) -> Result<()> { + fn check_fcmp_op(&mut self, ty: ValType) -> Result<()> { debug_assert!(matches!(ty, ValType::F32 | ValType::F64)); - self.check_non_deterministic_enabled(offset)?; - self.check_cmp_op(offset, ty) + self.check_floats_enabled()?; + self.check_cmp_op(ty) } /// Checks the validity of a common unary operator. - fn check_unary_op(&mut self, offset: usize, ty: ValType) -> Result<()> { - self.pop_operand(offset, Some(ty))?; + fn check_unary_op(&mut self, ty: ValType) -> Result<()> { + self.pop_operand(Some(ty))?; self.push_operand(ty)?; Ok(()) } /// Checks the validity of a common unary float operator. - fn check_funary_op(&mut self, offset: usize, ty: ValType) -> Result<()> { + fn check_funary_op(&mut self, ty: ValType) -> Result<()> { debug_assert!(matches!(ty, ValType::F32 | ValType::F64)); - self.check_non_deterministic_enabled(offset)?; - self.check_unary_op(offset, ty) + self.check_floats_enabled()?; + self.check_unary_op(ty) } /// Checks the validity of a common conversion operator. - fn check_conversion_op(&mut self, offset: usize, into: ValType, from: ValType) -> Result<()> { - self.pop_operand(offset, Some(from))?; + fn check_conversion_op(&mut self, into: ValType, from: ValType) -> Result<()> { + self.pop_operand(Some(from))?; self.push_operand(into)?; Ok(()) } /// Checks the validity of a common conversion operator. - fn check_fconversion_op(&mut self, offset: usize, into: ValType, from: ValType) -> Result<()> { + fn check_fconversion_op(&mut self, into: ValType, from: ValType) -> Result<()> { debug_assert!(matches!(into, ValType::F32 | ValType::F64)); - self.check_non_deterministic_enabled(offset)?; - self.check_conversion_op(offset, into, from) + self.check_floats_enabled()?; + self.check_conversion_op(into, from) } /// Checks the validity of a common binary operator. - fn check_binary_op(&mut self, offset: usize, ty: ValType) -> Result<()> { - self.pop_operand(offset, Some(ty))?; - self.pop_operand(offset, Some(ty))?; + fn check_binary_op(&mut self, ty: ValType) -> Result<()> { + self.pop_operand(Some(ty))?; + self.pop_operand(Some(ty))?; self.push_operand(ty)?; Ok(()) } /// Checks the validity of a common binary float operator. - fn check_fbinary_op(&mut self, offset: usize, ty: ValType) -> Result<()> { + fn check_fbinary_op(&mut self, ty: ValType) -> Result<()> { debug_assert!(matches!(ty, ValType::F32 | ValType::F64)); - self.check_non_deterministic_enabled(offset)?; - self.check_binary_op(offset, ty) + self.check_floats_enabled()?; + self.check_binary_op(ty) } /// Checks the validity of an atomic load operator. - fn check_atomic_load(&mut self, offset: usize, memarg: MemArg, load_ty: ValType) -> Result<()> { - self.check_threads_enabled(offset)?; - let ty = self.check_shared_memarg_wo_align(offset, memarg)?; - self.pop_operand(offset, Some(ty))?; + fn check_atomic_load(&mut self, memarg: MemArg, load_ty: ValType) -> Result<()> { + let ty = self.check_shared_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(load_ty)?; Ok(()) } /// Checks the validity of an atomic store operator. - fn check_atomic_store( - &mut self, - offset: usize, - memarg: MemArg, - store_ty: ValType, - ) -> Result<()> { - self.check_threads_enabled(offset)?; - let ty = self.check_shared_memarg_wo_align(offset, memarg)?; - self.pop_operand(offset, Some(store_ty))?; - self.pop_operand(offset, Some(ty))?; + fn check_atomic_store(&mut self, memarg: MemArg, store_ty: ValType) -> Result<()> { + let ty = self.check_shared_memarg(memarg)?; + self.pop_operand(Some(store_ty))?; + self.pop_operand(Some(ty))?; Ok(()) } /// Checks the validity of a common atomic binary operator. - fn check_atomic_binary_op( - &mut self, - offset: usize, - memarg: MemArg, - op_ty: ValType, - ) -> Result<()> { - self.check_threads_enabled(offset)?; - let ty = self.check_shared_memarg_wo_align(offset, memarg)?; - self.pop_operand(offset, Some(op_ty))?; - self.pop_operand(offset, Some(ty))?; + fn check_atomic_binary_op(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> { + let ty = self.check_shared_memarg(memarg)?; + self.pop_operand(Some(op_ty))?; + self.pop_operand(Some(ty))?; self.push_operand(op_ty)?; Ok(()) } /// Checks the validity of an atomic compare exchange operator. - fn check_atomic_binary_cmpxchg( - &mut self, - offset: usize, - memarg: MemArg, - op_ty: ValType, - ) -> Result<()> { - self.check_threads_enabled(offset)?; - let ty = self.check_shared_memarg_wo_align(offset, memarg)?; - self.pop_operand(offset, Some(op_ty))?; - self.pop_operand(offset, Some(op_ty))?; - self.pop_operand(offset, Some(ty))?; + fn check_atomic_binary_cmpxchg(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> { + let ty = self.check_shared_memarg(memarg)?; + self.pop_operand(Some(op_ty))?; + self.pop_operand(Some(op_ty))?; + self.pop_operand(Some(ty))?; self.push_operand(op_ty)?; Ok(()) } /// Checks a [`V128`] splat operator. - fn check_v128_splat(&mut self, offset: usize, src_ty: ValType) -> Result<()> { - self.check_simd_enabled(offset)?; - self.pop_operand(offset, Some(src_ty))?; + fn check_v128_splat(&mut self, src_ty: ValType) -> Result<()> { + self.pop_operand(Some(src_ty))?; self.push_operand(ValType::V128)?; Ok(()) } /// Checks a [`V128`] binary operator. - fn check_v128_binary_op(&mut self, offset: usize) -> Result<()> { - self.check_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn check_v128_binary_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } /// Checks a [`V128`] binary float operator. - fn check_v128_fbinary_op(&mut self, offset: usize) -> Result<()> { - self.check_non_deterministic_enabled(offset)?; - self.check_v128_binary_op(offset) - } - - /// Checks a [`V128`] binary operator. - fn check_v128_relaxed_binary_op(&mut self, offset: usize) -> Result<()> { - self.check_relaxed_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) + fn check_v128_fbinary_op(&mut self) -> Result<()> { + self.check_floats_enabled()?; + self.check_v128_binary_op() } /// Checks a [`V128`] binary operator. - fn check_v128_unary_op(&mut self, offset: usize) -> Result<()> { - self.check_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; + fn check_v128_unary_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } /// Checks a [`V128`] binary operator. - fn check_v128_funary_op(&mut self, offset: usize) -> Result<()> { - self.check_non_deterministic_enabled(offset)?; - self.check_v128_unary_op(offset) - } - - /// Checks a [`V128`] binary operator. - fn check_v128_relaxed_unary_op(&mut self, offset: usize) -> Result<()> { - self.check_relaxed_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) + fn check_v128_funary_op(&mut self) -> Result<()> { + self.check_floats_enabled()?; + self.check_v128_unary_op() } /// Checks a [`V128`] relaxed ternary operator. - fn check_v128_relaxed_ternary_op(&mut self, offset: usize) -> Result<()> { - self.check_relaxed_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn check_v128_ternary_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } /// Checks a [`V128`] relaxed ternary operator. - fn check_v128_bitmask_op(&mut self, offset: usize) -> Result<()> { - self.check_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; + fn check_v128_bitmask_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::I32)?; Ok(()) } /// Checks a [`V128`] relaxed ternary operator. - fn check_v128_shift_op(&mut self, offset: usize) -> Result<()> { - self.check_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn check_v128_shift_op(&mut self) -> Result<()> { + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } /// Checks a [`V128`] common load operator. - fn check_v128_load_op(&mut self, offset: usize, memarg: MemArg) -> Result<()> { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 3, offset)?; - self.pop_operand(offset, Some(idx))?; + fn check_v128_load_op(&mut self, memarg: MemArg) -> Result<()> { + let idx = self.check_memarg(memarg)?; + self.pop_operand(Some(idx))?; self.push_operand(ValType::V128)?; Ok(()) } - fn func_type_at(&self, at: u32, offset: usize) -> Result<&'resources R::FuncType> { + fn func_type_at(&self, at: u32) -> Result<&'resources R::FuncType> { self.resources .func_type_at(at) - .ok_or_else(|| format_err!(offset, "unknown type: type index out of bounds")) + .ok_or_else(|| format_err!(self.offset, "unknown type: type index out of bounds")) } - fn tag_at(&self, at: u32, offset: usize) -> Result<&'resources R::FuncType> { + fn tag_at(&self, at: u32) -> Result<&'resources R::FuncType> { self.resources .tag_at(at) - .ok_or_else(|| format_err!(offset, "unknown tag {}: tag index out of bounds", at)) + .ok_or_else(|| format_err!(self.offset, "unknown tag {}: tag index out of bounds", at)) } - fn params( - &self, - offset: usize, - ty: BlockType, - ) -> Result + 'resources> { + fn params(&self, ty: BlockType) -> Result + 'resources> { Ok(match ty { BlockType::Empty | BlockType::Type(_) => Either::B(None.into_iter()), - BlockType::FuncType(t) => Either::A(self.func_type_at(t, offset)?.inputs()), + BlockType::FuncType(t) => Either::A(self.func_type_at(t)?.inputs()), }) } - fn results( - &self, - offset: usize, - ty: BlockType, - ) -> Result + 'resources> { + fn results(&self, ty: BlockType) -> Result + 'resources> { Ok(match ty { BlockType::Empty => Either::B(None.into_iter()), BlockType::Type(t) => Either::B(Some(t).into_iter()), - BlockType::FuncType(t) => Either::A(self.func_type_at(t, offset)?.outputs()), + BlockType::FuncType(t) => Either::A(self.func_type_at(t)?.outputs()), }) } fn label_types( &self, - offset: usize, ty: BlockType, kind: FrameKind, ) -> Result + 'resources> { Ok(match kind { - FrameKind::Loop => Either::A(self.params(offset, ty)?), - _ => Either::B(self.results(offset, ty)?), + FrameKind::Loop => Either::A(self.params(ty)?), + _ => Either::B(self.results(ty)?), }) } } -fn ty_to_str(ty: ValType) -> &'static str { +pub fn ty_to_str(ty: ValType) -> &'static str { match ty { ValType::I32 => "i32", ValType::I64 => "i64", ValType::F32 => "f32", ValType::F64 => "f64", ValType::V128 => "v128", - ValType::FuncRef => "funcref", - ValType::ExternRef => "externref", + ValType::Ref(r) => r.wat(), } } +/// A wrapper "visitor" around the real operator validator internally which +/// exists to check that the required wasm feature is enabled to proceed with +/// validation. +/// +/// This validator is macro-generated to ensure that the proposal listed in this +/// crate's macro matches the one that's validated here. Each instruction's +/// visit method validates the specified proposal is enabled and then delegates +/// to `OperatorValidatorTemp` to perform the actual opcode validation. +struct WasmProposalValidator<'validator, 'resources, T>( + OperatorValidatorTemp<'validator, 'resources, T>, +); + +impl WasmProposalValidator<'_, '_, T> { + fn check_enabled(&self, flag: bool, desc: &str) -> Result<()> { + if flag { + return Ok(()); + } + bail!(self.0.offset, "{desc} support is not enabled"); + } +} + +macro_rules! validate_proposal { + ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + $( + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Result<()> { + validate_proposal!(validate self $proposal); + self.0.$visit($( $($arg),* )?) + } + )* + }; + + (validate self mvp) => {}; + (validate $self:ident $proposal:ident) => { + $self.check_enabled($self.0.features.$proposal, validate_proposal!(desc $proposal))? + }; + + (desc simd) => ("SIMD"); + (desc relaxed_simd) => ("relaxed SIMD"); + (desc threads) => ("threads"); + (desc saturating_float_to_int) => ("saturating float to int conversions"); + (desc reference_types) => ("reference types"); + (desc bulk_memory) => ("bulk memory"); + (desc sign_extension) => ("sign extension operations"); + (desc exceptions) => ("exceptions"); + (desc tail_call) => ("tail calls"); + (desc function_references) => ("function references"); + (desc memory_control) => ("memory control"); + (desc gc) => ("gc"); +} + +impl<'a, T> VisitOperator<'a> for WasmProposalValidator<'_, '_, T> +where + T: WasmModuleResources, +{ + type Output = Result<()>; + + for_each_operator!(validate_proposal); +} + impl<'a, T> VisitOperator<'a> for OperatorValidatorTemp<'_, '_, T> where T: WasmModuleResources, { type Output = Result<()>; - fn visit_nop(&mut self, _: usize) -> Self::Output { + fn visit_nop(&mut self) -> Self::Output { Ok(()) } - fn visit_unreachable(&mut self, offset: usize) -> Self::Output { - self.unreachable(offset)?; + fn visit_unreachable(&mut self) -> Self::Output { + self.unreachable()?; Ok(()) } - fn visit_block(&mut self, offset: usize, ty: BlockType) -> Self::Output { - self.check_block_type(offset, ty)?; - for ty in self.params(offset, ty)?.rev() { - self.pop_operand(offset, Some(ty))?; + fn visit_block(&mut self, ty: BlockType) -> Self::Output { + self.check_block_type(ty)?; + for ty in self.params(ty)?.rev() { + self.pop_operand(Some(ty))?; } - self.push_ctrl(offset, FrameKind::Block, ty)?; + self.push_ctrl(FrameKind::Block, ty)?; Ok(()) } - fn visit_loop(&mut self, offset: usize, ty: BlockType) -> Self::Output { - self.check_block_type(offset, ty)?; - for ty in self.params(offset, ty)?.rev() { - self.pop_operand(offset, Some(ty))?; + fn visit_loop(&mut self, ty: BlockType) -> Self::Output { + self.check_block_type(ty)?; + for ty in self.params(ty)?.rev() { + self.pop_operand(Some(ty))?; } - self.push_ctrl(offset, FrameKind::Loop, ty)?; + self.push_ctrl(FrameKind::Loop, ty)?; Ok(()) } - fn visit_if(&mut self, offset: usize, ty: BlockType) -> Self::Output { - self.check_block_type(offset, ty)?; - self.pop_operand(offset, Some(ValType::I32))?; - for ty in self.params(offset, ty)?.rev() { - self.pop_operand(offset, Some(ty))?; + fn visit_if(&mut self, ty: BlockType) -> Self::Output { + self.check_block_type(ty)?; + self.pop_operand(Some(ValType::I32))?; + for ty in self.params(ty)?.rev() { + self.pop_operand(Some(ty))?; } - self.push_ctrl(offset, FrameKind::If, ty)?; + self.push_ctrl(FrameKind::If, ty)?; Ok(()) } - fn visit_else(&mut self, offset: usize) -> Self::Output { - let frame = self.pop_ctrl(offset)?; + fn visit_else(&mut self) -> Self::Output { + let frame = self.pop_ctrl()?; if frame.kind != FrameKind::If { - bail!(offset, "else found outside of an `if` block"); + bail!(self.offset, "else found outside of an `if` block"); } - self.push_ctrl(offset, FrameKind::Else, frame.block_type)?; + self.push_ctrl(FrameKind::Else, frame.block_type)?; Ok(()) } - fn visit_try(&mut self, offset: usize, ty: BlockType) -> Self::Output { - self.check_exceptions_enabled(offset)?; - self.check_block_type(offset, ty)?; - for ty in self.params(offset, ty)?.rev() { - self.pop_operand(offset, Some(ty))?; + fn visit_try(&mut self, ty: BlockType) -> Self::Output { + self.check_block_type(ty)?; + for ty in self.params(ty)?.rev() { + self.pop_operand(Some(ty))?; } - self.push_ctrl(offset, FrameKind::Try, ty)?; + self.push_ctrl(FrameKind::Try, ty)?; Ok(()) } - fn visit_catch(&mut self, offset: usize, index: u32) -> Self::Output { - self.check_exceptions_enabled(offset)?; - let frame = self.pop_ctrl(offset)?; + fn visit_catch(&mut self, index: u32) -> Self::Output { + let frame = self.pop_ctrl()?; if frame.kind != FrameKind::Try && frame.kind != FrameKind::Catch { - bail!(offset, "catch found outside of an `try` block"); + bail!(self.offset, "catch found outside of an `try` block"); } // Start a new frame and push `exnref` value. let height = self.operands.len(); + let init_height = self.inits.len(); self.control.push(Frame { kind: FrameKind::Catch, block_type: frame.block_type, height, unreachable: false, + init_height, }); // Push exception argument types. - let ty = self.tag_at(index, offset)?; + let ty = self.tag_at(index)?; for ty in ty.inputs() { self.push_operand(ty)?; } Ok(()) } - fn visit_throw(&mut self, offset: usize, index: u32) -> Self::Output { - self.check_exceptions_enabled(offset)?; + fn visit_throw(&mut self, index: u32) -> Self::Output { // Check values associated with the exception. - let ty = self.tag_at(index, offset)?; + let ty = self.tag_at(index)?; for ty in ty.inputs().rev() { - self.pop_operand(offset, Some(ty))?; + self.pop_operand(Some(ty))?; } if ty.outputs().len() > 0 { - bail!(offset, "result type expected to be empty for exception"); + bail!( + self.offset, + "result type expected to be empty for exception" + ); } - self.unreachable(offset)?; + self.unreachable()?; Ok(()) } - fn visit_rethrow(&mut self, offset: usize, relative_depth: u32) -> Self::Output { - self.check_exceptions_enabled(offset)?; + fn visit_rethrow(&mut self, relative_depth: u32) -> Self::Output { // This is not a jump, but we need to check that the `rethrow` // targets an actual `catch` to get the exception. - let (_, kind) = self.jump(offset, relative_depth)?; + let (_, kind) = self.jump(relative_depth)?; if kind != FrameKind::Catch && kind != FrameKind::CatchAll { bail!( - offset, + self.offset, "invalid rethrow label: target was not a `catch` block" ); } - self.unreachable(offset)?; + self.unreachable()?; Ok(()) } - fn visit_delegate(&mut self, offset: usize, relative_depth: u32) -> Self::Output { - self.check_exceptions_enabled(offset)?; - let frame = self.pop_ctrl(offset)?; + fn visit_delegate(&mut self, relative_depth: u32) -> Self::Output { + let frame = self.pop_ctrl()?; if frame.kind != FrameKind::Try { - bail!(offset, "delegate found outside of an `try` block"); + bail!(self.offset, "delegate found outside of an `try` block"); } // This operation is not a jump, but we need to check the // depth for validity - let _ = self.jump(offset, relative_depth)?; - for ty in self.results(offset, frame.block_type)? { + let _ = self.jump(relative_depth)?; + for ty in self.results(frame.block_type)? { self.push_operand(ty)?; } Ok(()) } - fn visit_catch_all(&mut self, offset: usize) -> Self::Output { - self.check_exceptions_enabled(offset)?; - let frame = self.pop_ctrl(offset)?; + fn visit_catch_all(&mut self) -> Self::Output { + let frame = self.pop_ctrl()?; if frame.kind == FrameKind::CatchAll { - bail!(offset, "only one catch_all allowed per `try` block"); + bail!(self.offset, "only one catch_all allowed per `try` block"); } else if frame.kind != FrameKind::Try && frame.kind != FrameKind::Catch { - bail!(offset, "catch_all found outside of a `try` block"); + bail!(self.offset, "catch_all found outside of a `try` block"); } let height = self.operands.len(); + let init_height = self.inits.len(); self.control.push(Frame { kind: FrameKind::CatchAll, block_type: frame.block_type, height, unreachable: false, + init_height, }); Ok(()) } - fn visit_end(&mut self, offset: usize) -> Self::Output { - let mut frame = self.pop_ctrl(offset)?; + fn visit_end(&mut self) -> Self::Output { + let mut frame = self.pop_ctrl()?; // Note that this `if` isn't included in the appendix right // now, but it's used to allow for `if` statements that are // missing an `else` block which have the same parameter/return // types on the block (since that's valid). if frame.kind == FrameKind::If { - self.push_ctrl(offset, FrameKind::Else, frame.block_type)?; - frame = self.pop_ctrl(offset)?; + self.push_ctrl(FrameKind::Else, frame.block_type)?; + frame = self.pop_ctrl()?; } - for ty in self.results(offset, frame.block_type)? { + for ty in self.results(frame.block_type)? { self.push_operand(ty)?; } if self.control.is_empty() && self.end_which_emptied_control.is_none() { - self.end_which_emptied_control = Some(offset); + assert_ne!(self.offset, 0); + self.end_which_emptied_control = Some(self.offset); } Ok(()) } - fn visit_br(&mut self, offset: usize, relative_depth: u32) -> Self::Output { - let (ty, kind) = self.jump(offset, relative_depth)?; - for ty in self.label_types(offset, ty, kind)?.rev() { - self.pop_operand(offset, Some(ty))?; + fn visit_br(&mut self, relative_depth: u32) -> Self::Output { + let (ty, kind) = self.jump(relative_depth)?; + for ty in self.label_types(ty, kind)?.rev() { + self.pop_operand(Some(ty))?; } - self.unreachable(offset)?; + self.unreachable()?; Ok(()) } - fn visit_br_if(&mut self, offset: usize, relative_depth: u32) -> Self::Output { - self.pop_operand(offset, Some(ValType::I32))?; - let (ty, kind) = self.jump(offset, relative_depth)?; - let types = self.label_types(offset, ty, kind)?; + fn visit_br_if(&mut self, relative_depth: u32) -> Self::Output { + self.pop_operand(Some(ValType::I32))?; + let (ty, kind) = self.jump(relative_depth)?; + let types = self.label_types(ty, kind)?; for ty in types.clone().rev() { - self.pop_operand(offset, Some(ty))?; + self.pop_operand(Some(ty))?; } for ty in types { self.push_operand(ty)?; } Ok(()) } - fn visit_br_table(&mut self, offset: usize, table: BrTable) -> Self::Output { - self.pop_operand(offset, Some(ValType::I32))?; - let default = self.jump(offset, table.default())?; - let default_types = self.label_types(offset, default.0, default.1)?; + fn visit_br_table(&mut self, table: BrTable) -> Self::Output { + self.pop_operand(Some(ValType::I32))?; + let default = self.jump(table.default())?; + let default_types = self.label_types(default.0, default.1)?; for element in table.targets() { let relative_depth = element?; - let block = self.jump(offset, relative_depth)?; - let tys = self.label_types(offset, block.0, block.1)?; + let block = self.jump(relative_depth)?; + let tys = self.label_types(block.0, block.1)?; if tys.len() != default_types.len() { bail!( - offset, + self.offset, "type mismatch: br_table target labels have different number of types" ); } debug_assert!(self.br_table_tmp.is_empty()); for ty in tys.rev() { - let ty = self.pop_operand(offset, Some(ty))?; + let ty = self.pop_operand(Some(ty))?; self.br_table_tmp.push(ty); } for ty in self.inner.br_table_tmp.drain(..).rev() { @@ -1175,2040 +1253,2113 @@ where } } for ty in default_types.rev() { - self.pop_operand(offset, Some(ty))?; + self.pop_operand(Some(ty))?; } - self.unreachable(offset)?; + self.unreachable()?; Ok(()) } - fn visit_return(&mut self, offset: usize) -> Self::Output { - self.check_return(offset)?; + fn visit_return(&mut self) -> Self::Output { + self.check_return()?; Ok(()) } - fn visit_call(&mut self, offset: usize, function_index: u32) -> Self::Output { - self.check_call(offset, function_index)?; + fn visit_call(&mut self, function_index: u32) -> Self::Output { + self.check_call(function_index)?; Ok(()) } - fn visit_return_call(&mut self, offset: usize, function_index: u32) -> Self::Output { - if !self.features.tail_call { - bail!(offset, "tail calls support is not enabled"); - } - self.check_call(offset, function_index)?; - self.check_return(offset)?; + fn visit_return_call(&mut self, function_index: u32) -> Self::Output { + self.check_call(function_index)?; + self.check_return()?; Ok(()) } + fn visit_call_ref(&mut self, type_index: u32) -> Self::Output { + let hty = HeapType::Indexed(type_index); + self.resources + .check_heap_type(hty, &self.features, self.offset)?; + // If `None` is popped then that means a "bottom" type was popped which + // is always considered equivalent to the `hty` tag. + if let Some(rt) = self.pop_ref()? { + let expected = RefType::indexed_func(true, type_index) + .expect("existing heap types should be within our limits"); + if !self + .resources + .matches(ValType::Ref(rt), ValType::Ref(expected)) + { + bail!( + self.offset, + "type mismatch: funcref on stack does not match specified type", + ); + } + } + self.check_call_ty(type_index) + } + fn visit_return_call_ref(&mut self, type_index: u32) -> Self::Output { + self.visit_call_ref(type_index)?; + self.check_return() + } fn visit_call_indirect( &mut self, - offset: usize, index: u32, table_index: u32, table_byte: u8, ) -> Self::Output { if table_byte != 0 && !self.features.reference_types { - bail!(offset, "reference-types not enabled: zero byte expected"); + bail!( + self.offset, + "reference-types not enabled: zero byte expected" + ); } - self.check_call_indirect(offset, index, table_index)?; + self.check_call_indirect(index, table_index)?; Ok(()) } - fn visit_return_call_indirect( - &mut self, - offset: usize, - index: u32, - table_index: u32, - ) -> Self::Output { - if !self.features.tail_call { - bail!(offset, "tail calls support is not enabled"); - } - self.check_call_indirect(offset, index, table_index)?; - self.check_return(offset)?; + fn visit_return_call_indirect(&mut self, index: u32, table_index: u32) -> Self::Output { + self.check_call_indirect(index, table_index)?; + self.check_return()?; Ok(()) } - fn visit_drop(&mut self, offset: usize) -> Self::Output { - self.pop_operand(offset, None)?; + fn visit_drop(&mut self) -> Self::Output { + self.pop_operand(None)?; Ok(()) } - fn visit_select(&mut self, offset: usize) -> Self::Output { - self.pop_operand(offset, Some(ValType::I32))?; - let ty1 = self.pop_operand(offset, None)?; - let ty2 = self.pop_operand(offset, None)?; - fn is_num(ty: Option) -> bool { - matches!( - ty, - Some(ValType::I32) - | Some(ValType::I64) - | Some(ValType::F32) - | Some(ValType::F64) - | Some(ValType::V128) - | None - ) - } - if !is_num(ty1) || !is_num(ty2) { - bail!(offset, "type mismatch: select only takes integral types") - } - if ty1 != ty2 && ty1 != None && ty2 != None { - bail!( - offset, - "type mismatch: select operands have different types" - ) - } - self.push_operand(ty1.or(ty2))?; + fn visit_select(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::I32))?; + let ty1 = self.pop_operand(None)?; + let ty2 = self.pop_operand(None)?; + + let ty = match (ty1, ty2) { + // All heap-related types aren't allowed with the `select` + // instruction + (MaybeType::HeapBot, _) + | (_, MaybeType::HeapBot) + | (MaybeType::Type(ValType::Ref(_)), _) + | (_, MaybeType::Type(ValType::Ref(_))) => { + bail!( + self.offset, + "type mismatch: select only takes integral types" + ) + } + + // If one operand is the "bottom" type then whatever the other + // operand is is the result of the `select` + (MaybeType::Bot, t) | (t, MaybeType::Bot) => t, + + // Otherwise these are two integral types and they must match for + // `select` to typecheck. + (t @ MaybeType::Type(t1), MaybeType::Type(t2)) => { + if t1 != t2 { + bail!( + self.offset, + "type mismatch: select operands have different types" + ); + } + t + } + }; + self.push_operand(ty)?; Ok(()) } - fn visit_typed_select(&mut self, offset: usize, ty: ValType) -> Self::Output { - self.features - .check_value_type(ty) - .map_err(|e| BinaryReaderError::new(e, offset))?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; - self.pop_operand(offset, Some(ty))?; + fn visit_typed_select(&mut self, ty: ValType) -> Self::Output { + self.resources + .check_value_type(ty, &self.features, self.offset)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ty))?; + self.pop_operand(Some(ty))?; self.push_operand(ty)?; Ok(()) } - fn visit_local_get(&mut self, offset: usize, local_index: u32) -> Self::Output { - let ty = self.local(offset, local_index)?; + fn visit_local_get(&mut self, local_index: u32) -> Self::Output { + let ty = self.local(local_index)?; + if !self.local_inits[local_index as usize] { + bail!(self.offset, "uninitialized local: {}", local_index); + } self.push_operand(ty)?; Ok(()) } - fn visit_local_set(&mut self, offset: usize, local_index: u32) -> Self::Output { - let ty = self.local(offset, local_index)?; - self.pop_operand(offset, Some(ty))?; + fn visit_local_set(&mut self, local_index: u32) -> Self::Output { + let ty = self.local(local_index)?; + self.pop_operand(Some(ty))?; + if !self.local_inits[local_index as usize] { + self.local_inits[local_index as usize] = true; + self.inits.push(local_index); + } Ok(()) } - fn visit_local_tee(&mut self, offset: usize, local_index: u32) -> Self::Output { - let ty = self.local(offset, local_index)?; - self.pop_operand(offset, Some(ty))?; + fn visit_local_tee(&mut self, local_index: u32) -> Self::Output { + let ty = self.local(local_index)?; + self.pop_operand(Some(ty))?; + if !self.local_inits[local_index as usize] { + self.local_inits[local_index as usize] = true; + self.inits.push(local_index); + } + self.push_operand(ty)?; Ok(()) } - fn visit_global_get(&mut self, offset: usize, global_index: u32) -> Self::Output { + fn visit_global_get(&mut self, global_index: u32) -> Self::Output { if let Some(ty) = self.resources.global_at(global_index) { self.push_operand(ty.content_type)?; } else { - bail!(offset, "unknown global: global index out of bounds"); + bail!(self.offset, "unknown global: global index out of bounds"); }; Ok(()) } - fn visit_global_set(&mut self, offset: usize, global_index: u32) -> Self::Output { + fn visit_global_set(&mut self, global_index: u32) -> Self::Output { if let Some(ty) = self.resources.global_at(global_index) { if !ty.mutable { bail!( - offset, + self.offset, "global is immutable: cannot modify it with `global.set`" ); } - self.pop_operand(offset, Some(ty.content_type))?; + self.pop_operand(Some(ty.content_type))?; } else { - bail!(offset, "unknown global: global index out of bounds"); + bail!(self.offset, "unknown global: global index out of bounds"); }; Ok(()) } - fn visit_i32_load(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 2, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i64_load(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 3, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_i64_load(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I64)?; Ok(()) } - fn visit_f32_load(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - let ty = self.check_memarg(memarg, 2, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_f32_load(&mut self, memarg: MemArg) -> Self::Output { + self.check_floats_enabled()?; + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::F32)?; Ok(()) } - fn visit_f64_load(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - let ty = self.check_memarg(memarg, 3, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_f64_load(&mut self, memarg: MemArg) -> Self::Output { + self.check_floats_enabled()?; + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::F64)?; Ok(()) } - fn visit_i32_load8_s(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 0, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_i32_load8_s(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i32_load8_u(&mut self, input: usize, memarg: MemArg) -> Self::Output { - self.visit_i32_load8_s(input, memarg) + fn visit_i32_load8_u(&mut self, memarg: MemArg) -> Self::Output { + self.visit_i32_load8_s(memarg) } - fn visit_i32_load16_s(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 1, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_i32_load16_s(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i32_load16_u(&mut self, input: usize, memarg: MemArg) -> Self::Output { - self.visit_i32_load16_s(input, memarg) + fn visit_i32_load16_u(&mut self, memarg: MemArg) -> Self::Output { + self.visit_i32_load16_s(memarg) } - fn visit_i64_load8_s(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 0, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_i64_load8_s(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I64)?; Ok(()) } - fn visit_i64_load8_u(&mut self, input: usize, memarg: MemArg) -> Self::Output { - self.visit_i64_load8_s(input, memarg) + fn visit_i64_load8_u(&mut self, memarg: MemArg) -> Self::Output { + self.visit_i64_load8_s(memarg) } - fn visit_i64_load16_s(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 1, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_i64_load16_s(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I64)?; Ok(()) } - fn visit_i64_load16_u(&mut self, input: usize, memarg: MemArg) -> Self::Output { - self.visit_i64_load16_s(input, memarg) + fn visit_i64_load16_u(&mut self, memarg: MemArg) -> Self::Output { + self.visit_i64_load16_s(memarg) } - fn visit_i64_load32_s(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 2, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_i64_load32_s(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I64)?; Ok(()) } - fn visit_i64_load32_u(&mut self, input: usize, memarg: MemArg) -> Self::Output { - self.visit_i64_load32_s(input, memarg) + fn visit_i64_load32_u(&mut self, memarg: MemArg) -> Self::Output { + self.visit_i64_load32_s(memarg) } - fn visit_i32_store(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 2, offset)?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; + fn visit_i32_store(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_i64_store(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 3, offset)?; - self.pop_operand(offset, Some(ValType::I64))?; - self.pop_operand(offset, Some(ty))?; + fn visit_i64_store(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_f32_store(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - let ty = self.check_memarg(memarg, 2, offset)?; - self.pop_operand(offset, Some(ValType::F32))?; - self.pop_operand(offset, Some(ty))?; + fn visit_f32_store(&mut self, memarg: MemArg) -> Self::Output { + self.check_floats_enabled()?; + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::F32))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_f64_store(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - let ty = self.check_memarg(memarg, 3, offset)?; - self.pop_operand(offset, Some(ValType::F64))?; - self.pop_operand(offset, Some(ty))?; + fn visit_f64_store(&mut self, memarg: MemArg) -> Self::Output { + self.check_floats_enabled()?; + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::F64))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_i32_store8(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 0, offset)?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; + fn visit_i32_store8(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_i32_store16(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 1, offset)?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; + fn visit_i32_store16(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_i64_store8(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 0, offset)?; - self.pop_operand(offset, Some(ValType::I64))?; - self.pop_operand(offset, Some(ty))?; + fn visit_i64_store8(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_i64_store16(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 1, offset)?; - self.pop_operand(offset, Some(ValType::I64))?; - self.pop_operand(offset, Some(ty))?; + fn visit_i64_store16(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_i64_store32(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - let ty = self.check_memarg(memarg, 2, offset)?; - self.pop_operand(offset, Some(ValType::I64))?; - self.pop_operand(offset, Some(ty))?; + fn visit_i64_store32(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_memory_size(&mut self, offset: usize, mem: u32, mem_byte: u8) -> Self::Output { + fn visit_memory_size(&mut self, mem: u32, mem_byte: u8) -> Self::Output { if mem_byte != 0 && !self.features.multi_memory { - bail!(offset, "multi-memory not enabled: zero byte expected"); + bail!(self.offset, "multi-memory not enabled: zero byte expected"); } - let index_ty = self.check_memory_index(offset, mem)?; + let index_ty = self.check_memory_index(mem)?; self.push_operand(index_ty)?; Ok(()) } - fn visit_memory_grow(&mut self, offset: usize, mem: u32, mem_byte: u8) -> Self::Output { + fn visit_memory_grow(&mut self, mem: u32, mem_byte: u8) -> Self::Output { if mem_byte != 0 && !self.features.multi_memory { - bail!(offset, "multi-memory not enabled: zero byte expected"); + bail!(self.offset, "multi-memory not enabled: zero byte expected"); } - let index_ty = self.check_memory_index(offset, mem)?; - self.pop_operand(offset, Some(index_ty))?; + let index_ty = self.check_memory_index(mem)?; + self.pop_operand(Some(index_ty))?; self.push_operand(index_ty)?; Ok(()) } - fn visit_i32_const(&mut self, _offset: usize, _value: i32) -> Self::Output { + fn visit_i32_const(&mut self, _value: i32) -> Self::Output { self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i64_const(&mut self, _offset: usize, _value: i64) -> Self::Output { + fn visit_i64_const(&mut self, _value: i64) -> Self::Output { self.push_operand(ValType::I64)?; Ok(()) } - fn visit_f32_const(&mut self, offset: usize, _value: Ieee32) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; + fn visit_f32_const(&mut self, _value: Ieee32) -> Self::Output { + self.check_floats_enabled()?; self.push_operand(ValType::F32)?; Ok(()) } - fn visit_f64_const(&mut self, offset: usize, _value: Ieee64) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; + fn visit_f64_const(&mut self, _value: Ieee64) -> Self::Output { + self.check_floats_enabled()?; self.push_operand(ValType::F64)?; Ok(()) } - fn visit_i32_eqz(&mut self, offset: usize) -> Self::Output { - self.pop_operand(offset, Some(ValType::I32))?; + fn visit_i32_eqz(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::I32))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i32_eq(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_eq(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_ne(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_ne(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_lt_s(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_lt_s(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_lt_u(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_lt_u(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_gt_s(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_gt_s(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_gt_u(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_gt_u(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_le_s(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_le_s(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_le_u(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_le_u(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_ge_s(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_ge_s(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i32_ge_u(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I32) + fn visit_i32_ge_u(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I32) } - fn visit_i64_eqz(&mut self, offset: usize) -> Self::Output { - self.pop_operand(offset, Some(ValType::I64))?; + fn visit_i64_eqz(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::I64))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i64_eq(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_eq(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_ne(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_ne(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_lt_s(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_lt_s(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_lt_u(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_lt_u(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_gt_s(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_gt_s(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_gt_u(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_gt_u(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_le_s(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_le_s(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_le_u(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_le_u(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_ge_s(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_ge_s(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_i64_ge_u(&mut self, offset: usize) -> Self::Output { - self.check_cmp_op(offset, ValType::I64) + fn visit_i64_ge_u(&mut self) -> Self::Output { + self.check_cmp_op(ValType::I64) } - fn visit_f32_eq(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F32) + fn visit_f32_eq(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F32) } - fn visit_f32_ne(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F32) + fn visit_f32_ne(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F32) } - fn visit_f32_lt(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F32) + fn visit_f32_lt(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F32) } - fn visit_f32_gt(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F32) + fn visit_f32_gt(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F32) } - fn visit_f32_le(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F32) + fn visit_f32_le(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F32) } - fn visit_f32_ge(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F32) + fn visit_f32_ge(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F32) } - fn visit_f64_eq(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F64) + fn visit_f64_eq(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F64) } - fn visit_f64_ne(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F64) + fn visit_f64_ne(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F64) } - fn visit_f64_lt(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F64) + fn visit_f64_lt(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F64) } - fn visit_f64_gt(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F64) + fn visit_f64_gt(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F64) } - fn visit_f64_le(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F64) + fn visit_f64_le(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F64) } - fn visit_f64_ge(&mut self, offset: usize) -> Self::Output { - self.check_fcmp_op(offset, ValType::F64) + fn visit_f64_ge(&mut self) -> Self::Output { + self.check_fcmp_op(ValType::F64) } - fn visit_i32_clz(&mut self, offset: usize) -> Self::Output { - self.check_unary_op(offset, ValType::I32) + fn visit_i32_clz(&mut self) -> Self::Output { + self.check_unary_op(ValType::I32) } - fn visit_i32_ctz(&mut self, offset: usize) -> Self::Output { - self.check_unary_op(offset, ValType::I32) + fn visit_i32_ctz(&mut self) -> Self::Output { + self.check_unary_op(ValType::I32) } - fn visit_i32_popcnt(&mut self, offset: usize) -> Self::Output { - self.check_unary_op(offset, ValType::I32) + fn visit_i32_popcnt(&mut self) -> Self::Output { + self.check_unary_op(ValType::I32) } - fn visit_i32_add(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_add(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_sub(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_sub(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_mul(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_mul(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_div_s(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_div_s(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_div_u(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_div_u(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_rem_s(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_rem_s(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_rem_u(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_rem_u(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_and(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_and(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_or(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_or(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_xor(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_xor(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_shl(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_shl(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_shr_s(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_shr_s(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_shr_u(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_shr_u(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_rotl(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_rotl(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i32_rotr(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I32) + fn visit_i32_rotr(&mut self) -> Self::Output { + self.check_binary_op(ValType::I32) } - fn visit_i64_clz(&mut self, offset: usize) -> Self::Output { - self.check_unary_op(offset, ValType::I64) + fn visit_i64_clz(&mut self) -> Self::Output { + self.check_unary_op(ValType::I64) } - fn visit_i64_ctz(&mut self, offset: usize) -> Self::Output { - self.check_unary_op(offset, ValType::I64) + fn visit_i64_ctz(&mut self) -> Self::Output { + self.check_unary_op(ValType::I64) } - fn visit_i64_popcnt(&mut self, offset: usize) -> Self::Output { - self.check_unary_op(offset, ValType::I64) + fn visit_i64_popcnt(&mut self) -> Self::Output { + self.check_unary_op(ValType::I64) } - fn visit_i64_add(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_add(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_sub(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_sub(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_mul(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_mul(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_div_s(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_div_s(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_div_u(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_div_u(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_rem_s(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_rem_s(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_rem_u(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_rem_u(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_and(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_and(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_or(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_or(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_xor(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_xor(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_shl(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_shl(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_shr_s(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_shr_s(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_shr_u(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_shr_u(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_rotl(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_rotl(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_i64_rotr(&mut self, offset: usize) -> Self::Output { - self.check_binary_op(offset, ValType::I64) + fn visit_i64_rotr(&mut self) -> Self::Output { + self.check_binary_op(ValType::I64) } - fn visit_f32_abs(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F32) + fn visit_f32_abs(&mut self) -> Self::Output { + self.check_funary_op(ValType::F32) } - fn visit_f32_neg(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F32) + fn visit_f32_neg(&mut self) -> Self::Output { + self.check_funary_op(ValType::F32) } - fn visit_f32_ceil(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F32) + fn visit_f32_ceil(&mut self) -> Self::Output { + self.check_funary_op(ValType::F32) } - fn visit_f32_floor(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F32) + fn visit_f32_floor(&mut self) -> Self::Output { + self.check_funary_op(ValType::F32) } - fn visit_f32_trunc(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F32) + fn visit_f32_trunc(&mut self) -> Self::Output { + self.check_funary_op(ValType::F32) } - fn visit_f32_nearest(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F32) + fn visit_f32_nearest(&mut self) -> Self::Output { + self.check_funary_op(ValType::F32) } - fn visit_f32_sqrt(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F32) + fn visit_f32_sqrt(&mut self) -> Self::Output { + self.check_funary_op(ValType::F32) } - fn visit_f32_add(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F32) + fn visit_f32_add(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F32) } - fn visit_f32_sub(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F32) + fn visit_f32_sub(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F32) } - fn visit_f32_mul(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F32) + fn visit_f32_mul(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F32) } - fn visit_f32_div(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F32) + fn visit_f32_div(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F32) } - fn visit_f32_min(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F32) + fn visit_f32_min(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F32) } - fn visit_f32_max(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F32) + fn visit_f32_max(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F32) } - fn visit_f32_copysign(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F32) + fn visit_f32_copysign(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F32) } - fn visit_f64_abs(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F64) + fn visit_f64_abs(&mut self) -> Self::Output { + self.check_funary_op(ValType::F64) } - fn visit_f64_neg(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F64) + fn visit_f64_neg(&mut self) -> Self::Output { + self.check_funary_op(ValType::F64) } - fn visit_f64_ceil(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F64) + fn visit_f64_ceil(&mut self) -> Self::Output { + self.check_funary_op(ValType::F64) } - fn visit_f64_floor(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F64) + fn visit_f64_floor(&mut self) -> Self::Output { + self.check_funary_op(ValType::F64) } - fn visit_f64_trunc(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F64) + fn visit_f64_trunc(&mut self) -> Self::Output { + self.check_funary_op(ValType::F64) } - fn visit_f64_nearest(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F64) + fn visit_f64_nearest(&mut self) -> Self::Output { + self.check_funary_op(ValType::F64) } - fn visit_f64_sqrt(&mut self, offset: usize) -> Self::Output { - self.check_funary_op(offset, ValType::F64) + fn visit_f64_sqrt(&mut self) -> Self::Output { + self.check_funary_op(ValType::F64) } - fn visit_f64_add(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F64) + fn visit_f64_add(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F64) } - fn visit_f64_sub(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F64) + fn visit_f64_sub(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F64) } - fn visit_f64_mul(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F64) + fn visit_f64_mul(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F64) } - fn visit_f64_div(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F64) + fn visit_f64_div(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F64) } - fn visit_f64_min(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F64) + fn visit_f64_min(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F64) } - fn visit_f64_max(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F64) + fn visit_f64_max(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F64) } - fn visit_f64_copysign(&mut self, offset: usize) -> Self::Output { - self.check_fbinary_op(offset, ValType::F64) + fn visit_f64_copysign(&mut self) -> Self::Output { + self.check_fbinary_op(ValType::F64) } - fn visit_i32_wrap_i64(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I32, ValType::I64) + fn visit_i32_wrap_i64(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::I64) } - fn visit_i32_trunc_f32_s(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I32, ValType::F32) + fn visit_i32_trunc_f32_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F32) } - fn visit_i32_trunc_f32_u(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I32, ValType::F32) + fn visit_i32_trunc_f32_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F32) } - fn visit_i32_trunc_f64_s(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I32, ValType::F64) + fn visit_i32_trunc_f64_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F64) } - fn visit_i32_trunc_f64_u(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I32, ValType::F64) + fn visit_i32_trunc_f64_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F64) } - fn visit_i64_extend_i32_s(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I64, ValType::I32) + fn visit_i64_extend_i32_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::I32) } - fn visit_i64_extend_i32_u(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I64, ValType::I32) + fn visit_i64_extend_i32_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::I32) } - fn visit_i64_trunc_f32_s(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I64, ValType::F32) + fn visit_i64_trunc_f32_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F32) } - fn visit_i64_trunc_f32_u(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I64, ValType::F32) + fn visit_i64_trunc_f32_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F32) } - fn visit_i64_trunc_f64_s(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I64, ValType::F64) + fn visit_i64_trunc_f64_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F64) } - fn visit_i64_trunc_f64_u(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I64, ValType::F64) + fn visit_i64_trunc_f64_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F64) } - fn visit_f32_convert_i32_s(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F32, ValType::I32) + fn visit_f32_convert_i32_s(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F32, ValType::I32) } - fn visit_f32_convert_i32_u(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F32, ValType::I32) + fn visit_f32_convert_i32_u(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F32, ValType::I32) } - fn visit_f32_convert_i64_s(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F32, ValType::I64) + fn visit_f32_convert_i64_s(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F32, ValType::I64) } - fn visit_f32_convert_i64_u(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F32, ValType::I64) + fn visit_f32_convert_i64_u(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F32, ValType::I64) } - fn visit_f32_demote_f64(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F32, ValType::F64) + fn visit_f32_demote_f64(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F32, ValType::F64) } - fn visit_f64_convert_i32_s(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F64, ValType::I32) + fn visit_f64_convert_i32_s(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F64, ValType::I32) } - fn visit_f64_convert_i32_u(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F64, ValType::I32) + fn visit_f64_convert_i32_u(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F64, ValType::I32) } - fn visit_f64_convert_i64_s(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F64, ValType::I64) + fn visit_f64_convert_i64_s(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F64, ValType::I64) } - fn visit_f64_convert_i64_u(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F64, ValType::I64) + fn visit_f64_convert_i64_u(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F64, ValType::I64) } - fn visit_f64_promote_f32(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F64, ValType::F32) + fn visit_f64_promote_f32(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F64, ValType::F32) } - fn visit_i32_reinterpret_f32(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I32, ValType::F32) + fn visit_i32_reinterpret_f32(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F32) } - fn visit_i64_reinterpret_f64(&mut self, offset: usize) -> Self::Output { - self.check_conversion_op(offset, ValType::I64, ValType::F64) + fn visit_i64_reinterpret_f64(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F64) } - fn visit_f32_reinterpret_i32(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F32, ValType::I32) + fn visit_f32_reinterpret_i32(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F32, ValType::I32) } - fn visit_f64_reinterpret_i64(&mut self, offset: usize) -> Self::Output { - self.check_fconversion_op(offset, ValType::F64, ValType::I64) + fn visit_f64_reinterpret_i64(&mut self) -> Self::Output { + self.check_fconversion_op(ValType::F64, ValType::I64) } - fn visit_i32_trunc_sat_f32_s(&mut self, offset: usize) -> Self::Output { - self.check_saturating_float_to_int_enabled(offset)?; - self.check_conversion_op(offset, ValType::I32, ValType::F32) + fn visit_i32_trunc_sat_f32_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F32) } - fn visit_i32_trunc_sat_f32_u(&mut self, offset: usize) -> Self::Output { - self.check_saturating_float_to_int_enabled(offset)?; - self.check_conversion_op(offset, ValType::I32, ValType::F32) + fn visit_i32_trunc_sat_f32_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F32) } - fn visit_i32_trunc_sat_f64_s(&mut self, offset: usize) -> Self::Output { - self.check_saturating_float_to_int_enabled(offset)?; - self.check_conversion_op(offset, ValType::I32, ValType::F64) + fn visit_i32_trunc_sat_f64_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F64) } - fn visit_i32_trunc_sat_f64_u(&mut self, offset: usize) -> Self::Output { - self.check_saturating_float_to_int_enabled(offset)?; - self.check_conversion_op(offset, ValType::I32, ValType::F64) + fn visit_i32_trunc_sat_f64_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I32, ValType::F64) } - fn visit_i64_trunc_sat_f32_s(&mut self, offset: usize) -> Self::Output { - self.check_saturating_float_to_int_enabled(offset)?; - self.check_conversion_op(offset, ValType::I64, ValType::F32) + fn visit_i64_trunc_sat_f32_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F32) } - fn visit_i64_trunc_sat_f32_u(&mut self, offset: usize) -> Self::Output { - self.check_saturating_float_to_int_enabled(offset)?; - self.check_conversion_op(offset, ValType::I64, ValType::F32) + fn visit_i64_trunc_sat_f32_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F32) } - fn visit_i64_trunc_sat_f64_s(&mut self, offset: usize) -> Self::Output { - self.check_saturating_float_to_int_enabled(offset)?; - self.check_conversion_op(offset, ValType::I64, ValType::F64) + fn visit_i64_trunc_sat_f64_s(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F64) } - fn visit_i64_trunc_sat_f64_u(&mut self, offset: usize) -> Self::Output { - self.check_saturating_float_to_int_enabled(offset)?; - self.check_conversion_op(offset, ValType::I64, ValType::F64) + fn visit_i64_trunc_sat_f64_u(&mut self) -> Self::Output { + self.check_conversion_op(ValType::I64, ValType::F64) } - fn visit_i32_extend8_s(&mut self, offset: usize) -> Self::Output { - self.check_sign_extension_enabled(offset)?; - self.check_unary_op(offset, ValType::I32) + fn visit_i32_extend8_s(&mut self) -> Self::Output { + self.check_unary_op(ValType::I32) } - fn visit_i32_extend16_s(&mut self, offset: usize) -> Self::Output { - self.check_sign_extension_enabled(offset)?; - self.check_unary_op(offset, ValType::I32) + fn visit_i32_extend16_s(&mut self) -> Self::Output { + self.check_unary_op(ValType::I32) } - fn visit_i64_extend8_s(&mut self, offset: usize) -> Self::Output { - self.check_sign_extension_enabled(offset)?; - self.check_unary_op(offset, ValType::I64) + fn visit_i64_extend8_s(&mut self) -> Self::Output { + self.check_unary_op(ValType::I64) } - fn visit_i64_extend16_s(&mut self, offset: usize) -> Self::Output { - self.check_sign_extension_enabled(offset)?; - self.check_unary_op(offset, ValType::I64) + fn visit_i64_extend16_s(&mut self) -> Self::Output { + self.check_unary_op(ValType::I64) } - fn visit_i64_extend32_s(&mut self, offset: usize) -> Self::Output { - self.check_sign_extension_enabled(offset)?; - self.check_unary_op(offset, ValType::I64) + fn visit_i64_extend32_s(&mut self) -> Self::Output { + self.check_unary_op(ValType::I64) } - fn visit_i32_atomic_load(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_load(offset, memarg, ValType::I32) + fn visit_i32_atomic_load(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_load(memarg, ValType::I32) } - fn visit_i32_atomic_load16_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_load(offset, memarg, ValType::I32) + fn visit_i32_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_load(memarg, ValType::I32) } - fn visit_i32_atomic_load8_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_load(offset, memarg, ValType::I32) + fn visit_i32_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_load(memarg, ValType::I32) } - fn visit_i64_atomic_load(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_load(offset, memarg, ValType::I64) + fn visit_i64_atomic_load(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_load(memarg, ValType::I64) } - fn visit_i64_atomic_load32_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_load(offset, memarg, ValType::I64) + fn visit_i64_atomic_load32_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_load(memarg, ValType::I64) } - fn visit_i64_atomic_load16_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_load(offset, memarg, ValType::I64) + fn visit_i64_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_load(memarg, ValType::I64) } - fn visit_i64_atomic_load8_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_load(offset, memarg, ValType::I64) + fn visit_i64_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_load(memarg, ValType::I64) } - fn visit_i32_atomic_store(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_store(offset, memarg, ValType::I32) + fn visit_i32_atomic_store(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_store(memarg, ValType::I32) } - fn visit_i32_atomic_store16(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_store(offset, memarg, ValType::I32) + fn visit_i32_atomic_store16(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_store(memarg, ValType::I32) } - fn visit_i32_atomic_store8(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_store(offset, memarg, ValType::I32) + fn visit_i32_atomic_store8(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_store(memarg, ValType::I32) } - fn visit_i64_atomic_store(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_store(offset, memarg, ValType::I64) + fn visit_i64_atomic_store(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_store(memarg, ValType::I64) } - fn visit_i64_atomic_store32(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_store(offset, memarg, ValType::I64) + fn visit_i64_atomic_store32(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_store(memarg, ValType::I64) } - fn visit_i64_atomic_store16(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_store(offset, memarg, ValType::I64) + fn visit_i64_atomic_store16(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_store(memarg, ValType::I64) } - fn visit_i64_atomic_store8(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_store(offset, memarg, ValType::I64) + fn visit_i64_atomic_store8(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_store(memarg, ValType::I64) } - fn visit_i32_atomic_rmw_add(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw_sub(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw_and(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw_or(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw_xor(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw16_add_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw16_sub_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw16_and_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw16_or_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw16_xor_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw8_add_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw8_sub_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw8_and_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw8_or_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw8_xor_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i64_atomic_rmw_add(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw_sub(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw_and(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw_or(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw_xor(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw32_add_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw32_add_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw32_sub_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw32_sub_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw32_and_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw32_and_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw32_or_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw32_or_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw32_xor_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw32_xor_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw16_add_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw16_sub_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw16_and_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw16_or_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw16_xor_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw8_add_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw8_sub_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw8_and_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw8_or_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw8_xor_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i32_atomic_rmw_xchg(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw16_xchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw8_xchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_i32_atomic_rmw_cmpxchg(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_cmpxchg(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_cmpxchg(memarg, ValType::I32) } - fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_cmpxchg(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_cmpxchg(memarg, ValType::I32) } - fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_cmpxchg(offset, memarg, ValType::I32) + fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_cmpxchg(memarg, ValType::I32) } - fn visit_i64_atomic_rmw_xchg(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw32_xchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw32_xchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw16_xchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw8_xchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I64) } - fn visit_i64_atomic_rmw_cmpxchg(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_cmpxchg(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_cmpxchg(memarg, ValType::I64) } - fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_cmpxchg(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_cmpxchg(memarg, ValType::I64) } - fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_cmpxchg(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_cmpxchg(memarg, ValType::I64) } - fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_cmpxchg(offset, memarg, ValType::I64) + fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_cmpxchg(memarg, ValType::I64) } - fn visit_memory_atomic_notify(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_atomic_binary_op(offset, memarg, ValType::I32) + fn visit_memory_atomic_notify(&mut self, memarg: MemArg) -> Self::Output { + self.check_atomic_binary_op(memarg, ValType::I32) } - fn visit_memory_atomic_wait32(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_threads_enabled(offset)?; - let ty = self.check_shared_memarg_wo_align(offset, memarg)?; - self.pop_operand(offset, Some(ValType::I64))?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; + fn visit_memory_atomic_wait32(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_shared_memarg(memarg)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_memory_atomic_wait64(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_threads_enabled(offset)?; - let ty = self.check_shared_memarg_wo_align(offset, memarg)?; - self.pop_operand(offset, Some(ValType::I64))?; - self.pop_operand(offset, Some(ValType::I64))?; - self.pop_operand(offset, Some(ty))?; + fn visit_memory_atomic_wait64(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_shared_memarg(memarg)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_atomic_fence(&mut self, offset: usize, flags: u8) -> Self::Output { - self.check_threads_enabled(offset)?; - if flags != 0 { - bail!(offset, "non-zero flags for fence not supported yet"); - } + fn visit_atomic_fence(&mut self) -> Self::Output { Ok(()) } - fn visit_ref_null(&mut self, offset: usize, ty: ValType) -> Self::Output { - self.check_reference_types_enabled(offset)?; - self.features - .check_value_type(ty) - .map_err(|e| BinaryReaderError::new(e, offset))?; - if !ty.is_reference_type() { - bail!(offset, "invalid non-reference type in ref.null"); + fn visit_ref_null(&mut self, heap_type: HeapType) -> Self::Output { + self.resources + .check_heap_type(heap_type, &self.features, self.offset)?; + self.push_operand(ValType::Ref( + RefType::new(true, heap_type).expect("existing heap types should be within our limits"), + ))?; + Ok(()) + } + + fn visit_ref_as_non_null(&mut self) -> Self::Output { + let ty = match self.pop_ref()? { + Some(ty) => MaybeType::Type(ValType::Ref(ty.as_non_null())), + None => MaybeType::HeapBot, + }; + self.push_operand(ty)?; + Ok(()) + } + fn visit_br_on_null(&mut self, relative_depth: u32) -> Self::Output { + let ty = match self.pop_ref()? { + None => MaybeType::HeapBot, + Some(ty) => MaybeType::Type(ValType::Ref(ty.as_non_null())), + }; + let (ft, kind) = self.jump(relative_depth)?; + for ty in self.label_types(ft, kind)?.rev() { + self.pop_operand(Some(ty))?; + } + for ty in self.label_types(ft, kind)? { + self.push_operand(ty)?; } self.push_operand(ty)?; Ok(()) } - fn visit_ref_is_null(&mut self, offset: usize) -> Self::Output { - self.check_reference_types_enabled(offset)?; - match self.pop_operand(offset, None)? { - None => {} - Some(t) => { - if !t.is_reference_type() { + fn visit_br_on_non_null(&mut self, relative_depth: u32) -> Self::Output { + let ty = self.pop_ref()?; + let (ft, kind) = self.jump(relative_depth)?; + let mut lts = self.label_types(ft, kind)?; + match (lts.next_back(), ty) { + (None, _) => bail!( + self.offset, + "type mismatch: br_on_non_null target has no label types", + ), + (Some(ValType::Ref(_)), None) => {} + (Some(rt1 @ ValType::Ref(_)), Some(rt0)) => { + // Switch rt0, our popped type, to a non-nullable type and + // perform the match because if the branch is taken it's a + // non-null value. + let ty = rt0.as_non_null(); + if !self.resources.matches(ty.into(), rt1) { bail!( - offset, - "type mismatch: invalid reference type in ref.is_null" - ); + self.offset, + "type mismatch: expected {} but found {}", + ty_to_str(rt0.into()), + ty_to_str(rt1) + ) } } + (Some(_), _) => bail!( + self.offset, + "type mismatch: br_on_non_null target does not end with heap type", + ), + } + for ty in self.label_types(ft, kind)?.rev().skip(1) { + self.pop_operand(Some(ty))?; } + for ty in lts { + self.push_operand(ty)?; + } + Ok(()) + } + fn visit_ref_is_null(&mut self) -> Self::Output { + self.pop_ref()?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_ref_func(&mut self, offset: usize, function_index: u32) -> Self::Output { - self.check_reference_types_enabled(offset)?; - if self.resources.type_of_function(function_index).is_none() { - bail!( - offset, + fn visit_ref_func(&mut self, function_index: u32) -> Self::Output { + let type_index = match self.resources.type_index_of_function(function_index) { + Some(idx) => idx, + None => bail!( + self.offset, "unknown function {}: function index out of bounds", function_index, - ); - } + ), + }; if !self.resources.is_function_referenced(function_index) { - bail!(offset, "undeclared function reference"); + bail!(self.offset, "undeclared function reference"); + } + + // FIXME(#924) this should not be conditional based on enabled + // proposals. + if self.features.function_references { + self.push_operand( + RefType::indexed_func(false, type_index) + .expect("our limits on number of types should fit into ref type"), + )?; + } else { + self.push_operand(ValType::FUNCREF)?; } - self.push_operand(ValType::FuncRef)?; Ok(()) } - fn visit_v128_load(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_simd_enabled(offset)?; - let ty = self.check_memarg(memarg, 4, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_v128_load(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_store(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_simd_enabled(offset)?; - let ty = self.check_memarg(memarg, 4, offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ty))?; + fn visit_v128_store(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_v128_const(&mut self, offset: usize, _value: V128) -> Self::Output { - self.check_simd_enabled(offset)?; + fn visit_v128_const(&mut self, _value: V128) -> Self::Output { self.push_operand(ValType::V128)?; Ok(()) } - fn visit_i8x16_splat(&mut self, offset: usize) -> Self::Output { - self.check_v128_splat(offset, ValType::I32) + fn visit_i8x16_splat(&mut self) -> Self::Output { + self.check_v128_splat(ValType::I32) } - fn visit_i16x8_splat(&mut self, offset: usize) -> Self::Output { - self.check_v128_splat(offset, ValType::I32) + fn visit_i16x8_splat(&mut self) -> Self::Output { + self.check_v128_splat(ValType::I32) } - fn visit_i32x4_splat(&mut self, offset: usize) -> Self::Output { - self.check_v128_splat(offset, ValType::I32) + fn visit_i32x4_splat(&mut self) -> Self::Output { + self.check_v128_splat(ValType::I32) } - fn visit_i64x2_splat(&mut self, offset: usize) -> Self::Output { - self.check_v128_splat(offset, ValType::I64) + fn visit_i64x2_splat(&mut self) -> Self::Output { + self.check_v128_splat(ValType::I64) } - fn visit_f32x4_splat(&mut self, offset: usize) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - self.check_v128_splat(offset, ValType::F32) + fn visit_f32x4_splat(&mut self) -> Self::Output { + self.check_floats_enabled()?; + self.check_v128_splat(ValType::F32) } - fn visit_f64x2_splat(&mut self, offset: usize) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - self.check_v128_splat(offset, ValType::F64) + fn visit_f64x2_splat(&mut self) -> Self::Output { + self.check_floats_enabled()?; + self.check_v128_splat(ValType::F64) } - fn visit_i8x16_extract_lane_s(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 16)?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i8x16_extract_lane_s(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 16)?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i8x16_extract_lane_u(&mut self, input: usize, lane: u8) -> Self::Output { - self.visit_i8x16_extract_lane_s(input, lane) + fn visit_i8x16_extract_lane_u(&mut self, lane: u8) -> Self::Output { + self.visit_i8x16_extract_lane_s(lane) } - fn visit_i16x8_extract_lane_s(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 8)?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i16x8_extract_lane_s(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 8)?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i16x8_extract_lane_u(&mut self, input: usize, lane: u8) -> Self::Output { - self.visit_i16x8_extract_lane_s(input, lane) + fn visit_i16x8_extract_lane_u(&mut self, lane: u8) -> Self::Output { + self.visit_i16x8_extract_lane_s(lane) } - fn visit_i32x4_extract_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 4)?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i32x4_extract_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_i8x16_replace_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 16)?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i8x16_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 16)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_i16x8_replace_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 8)?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i16x8_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 8)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_i32x4_replace_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 4)?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i32x4_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_i64x2_extract_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 2)?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i64x2_extract_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::I64)?; Ok(()) } - fn visit_i64x2_replace_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 2)?; - self.pop_operand(offset, Some(ValType::I64))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i64x2_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_f32x4_extract_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 4)?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_f32x4_extract_lane(&mut self, lane: u8) -> Self::Output { + self.check_floats_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::F32)?; Ok(()) } - fn visit_f32x4_replace_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 4)?; - self.pop_operand(offset, Some(ValType::F32))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_f32x4_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_floats_enabled()?; + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::F32))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_f64x2_extract_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 2)?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_f64x2_extract_lane(&mut self, lane: u8) -> Self::Output { + self.check_floats_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::F64)?; Ok(()) } - fn visit_f64x2_replace_lane(&mut self, offset: usize, lane: u8) -> Self::Output { - self.check_non_deterministic_enabled(offset)?; - self.check_simd_enabled(offset)?; - self.check_simd_lane_index(offset, lane, 2)?; - self.pop_operand(offset, Some(ValType::F64))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_f64x2_replace_lane(&mut self, lane: u8) -> Self::Output { + self.check_floats_enabled()?; + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::F64))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_f32x4_eq(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_eq(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_ne(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_ne(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_lt(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_lt(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_gt(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_gt(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_le(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_le(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_ge(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_ge(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_eq(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_eq(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_ne(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_ne(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_lt(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_lt(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_gt(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_gt(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_le(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_le(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_ge(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_ge(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_add(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_add(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_sub(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_sub(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_mul(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_mul(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_div(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_div(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_min(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_min(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_max(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_max(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_pmin(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_pmin(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_pmax(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f32x4_pmax(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_add(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_add(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_sub(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_sub(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_mul(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_mul(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_div(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_div(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_min(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_min(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_max(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_max(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_pmin(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_pmin(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f64x2_pmax(&mut self, offset: usize) -> Self::Output { - self.check_v128_fbinary_op(offset) + fn visit_f64x2_pmax(&mut self) -> Self::Output { + self.check_v128_fbinary_op() } - fn visit_f32x4_relaxed_min(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_binary_op(offset) + fn visit_i8x16_eq(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_f32x4_relaxed_max(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_binary_op(offset) + fn visit_i8x16_ne(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_f64x2_relaxed_min(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_binary_op(offset) + fn visit_i8x16_lt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_f64x2_relaxed_max(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_binary_op(offset) + fn visit_i8x16_lt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_eq(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_gt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_ne(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_gt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_lt_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_le_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_lt_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_le_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_gt_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_ge_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_gt_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_ge_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_le_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_eq(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_le_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_ne(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_ge_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_lt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_ge_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_lt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_eq(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_gt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_ne(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_gt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_lt_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_le_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_lt_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_le_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_gt_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_ge_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_gt_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_ge_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_le_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_eq(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_le_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_ne(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_ge_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_lt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_ge_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_lt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_eq(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_gt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_ne(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_gt_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_lt_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_le_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_lt_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_le_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_gt_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_ge_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_gt_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_ge_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_le_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_eq(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_le_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_ne(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_ge_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_lt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_ge_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_gt_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_eq(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_le_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_ne(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_ge_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_lt_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_v128_and(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_gt_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_v128_andnot(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_le_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_v128_or(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_ge_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_v128_xor(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_v128_and(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_add(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_v128_andnot(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_add_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_v128_or(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_add_sat_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_v128_xor(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_sub(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_add(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_sub_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_add_sat_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_sub_sat_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_add_sat_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_min_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_sub(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_min_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_sub_sat_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_max_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_sub_sat_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_max_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_min_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_add(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_min_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_add_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_max_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_add_sat_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_max_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_sub(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_add(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_sub_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_add_sat_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_sub_sat_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_add_sat_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_mul(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_sub(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_min_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_sub_sat_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_min_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_sub_sat_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_max_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_mul(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_max_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_min_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_add(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_min_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_sub(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_max_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_mul(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_max_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_min_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_add(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_min_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_sub(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_max_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_mul(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_max_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_min_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_dot_i16x8_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_min_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_add(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_max_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_sub(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_max_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_mul(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_dot_i16x8_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_avgr_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_add(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_avgr_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_sub(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_narrow_i16x8_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_mul(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i8x16_narrow_i16x8_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_avgr_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_narrow_i32x4_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_avgr_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_narrow_i32x4_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_narrow_i16x8_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_extmul_low_i8x16_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_narrow_i16x8_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_extmul_high_i8x16_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_narrow_i32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_extmul_low_i8x16_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_narrow_i32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_extmul_high_i8x16_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_extmul_low_i8x16_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_extmul_low_i16x8_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_extmul_high_i8x16_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_extmul_high_i16x8_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_extmul_low_i8x16_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_extmul_low_i16x8_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_extmul_high_i8x16_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i32x4_extmul_high_i16x8_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_extmul_low_i16x8_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_extmul_low_i32x4_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_extmul_high_i16x8_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_extmul_high_i32x4_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_extmul_low_i16x8_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_extmul_low_i32x4_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_extmul_high_i16x8_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i64x2_extmul_high_i32x4_u(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_extmul_low_i32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_i16x8_q15mulr_sat_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_extmul_high_i32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_f32x4_ceil(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_i64x2_extmul_low_i32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_f32x4_floor(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_i64x2_extmul_high_i32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_f32x4_trunc(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_i16x8_q15mulr_sat_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_binary_op(offset) + fn visit_f32x4_nearest(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f32x4_ceil(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_ceil(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f32x4_floor(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_floor(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f32x4_trunc(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_trunc(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f32x4_nearest(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_nearest(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_ceil(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f32x4_abs(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_floor(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f32x4_neg(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_trunc(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f32x4_sqrt(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_nearest(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_abs(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f32x4_abs(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_neg(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f32x4_neg(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_sqrt(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f32x4_sqrt(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f32x4_demote_f64x2_zero(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_abs(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_promote_low_f32x4(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_neg(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_convert_low_i32x4_s(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_sqrt(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f64x2_convert_low_i32x4_u(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f32x4_demote_f64x2_zero(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_i32x4_trunc_sat_f32x4_s(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_promote_low_f32x4(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_i32x4_trunc_sat_f32x4_u(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_convert_low_i32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_f64x2_convert_low_i32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_i32x4_trunc_sat_f32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f32x4_convert_i32x4_s(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_i32x4_trunc_sat_f32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_f32x4_convert_i32x4_u(&mut self) -> Self::Output { + self.check_v128_funary_op() } - fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_v128_not(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_i8x16_abs(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_f32x4_convert_i32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_i8x16_neg(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_f32x4_convert_i32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_funary_op(offset) + fn visit_i8x16_popcnt(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_v128_not(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i16x8_abs(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i8x16_abs(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i16x8_neg(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i8x16_neg(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_abs(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i8x16_popcnt(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_neg(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i16x8_abs(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i64x2_abs(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i16x8_neg(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i64x2_neg(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_abs(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i16x8_extend_low_i8x16_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_neg(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i16x8_extend_high_i8x16_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i64x2_abs(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i16x8_extend_low_i8x16_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i64x2_neg(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i16x8_extend_high_i8x16_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i16x8_extend_low_i8x16_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_extend_low_i16x8_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i16x8_extend_high_i8x16_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_extend_high_i16x8_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i16x8_extend_low_i8x16_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_extend_low_i16x8_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i16x8_extend_high_i8x16_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_extend_high_i16x8_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_extend_low_i16x8_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i64x2_extend_low_i32x4_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_extend_high_i16x8_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i64x2_extend_high_i32x4_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_extend_low_i16x8_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i64x2_extend_low_i32x4_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_extend_high_i16x8_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i64x2_extend_high_i32x4_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i64x2_extend_low_i32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i64x2_extend_high_i32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i64x2_extend_low_i32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i64x2_extend_high_i32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_v128_bitselect(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) } - fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i8x16_relaxed_swizzle(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; + Ok(()) } - fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_relaxed_trunc_f32x4_s(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_unary_op(offset) + fn visit_i32x4_relaxed_trunc_f32x4_u(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_relaxed_trunc_sat_f32x4_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_unary_op(offset) + fn visit_i32x4_relaxed_trunc_f64x2_s_zero(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_relaxed_trunc_sat_f32x4_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_unary_op(offset) + fn visit_i32x4_relaxed_trunc_f64x2_u_zero(&mut self) -> Self::Output { + self.check_v128_unary_op() } - fn visit_i32x4_relaxed_trunc_sat_f64x2_s_zero(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_unary_op(offset) + fn visit_f32x4_relaxed_madd(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_i32x4_relaxed_trunc_sat_f64x2_u_zero(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_unary_op(offset) + fn visit_f32x4_relaxed_nmadd(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_v128_bitselect(&mut self, offset: usize) -> Self::Output { - self.check_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) + fn visit_f64x2_relaxed_madd(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_f32x4_fma(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_ternary_op(offset) + fn visit_f64x2_relaxed_nmadd(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_f32x4_fms(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_ternary_op(offset) + fn visit_i8x16_relaxed_laneselect(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_f64x2_fma(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_ternary_op(offset) + fn visit_i16x8_relaxed_laneselect(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_f64x2_fms(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_ternary_op(offset) + fn visit_i32x4_relaxed_laneselect(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_i8x16_laneselect(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_ternary_op(offset) + fn visit_i64x2_relaxed_laneselect(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_i16x8_laneselect(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_ternary_op(offset) + fn visit_f32x4_relaxed_min(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i32x4_laneselect(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_ternary_op(offset) + fn visit_f32x4_relaxed_max(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i64x2_laneselect(&mut self, offset: usize) -> Self::Output { - self.check_v128_relaxed_ternary_op(offset) + fn visit_f64x2_relaxed_min(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_v128_any_true(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_f64x2_relaxed_max(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_all_true(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_i16x8_relaxed_q15mulr_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i8x16_bitmask(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_i16x8_relaxed_dot_i8x16_i7x16_s(&mut self) -> Self::Output { + self.check_v128_binary_op() } - fn visit_i16x8_all_true(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(&mut self) -> Self::Output { + self.check_v128_ternary_op() } - fn visit_i16x8_bitmask(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_v128_any_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i32x4_all_true(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_i8x16_all_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i32x4_bitmask(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_i8x16_bitmask(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i64x2_all_true(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_i16x8_all_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i64x2_bitmask(&mut self, offset: usize) -> Self::Output { - self.check_v128_bitmask_op(offset) + fn visit_i16x8_bitmask(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i8x16_shl(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i32x4_all_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i8x16_shr_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i32x4_bitmask(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i8x16_shr_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i64x2_all_true(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i16x8_shl(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i64x2_bitmask(&mut self) -> Self::Output { + self.check_v128_bitmask_op() } - fn visit_i16x8_shr_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i8x16_shl(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i16x8_shr_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i8x16_shr_s(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i32x4_shl(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i8x16_shr_u(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i32x4_shr_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i16x8_shl(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i32x4_shr_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i16x8_shr_s(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i64x2_shl(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i16x8_shr_u(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i64x2_shr_s(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i32x4_shl(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i64x2_shr_u(&mut self, offset: usize) -> Self::Output { - self.check_v128_shift_op(offset) + fn visit_i32x4_shr_s(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i8x16_swizzle(&mut self, offset: usize) -> Self::Output { - self.check_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; - self.push_operand(ValType::V128)?; - Ok(()) + fn visit_i32x4_shr_u(&mut self) -> Self::Output { + self.check_v128_shift_op() } - fn visit_i8x16_relaxed_swizzle(&mut self, offset: usize) -> Self::Output { - self.check_relaxed_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i64x2_shl(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i64x2_shr_s(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i64x2_shr_u(&mut self) -> Self::Output { + self.check_v128_shift_op() + } + fn visit_i8x16_swizzle(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_i8x16_shuffle(&mut self, offset: usize, lanes: [u8; 16]) -> Self::Output { - self.check_simd_enabled(offset)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(ValType::V128))?; + fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output { + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; for i in lanes { - self.check_simd_lane_index(offset, i, 32)?; + self.check_simd_lane_index(i, 32)?; } self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_load8_splat(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_simd_enabled(offset)?; - let ty = self.check_memarg(memarg, 0, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_v128_load8_splat(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_load16_splat(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_simd_enabled(offset)?; - let ty = self.check_memarg(memarg, 1, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_v128_load16_splat(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_load32_splat(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_simd_enabled(offset)?; - let ty = self.check_memarg(memarg, 2, offset)?; - self.pop_operand(offset, Some(ty))?; + fn visit_v128_load32_splat(&mut self, memarg: MemArg) -> Self::Output { + let ty = self.check_memarg(memarg)?; + self.pop_operand(Some(ty))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_load32_zero(&mut self, input: usize, memarg: MemArg) -> Self::Output { - self.visit_v128_load32_splat(input, memarg) + fn visit_v128_load32_zero(&mut self, memarg: MemArg) -> Self::Output { + self.visit_v128_load32_splat(memarg) } - fn visit_v128_load64_splat(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(offset, memarg) + fn visit_v128_load64_splat(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) } - fn visit_v128_load64_zero(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(offset, memarg) + fn visit_v128_load64_zero(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) } - fn visit_v128_load8x8_s(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(offset, memarg) + fn visit_v128_load8x8_s(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) } - fn visit_v128_load8x8_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(offset, memarg) + fn visit_v128_load8x8_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) } - fn visit_v128_load16x4_s(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(offset, memarg) + fn visit_v128_load16x4_s(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) } - fn visit_v128_load16x4_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(offset, memarg) + fn visit_v128_load16x4_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) } - fn visit_v128_load32x2_s(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(offset, memarg) + fn visit_v128_load32x2_s(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) } - fn visit_v128_load32x2_u(&mut self, offset: usize, memarg: MemArg) -> Self::Output { - self.check_v128_load_op(offset, memarg) + fn visit_v128_load32x2_u(&mut self, memarg: MemArg) -> Self::Output { + self.check_v128_load_op(memarg) } - fn visit_v128_load8_lane(&mut self, offset: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 0, offset)?; - self.check_simd_lane_index(offset, lane, 16)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(idx))?; + fn visit_v128_load8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 16)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_load16_lane(&mut self, offset: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 1, offset)?; - self.check_simd_lane_index(offset, lane, 8)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(idx))?; + fn visit_v128_load16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 8)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_load32_lane(&mut self, offset: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 2, offset)?; - self.check_simd_lane_index(offset, lane, 4)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(idx))?; + fn visit_v128_load32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_load64_lane(&mut self, offset: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 3, offset)?; - self.check_simd_lane_index(offset, lane, 2)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(idx))?; + fn visit_v128_load64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; self.push_operand(ValType::V128)?; Ok(()) } - fn visit_v128_store8_lane(&mut self, offset: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 0, offset)?; - self.check_simd_lane_index(offset, lane, 16)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(idx))?; + fn visit_v128_store8_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 16)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; Ok(()) } - fn visit_v128_store16_lane(&mut self, offset: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 1, offset)?; - self.check_simd_lane_index(offset, lane, 8)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(idx))?; + fn visit_v128_store16_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 8)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; Ok(()) } - fn visit_v128_store32_lane(&mut self, offset: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 2, offset)?; - self.check_simd_lane_index(offset, lane, 4)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(idx))?; + fn visit_v128_store32_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 4)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; Ok(()) } - fn visit_v128_store64_lane(&mut self, offset: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.check_simd_enabled(offset)?; - let idx = self.check_memarg(memarg, 3, offset)?; - self.check_simd_lane_index(offset, lane, 2)?; - self.pop_operand(offset, Some(ValType::V128))?; - self.pop_operand(offset, Some(idx))?; + fn visit_v128_store64_lane(&mut self, memarg: MemArg, lane: u8) -> Self::Output { + let idx = self.check_memarg(memarg)?; + self.check_simd_lane_index(lane, 2)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(idx))?; Ok(()) } - fn visit_memory_init(&mut self, offset: usize, segment: u32, mem: u32) -> Self::Output { - self.check_bulk_memory_enabled(offset)?; - let ty = self.check_memory_index(offset, mem)?; + fn visit_memory_init(&mut self, segment: u32, mem: u32) -> Self::Output { + let ty = self.check_memory_index(mem)?; match self.resources.data_count() { - None => bail!(offset, "data count section required"), + None => bail!(self.offset, "data count section required"), Some(count) if segment < count => {} - Some(_) => bail!(offset, "unknown data segment {}", segment), + Some(_) => bail!(self.offset, "unknown data segment {}", segment), } - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_data_drop(&mut self, offset: usize, segment: u32) -> Self::Output { - self.check_bulk_memory_enabled(offset)?; + fn visit_data_drop(&mut self, segment: u32) -> Self::Output { match self.resources.data_count() { - None => bail!(offset, "data count section required"), + None => bail!(self.offset, "data count section required"), Some(count) if segment < count => {} - Some(_) => bail!(offset, "unknown data segment {}", segment), + Some(_) => bail!(self.offset, "unknown data segment {}", segment), } Ok(()) } - fn visit_memory_copy(&mut self, offset: usize, dst: u32, src: u32) -> Self::Output { - self.check_bulk_memory_enabled(offset)?; - let dst_ty = self.check_memory_index(offset, dst)?; - let src_ty = self.check_memory_index(offset, src)?; + fn visit_memory_copy(&mut self, dst: u32, src: u32) -> Self::Output { + let dst_ty = self.check_memory_index(dst)?; + let src_ty = self.check_memory_index(src)?; // The length operand here is the smaller of src/dst, which is // i32 if one is i32 - self.pop_operand( - offset, - Some(match src_ty { - ValType::I32 => ValType::I32, - _ => dst_ty, - }), - )?; + self.pop_operand(Some(match src_ty { + ValType::I32 => ValType::I32, + _ => dst_ty, + }))?; // ... and the offset into each memory is required to be // whatever the indexing type is for that memory - self.pop_operand(offset, Some(src_ty))?; - self.pop_operand(offset, Some(dst_ty))?; + self.pop_operand(Some(src_ty))?; + self.pop_operand(Some(dst_ty))?; Ok(()) } - fn visit_memory_fill(&mut self, offset: usize, mem: u32) -> Self::Output { - self.check_bulk_memory_enabled(offset)?; - let ty = self.check_memory_index(offset, mem)?; - self.pop_operand(offset, Some(ty))?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; + fn visit_memory_fill(&mut self, mem: u32) -> Self::Output { + let ty = self.check_memory_index(mem)?; + self.pop_operand(Some(ty))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ty))?; Ok(()) } - fn visit_table_init(&mut self, offset: usize, segment: u32, table: u32) -> Self::Output { - self.check_bulk_memory_enabled(offset)?; - if table > 0 { - self.check_reference_types_enabled(offset)?; - } + fn visit_memory_discard(&mut self, mem: u32) -> Self::Output { + let ty = self.check_memory_index(mem)?; + self.pop_operand(Some(ty))?; + self.pop_operand(Some(ty))?; + Ok(()) + } + fn visit_table_init(&mut self, segment: u32, table: u32) -> Self::Output { + if table > 0 {} let table = match self.resources.table_at(table) { Some(table) => table, - None => bail!(offset, "unknown table {}: table index out of bounds", table), + None => bail!( + self.offset, + "unknown table {}: table index out of bounds", + table + ), }; let segment_ty = match self.resources.element_type_at(segment) { Some(ty) => ty, None => bail!( - offset, + self.offset, "unknown elem segment {}: segment index out of bounds", segment ), }; - if segment_ty != table.element_type { - bail!(offset, "type mismatch"); + if !self + .resources + .matches(ValType::Ref(segment_ty), ValType::Ref(table.element_type)) + { + bail!(self.offset, "type mismatch"); } - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; Ok(()) } - fn visit_elem_drop(&mut self, offset: usize, segment: u32) -> Self::Output { - self.check_bulk_memory_enabled(offset)?; + fn visit_elem_drop(&mut self, segment: u32) -> Self::Output { if segment >= self.resources.element_count() { bail!( - offset, + self.offset, "unknown elem segment {}: segment index out of bounds", segment ); } Ok(()) } - fn visit_table_copy(&mut self, offset: usize, dst_table: u32, src_table: u32) -> Self::Output { - self.check_bulk_memory_enabled(offset)?; - if src_table > 0 || dst_table > 0 { - self.check_reference_types_enabled(offset)?; - } + fn visit_table_copy(&mut self, dst_table: u32, src_table: u32) -> Self::Output { + if src_table > 0 || dst_table > 0 {} let (src, dst) = match ( self.resources.table_at(src_table), self.resources.table_at(dst_table), ) { (Some(a), Some(b)) => (a, b), - _ => bail!(offset, "table index out of bounds"), + _ => bail!(self.offset, "table index out of bounds"), }; - if src.element_type != dst.element_type { - bail!(offset, "type mismatch"); + if !self.resources.matches( + ValType::Ref(src.element_type), + ValType::Ref(dst.element_type), + ) { + bail!(self.offset, "type mismatch"); } - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; Ok(()) } - fn visit_table_get(&mut self, offset: usize, table: u32) -> Self::Output { - self.check_reference_types_enabled(offset)?; + fn visit_table_get(&mut self, table: u32) -> Self::Output { let ty = match self.resources.table_at(table) { Some(ty) => ty.element_type, - None => bail!(offset, "table index out of bounds"), + None => bail!(self.offset, "table index out of bounds"), }; - self.pop_operand(offset, Some(ValType::I32))?; - self.push_operand(ty)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::Ref(ty))?; Ok(()) } - fn visit_table_set(&mut self, offset: usize, table: u32) -> Self::Output { - self.check_reference_types_enabled(offset)?; + fn visit_table_set(&mut self, table: u32) -> Self::Output { let ty = match self.resources.table_at(table) { Some(ty) => ty.element_type, - None => bail!(offset, "table index out of bounds"), + None => bail!(self.offset, "table index out of bounds"), }; - self.pop_operand(offset, Some(ty))?; - self.pop_operand(offset, Some(ValType::I32))?; + self.pop_operand(Some(ValType::Ref(ty)))?; + self.pop_operand(Some(ValType::I32))?; Ok(()) } - fn visit_table_grow(&mut self, offset: usize, table: u32) -> Self::Output { - self.check_reference_types_enabled(offset)?; + fn visit_table_grow(&mut self, table: u32) -> Self::Output { let ty = match self.resources.table_at(table) { Some(ty) => ty.element_type, - None => bail!(offset, "table index out of bounds"), + None => bail!(self.offset, "table index out of bounds"), }; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::Ref(ty)))?; self.push_operand(ValType::I32)?; Ok(()) } - fn visit_table_size(&mut self, offset: usize, table: u32) -> Self::Output { - self.check_reference_types_enabled(offset)?; + fn visit_table_size(&mut self, table: u32) -> Self::Output { if self.resources.table_at(table).is_none() { - bail!(offset, "table index out of bounds"); + bail!(self.offset, "table index out of bounds"); } self.push_operand(ValType::I32)?; Ok(()) } - fn visit_table_fill(&mut self, offset: usize, table: u32) -> Self::Output { - self.check_bulk_memory_enabled(offset)?; + fn visit_table_fill(&mut self, table: u32) -> Self::Output { let ty = match self.resources.table_at(table) { Some(ty) => ty.element_type, - None => bail!(offset, "table index out of bounds"), + None => bail!(self.offset, "table index out of bounds"), }; - self.pop_operand(offset, Some(ValType::I32))?; - self.pop_operand(offset, Some(ty))?; - self.pop_operand(offset, Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::Ref(ty)))?; + self.pop_operand(Some(ValType::I32))?; Ok(()) } + fn visit_ref_i31(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::Ref(RefType::I31)) + } + fn visit_i31_get_s(&mut self) -> Self::Output { + match self.pop_ref()? { + Some(ref_type) => match ref_type.heap_type() { + HeapType::I31 => self.push_operand(ValType::I32), + _ => bail!(self.offset, "ref heap type mismatch: expected i31"), + }, + _ => bail!(self.offset, "type mismatch: expected (ref null? i31)"), + } + } + fn visit_i31_get_u(&mut self) -> Self::Output { + match self.pop_ref()? { + Some(ref_type) => match ref_type.heap_type() { + HeapType::I31 => self.push_operand(ValType::I32), + _ => bail!(self.offset, "ref heap type mismatch: expected i31"), + }, + _ => bail!(self.offset, "type mismatch: expected (ref null? i31)"), + } + } } #[derive(Clone)] diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs index fe89acd87d..83537bb2fc 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -1,16 +1,25 @@ //! Types relating to type information provided by validation. -use super::{component::ComponentState, core::Module}; +use super::{ + component::{ComponentState, ExternKind}, + core::Module, +}; +use crate::validator::names::KebabString; use crate::{ - ComponentExport, ComponentExternalKind, ComponentImport, ComponentTypeRef, Export, - ExternalKind, FuncType, GlobalType, Import, MemoryType, PrimitiveValType, TableType, TypeRef, + ArrayType, BinaryReaderError, Export, ExternalKind, FuncType, GlobalType, Import, MemoryType, + PrimitiveValType, RefType, Result, StructType, StructuralType, SubType, TableType, TypeRef, ValType, }; use indexmap::{IndexMap, IndexSet}; +use std::collections::HashMap; +use std::collections::HashSet; +use std::ops::Index; +use std::sync::atomic::{AtomicU64, Ordering}; use std::{ borrow::Borrow, hash::{Hash, Hasher}, mem, + ops::{Deref, DerefMut}, sync::Arc, }; @@ -133,37 +142,129 @@ fn push_primitive_wasm_types(ty: &PrimitiveValType, lowered_types: &mut LoweredT /// Represents a unique identifier for a type known to a [`crate::Validator`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[repr(C)] // use fixed field layout to ensure minimal size pub struct TypeId { - /// The effective type size for the type. - /// - /// This is stored as part of the ID to avoid having to recurse through - /// the global type list when calculating type sizes. - pub(crate) type_size: usize, /// The index into the global list of types. - pub(crate) index: usize, + index: u32, + + /// A unique integer assigned to this type. + /// + /// The purpose of this field is to ensure that two different `TypeId` + /// representations can be handed out for two different aliased types within + /// a component that actually point to the same underlying type (as pointed + /// to by the `index` field). + unique_id: u32, +} + +impl TypeId { + pub(crate) fn index(&self) -> usize { + usize::try_from(self.index).unwrap() + } +} + +// The size of `TypeId` was seen to have a large-ish impact in #844, so this +// assert ensures that it stays relatively small. +const _: () = { + assert!(std::mem::size_of::() <= 8); +}; + +/// Metadata about a type and its transitive structure. +/// +/// Currently contains two properties: +/// +/// * The "size" of a type - a proxy to the recursive size of a type if +/// everything in the type were unique (e.g. no shared references). Not an +/// approximation of runtime size, but instead of type-complexity size if +/// someone were to visit each element of the type individually. For example +/// `u32` has size 1 and `(list u32)` has size 2 (roughly). Used to prevent +/// massive trees of types. +/// +/// * Whether or not a type contains a "borrow" transitively inside of it. For +/// example `(borrow $t)` and `(list (borrow $t))` both contain borrows, but +/// `(list u32)` does not. Used to validate that component function results do +/// not contain borrows. +/// +/// Currently this is represented as a compact 32-bit integer to ensure that +/// `TypeId`, which this is stored in, remains relatively small. The maximum +/// type size allowed in wasmparser is 1M at this time which is 20 bits of +/// information, and then one more bit is used for whether or not a borrow is +/// used. Currently this uses the low 24 bits for the type size and the MSB for +/// the borrow bit. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub(crate) struct TypeInfo(u32); + +impl TypeInfo { + /// Creates a new blank set of type information. + /// + /// Defaults to size 1 to ensure that this consumes space in the final type + /// structure. + pub(crate) fn new() -> TypeInfo { + TypeInfo::_new(1, false) + } + + /// Creates a new blank set of information about a leaf "borrow" type which + /// has size 1. + pub(crate) fn borrow() -> TypeInfo { + TypeInfo::_new(1, true) + } + + /// Creates type information corresponding to a core type of the `size` + /// specified, meaning no borrows are contained within. + pub(crate) fn core(size: u32) -> TypeInfo { + TypeInfo::_new(size, false) + } + + fn _new(size: u32, contains_borrow: bool) -> TypeInfo { + assert!(size < (1 << 24)); + TypeInfo(size | ((contains_borrow as u32) << 31)) + } + + /// Combines another set of type information into this one, for example if + /// this is a record which has `other` as a field. + /// + /// Updates the size of `self` and whether or not this type contains a + /// borrow based on whether `other` contains a borrow. + /// + /// Returns an error if the type size would exceed this crate's static limit + /// of a type size. + pub(crate) fn combine(&mut self, other: TypeInfo, offset: usize) -> Result<()> { + *self = TypeInfo::_new( + super::combine_type_sizes(self.size(), other.size(), offset)?, + self.contains_borrow() || other.contains_borrow(), + ); + Ok(()) + } + + pub(crate) fn size(&self) -> u32 { + self.0 & 0xffffff + } + + pub(crate) fn contains_borrow(&self) -> bool { + (self.0 >> 31) != 0 + } } /// A unified type definition for validating WebAssembly modules and components. #[derive(Debug)] pub enum Type { - /// The definition is for a core function type. - Func(FuncType), + /// The definition is for a sub type. + Sub(SubType), /// The definition is for a core module type. /// /// This variant is only supported when parsing a component. - Module(ModuleType), + Module(Box), /// The definition is for a core module instance type. /// /// This variant is only supported when parsing a component. - Instance(InstanceType), + Instance(Box), /// The definition is for a component type. /// /// This variant is only supported when parsing a component. - Component(ComponentType), + Component(Box), /// The definition is for a component instance type. /// /// This variant is only supported when parsing a component. - ComponentInstance(ComponentInstanceType), + ComponentInstance(Box), /// The definition is for a component function type. /// /// This variant is only supported when parsing a component. @@ -172,74 +273,120 @@ pub enum Type { /// /// This variant is only supported when parsing a component. Defined(ComponentDefinedType), + /// This definition is for a resource type in the component model. + /// + /// Each resource is identified by a unique identifier specified here. + Resource(ResourceId), } impl Type { /// Converts the type to a core function type. - pub fn as_func_type(&self) -> Option<&FuncType> { + pub fn unwrap_func(&self) -> &FuncType { + match self { + Type::Sub(SubType { + structural_type: StructuralType::Func(ft), + .. + }) => ft, + _ => panic!("not a function type"), + } + } + + /// Converts the type to an array type. + pub fn unwrap_array(&self) -> &ArrayType { + match self { + Self::Sub(SubType { + structural_type: StructuralType::Array(ty), + .. + }) => ty, + _ => panic!("not an array type"), + } + } + + /// Converts the type to a struct type. + pub fn unwrap_struct(&self) -> &StructType { match self { - Self::Func(ty) => Some(ty), - _ => None, + Self::Sub(SubType { + structural_type: StructuralType::Struct(ty), + .. + }) => ty, + _ => panic!("not a struct type"), } } /// Converts the type to a core module type. - pub fn as_module_type(&self) -> Option<&ModuleType> { + pub fn unwrap_module(&self) -> &ModuleType { match self { - Self::Module(ty) => Some(ty), - _ => None, + Self::Module(ty) => ty, + _ => panic!("not a module type"), } } /// Converts the type to a core module instance type. - pub fn as_instance_type(&self) -> Option<&InstanceType> { + pub fn unwrap_instance(&self) -> &InstanceType { match self { - Self::Instance(ty) => Some(ty), - _ => None, + Self::Instance(ty) => ty, + _ => panic!("not an instance type"), } } /// Converts the type to a component type. - pub fn as_component_type(&self) -> Option<&ComponentType> { + pub fn unwrap_component(&self) -> &ComponentType { match self { - Self::Component(ty) => Some(ty), - _ => None, + Self::Component(ty) => ty, + _ => panic!("not a component type"), } } /// Converts the type to a component instance type. - pub fn as_component_instance_type(&self) -> Option<&ComponentInstanceType> { + pub fn unwrap_component_instance(&self) -> &ComponentInstanceType { match self { - Self::ComponentInstance(ty) => Some(ty), - _ => None, + Self::ComponentInstance(ty) => ty, + _ => panic!("not a component instance type"), } } /// Converts the type to a component function type. - pub fn as_component_func_type(&self) -> Option<&ComponentFuncType> { + pub fn unwrap_component_func(&self) -> &ComponentFuncType { match self { - Self::ComponentFunc(ty) => Some(ty), - _ => None, + Self::ComponentFunc(ty) => ty, + _ => panic!("not a component function type"), } } /// Converts the type to a component defined type. - pub fn as_defined_type(&self) -> Option<&ComponentDefinedType> { + pub fn unwrap_defined(&self) -> &ComponentDefinedType { + match self { + Self::Defined(ty) => ty, + _ => panic!("not a defined type"), + } + } + + /// Converts this type to a resource type, returning the corresponding id. + pub fn unwrap_resource(&self) -> ResourceId { match self { - Self::Defined(ty) => Some(ty), - _ => None, + Self::Resource(id) => *id, + _ => panic!("not a resource type"), } } - pub(crate) fn type_size(&self) -> usize { + pub(crate) fn calculate_info(&self, types: &TypeList) -> TypeInfo { + // TODO(#1036): calculate actual size for func, array, struct match self { - Self::Func(ty) => 1 + ty.params().len() + ty.results().len(), - Self::Module(ty) => ty.type_size, - Self::Instance(ty) => ty.type_size, - Self::Component(ty) => ty.type_size, - Self::ComponentInstance(ty) => ty.type_size, - Self::ComponentFunc(ty) => ty.type_size, - Self::Defined(ty) => ty.type_size(), + Self::Sub(ty) => { + let size = 1 + match ty.clone().structural_type { + StructuralType::Func(ty) => 1 + (ty.params().len() + ty.results().len()) as u32, + StructuralType::Array(_) => 2, + StructuralType::Struct(ty) => 1 + 2 * ty.fields.len() as u32, + }; + TypeInfo::core(size) + } + Self::Module(ty) => ty.info, + Self::Instance(ty) => ty.info, + Self::Component(ty) => ty.info, + Self::ComponentInstance(ty) => ty.info, + Self::ComponentFunc(ty) => ty.info, + Self::Defined(ty) => ty.info(types), + Self::Resource(_) => TypeInfo::new(), } } } @@ -254,58 +401,10 @@ pub enum ComponentValType { } impl ComponentValType { - pub(crate) fn requires_realloc(&self, types: &TypeList) -> bool { - match self { - ComponentValType::Primitive(ty) => ty.requires_realloc(), - ComponentValType::Type(ty) => types[*ty] - .as_defined_type() - .unwrap() - .requires_realloc(types), - } - } - - pub(crate) fn is_optional(&self, types: &TypeList) -> bool { + pub(crate) fn contains_ptr(&self, types: &TypeList) -> bool { match self { - ComponentValType::Primitive(_) => false, - ComponentValType::Type(ty) => { - matches!( - types[*ty].as_defined_type().unwrap(), - ComponentDefinedType::Option(_) - ) - } - } - } - - /// Determines if component value type `a` is a subtype of `b`. - pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { - Self::internal_is_subtype_of(a, at.list, b, bt.list) - } - - pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { - match (a, b) { - (ComponentValType::Primitive(a), ComponentValType::Primitive(b)) => { - PrimitiveValType::is_subtype_of(*a, *b) - } - (ComponentValType::Type(a), ComponentValType::Type(b)) => { - ComponentDefinedType::internal_is_subtype_of( - at[*a].as_defined_type().unwrap(), - at, - bt[*b].as_defined_type().unwrap(), - bt, - ) - } - (ComponentValType::Primitive(a), ComponentValType::Type(b)) => { - match bt[*b].as_defined_type().unwrap() { - ComponentDefinedType::Primitive(b) => PrimitiveValType::is_subtype_of(*a, *b), - _ => false, - } - } - (ComponentValType::Type(a), ComponentValType::Primitive(b)) => { - match at[*a].as_defined_type().unwrap() { - ComponentDefinedType::Primitive(a) => PrimitiveValType::is_subtype_of(*a, *b), - _ => false, - } - } + ComponentValType::Primitive(ty) => ty.contains_ptr(), + ComponentValType::Type(ty) => types[*ty].unwrap_defined().contains_ptr(types), } } @@ -313,16 +412,15 @@ impl ComponentValType { match self { Self::Primitive(ty) => push_primitive_wasm_types(ty, lowered_types), Self::Type(id) => types[*id] - .as_defined_type() - .unwrap() + .unwrap_defined() .push_wasm_types(types, lowered_types), } } - pub(crate) fn type_size(&self) -> usize { + pub(crate) fn info(&self, types: &TypeList) -> TypeInfo { match self { - Self::Primitive(_) => 1, - Self::Type(id) => id.type_size, + Self::Primitive(_) => TypeInfo::new(), + Self::Type(id) => types.info(*id), } } } @@ -343,48 +441,9 @@ pub enum EntityType { } impl EntityType { - /// Determines if entity type `a` is a subtype of `b`. - pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { - Self::internal_is_subtype_of(a, at.list, b, bt.list) - } - - pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { - macro_rules! limits_match { - ($a:expr, $b:expr) => {{ - let a = $a; - let b = $b; - a.initial >= b.initial - && match b.maximum { - Some(b_max) => match a.maximum { - Some(a_max) => a_max <= b_max, - None => false, - }, - None => true, - } - }}; - } - - match (a, b) { - (EntityType::Func(a), EntityType::Func(b)) => { - at[*a].as_func_type().unwrap() == bt[*b].as_func_type().unwrap() - } - (EntityType::Table(a), EntityType::Table(b)) => { - a.element_type == b.element_type && limits_match!(a, b) - } - (EntityType::Memory(a), EntityType::Memory(b)) => { - a.shared == b.shared && a.memory64 == b.memory64 && limits_match!(a, b) - } - (EntityType::Global(a), EntityType::Global(b)) => a == b, - (EntityType::Tag(a), EntityType::Tag(b)) => { - at[*a].as_func_type().unwrap() == bt[*b].as_func_type().unwrap() - } - _ => false, - } - } - pub(crate) fn desc(&self) -> &'static str { match self { - Self::Func(_) => "function", + Self::Func(_) => "func", Self::Table(_) => "table", Self::Memory(_) => "memory", Self::Global(_) => "global", @@ -392,10 +451,10 @@ impl EntityType { } } - pub(crate) fn type_size(&self) -> usize { + pub(crate) fn info(&self, types: &TypeList) -> TypeInfo { match self { - Self::Func(id) | Self::Tag(id) => id.type_size, - Self::Table(_) | Self::Memory(_) | Self::Global(_) => 1, + Self::Func(id) | Self::Tag(id) => types.info(*id), + Self::Table(_) | Self::Memory(_) | Self::Global(_) => TypeInfo::new(), } } } @@ -449,8 +508,8 @@ impl ModuleImportKey for (&str, &str) { /// Represents a core module type. #[derive(Debug, Clone)] pub struct ModuleType { - /// The effective type size for the module type. - pub(crate) type_size: usize, + /// Metadata about this module type + pub(crate) info: TypeInfo, /// The imports of the module type. pub imports: IndexMap<(String, String), EntityType>, /// The exports of the module type. @@ -464,26 +523,6 @@ impl ModuleType { pub fn lookup_import(&self, module: &str, name: &str) -> Option<&EntityType> { self.imports.get(&(module, name) as &dyn ModuleImportKey) } - - /// Determines if module type `a` is a subtype of `b`. - pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { - Self::internal_is_subtype_of(a, at.list, b, bt.list) - } - - pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { - // For module type subtyping, all exports in the other module type - // must be present in this module type's exports (i.e. it can export - // *more* than what this module type needs). - // However, for imports, the check is reversed (i.e. it is okay - // to import *less* than what this module type needs). - a.imports.iter().all(|(k, a)| match b.imports.get(k) { - Some(b) => EntityType::internal_is_subtype_of(b, bt, a, at), - None => false, - }) && b.exports.iter().all(|(k, b)| match a.exports.get(k) { - Some(a) => EntityType::internal_is_subtype_of(a, at, b, bt), - None => false, - }) - } } /// Represents the kind of module instance type. @@ -498,8 +537,8 @@ pub enum InstanceTypeKind { /// Represents a module instance type. #[derive(Debug, Clone)] pub struct InstanceType { - /// The effective type size for the module instance type. - pub(crate) type_size: usize, + /// Metadata about this instance type + pub(crate) info: TypeInfo, /// The kind of module instance type. pub kind: InstanceTypeKind, } @@ -515,7 +554,7 @@ impl InstanceType { types: &'a TypeList, ) -> &'a IndexMap { match &self.kind { - InstanceTypeKind::Instantiated(id) => &types[*id].as_module_type().unwrap().exports, + InstanceTypeKind::Instantiated(id) => &types[*id].unwrap_module().exports, InstanceTypeKind::Exports(exports) => exports, } } @@ -531,7 +570,18 @@ pub enum ComponentEntityType { /// The entity is a value. Value(ComponentValType), /// The entity is a type. - Type(TypeId), + Type { + /// This is the identifier of the type that was referenced when this + /// entity was created. + referenced: TypeId, + /// This is the identifier of the type that was created when this type + /// was imported or exported from the component. + /// + /// Note that the underlying type information for the `referenced` + /// field and for this `created` field is the same, but these two types + /// will hash to different values. + created: TypeId, + }, /// The entity is a component instance. Instance(TypeId), /// The entity is a component. @@ -541,69 +591,30 @@ pub enum ComponentEntityType { impl ComponentEntityType { /// Determines if component entity type `a` is a subtype of `b`. pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { - Self::internal_is_subtype_of(a, at.list, b, bt.list) - } - - pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { - match (a, b) { - (Self::Module(a), Self::Module(b)) => ModuleType::internal_is_subtype_of( - at[*a].as_module_type().unwrap(), - at, - bt[*b].as_module_type().unwrap(), - bt, - ), - (Self::Func(a), Self::Func(b)) => ComponentFuncType::internal_is_subtype_of( - at[*a].as_component_func_type().unwrap(), - at, - bt[*b].as_component_func_type().unwrap(), - bt, - ), - (Self::Value(a), Self::Value(b)) => { - ComponentValType::internal_is_subtype_of(a, at, b, bt) - } - (Self::Type(a), Self::Type(b)) => ComponentDefinedType::internal_is_subtype_of( - at[*a].as_defined_type().unwrap(), - at, - bt[*b].as_defined_type().unwrap(), - bt, - ), - (Self::Instance(a), Self::Instance(b)) => { - ComponentInstanceType::internal_is_subtype_of( - at[*a].as_component_instance_type().unwrap(), - at, - bt[*b].as_component_instance_type().unwrap(), - bt, - ) - } - (Self::Component(a), Self::Component(b)) => ComponentType::internal_is_subtype_of( - at[*a].as_component_type().unwrap(), - at, - bt[*b].as_component_type().unwrap(), - bt, - ), - _ => false, - } + SubtypeCx::new(at.list, bt.list) + .component_entity_type(a, b, 0) + .is_ok() } pub(crate) fn desc(&self) -> &'static str { match self { Self::Module(_) => "module", - Self::Func(_) => "function", + Self::Func(_) => "func", Self::Value(_) => "value", - Self::Type(_) => "type", + Self::Type { .. } => "type", Self::Instance(_) => "instance", Self::Component(_) => "component", } } - pub(crate) fn type_size(&self) -> usize { + pub(crate) fn info(&self, types: &TypeList) -> TypeInfo { match self { Self::Module(ty) | Self::Func(ty) - | Self::Type(ty) + | Self::Type { referenced: ty, .. } | Self::Instance(ty) - | Self::Component(ty) => ty.type_size, - Self::Value(ty) => ty.type_size(), + | Self::Component(ty) => types.info(*ty), + Self::Value(ty) => ty.info(types), } } } @@ -611,173 +622,141 @@ impl ComponentEntityType { /// Represents a type of a component. #[derive(Debug, Clone)] pub struct ComponentType { - /// The effective type size for the component type. - pub(crate) type_size: usize, + /// Metadata about this component type + pub(crate) info: TypeInfo, + /// The imports of the component type. + /// + /// Each import has its own kebab-name and an optional URL listed. Note that + /// the set of import names is disjoint with the set of export names. pub imports: IndexMap, + /// The exports of the component type. + /// + /// Each export has its own kebab-name and an optional URL listed. Note that + /// the set of export names is disjoint with the set of import names. pub exports: IndexMap, -} - -impl ComponentType { - /// Determines if component type `a` is a subtype of `b`. - pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { - Self::internal_is_subtype_of(a, at.list, b, bt.list) - } - pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { - // For component type subtyping, all exports in the other component type - // must be present in this component type's exports (i.e. it can export - // *more* than what this component type needs). - // However, for imports, the check is reversed (i.e. it is okay - // to import *less* than what this component type needs). - a.imports.iter().all(|(k, a)| match b.imports.get(k) { - Some(b) => ComponentEntityType::internal_is_subtype_of(b, bt, a, at), - None => false, - }) && b.exports.iter().all(|(k, b)| match a.exports.get(k) { - Some(a) => ComponentEntityType::internal_is_subtype_of(a, at, b, bt), - None => false, - }) - } -} - -/// Represents the kind of a component instance. -#[derive(Debug, Clone)] -pub enum ComponentInstanceTypeKind { - /// The instance type is from a definition. - Defined(IndexMap), - /// The instance type is the result of instantiating a component type. - Instantiated(TypeId), - /// The instance type is the result of instantiating from exported items. - Exports(IndexMap), + /// Universally quantified resources required to be provided when + /// instantiating this component type. + /// + /// Each resource in this map is explicitly imported somewhere in the + /// `imports` map. The "path" to where it's imported is specified by the + /// `Vec` payload here. For more information about the indexes see + /// the documentation on `ComponentState::imported_resources`. + /// + /// This should technically be inferrable from the structure of `imports`, + /// but it's stored as an auxiliary set for subtype checking and + /// instantiation. + /// + /// Note that this is not a set of all resources referred to by the + /// `imports`. Instead it's only those created, relative to the internals of + /// this component, by the imports. + pub imported_resources: Vec<(ResourceId, Vec)>, + + /// The dual of the `imported_resources`, or the set of defined + /// resources -- those created through the instantiation process which are + /// unique to this component. + /// + /// This set is similar to the `imported_resources` set but it's those + /// contained within the `exports`. Instantiating this component will + /// create fresh new versions of all of these resources. The path here is + /// within the `exports` array. + pub defined_resources: Vec<(ResourceId, Vec)>, + + /// The set of all resources which are explicitly exported by this + /// component, and where they're exported. + /// + /// This mapping is stored separately from `defined_resources` to ensure + /// that it contains all exported resources, not just those which are + /// defined. That means that this can cover reexports of imported + /// resources, exports of local resources, or exports of closed-over + /// resources for example. + pub explicit_resources: IndexMap>, } /// Represents a type of a component instance. #[derive(Debug, Clone)] pub struct ComponentInstanceType { - /// The effective type size for the instance type. - pub(crate) type_size: usize, - /// The kind of instance type. - pub kind: ComponentInstanceTypeKind, -} - -impl ComponentInstanceType { - /// Gets the exports of the instance type. - pub fn exports<'a>(&'a self, types: TypesRef<'a>) -> &'a IndexMap { - self.internal_exports(types.list) - } - - pub(crate) fn internal_exports<'a>( - &'a self, - types: &'a TypeList, - ) -> &'a IndexMap { - match &self.kind { - ComponentInstanceTypeKind::Defined(exports) - | ComponentInstanceTypeKind::Exports(exports) => exports, - ComponentInstanceTypeKind::Instantiated(id) => { - &types[*id].as_component_type().unwrap().exports - } - } - } + /// Metadata about this instance type + pub(crate) info: TypeInfo, - /// Determines if component instance type `a` is a subtype of `b`. - pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { - Self::internal_is_subtype_of(a, at.list, b, bt.list) - } - - pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { - let exports = a.internal_exports(at); + /// The list of exports, keyed by name, that this instance has. + /// + /// An optional URL and type of each export is provided as well. + pub exports: IndexMap, - // For instance type subtyping, all exports in the other instance type - // must be present in this instance type's exports (i.e. it can export - // *more* than what this instance type needs). - b.internal_exports(bt) - .iter() - .all(|(k, b)| match exports.get(k) { - Some(a) => ComponentEntityType::internal_is_subtype_of(a, at, b, bt), - None => false, - }) - } + /// The list of "defined resources" or those which are closed over in + /// this instance type. + /// + /// This list is populated, for example, when the type of an instance is + /// declared and it contains its own resource type exports defined + /// internally. For example: + /// + /// ```wasm + /// (component + /// (type (instance + /// (export "x" (type sub resource)) ;; one `defined_resources` entry + /// )) + /// ) + /// ``` + /// + /// This list is also a bit of an oddity, however, because the type of a + /// concrete instance will always have this as empty. For example: + /// + /// ```wasm + /// (component + /// (type $t (instance (export "x" (type sub resource)))) + /// + /// ;; the type of this instance has no defined resources + /// (import "i" (instance (type $t))) + /// ) + /// ``` + /// + /// This list ends up only being populated for instance types declared in a + /// module which aren't yet "attached" to anything. Once something is + /// instantiated, imported, exported, or otherwise refers to a concrete + /// instance then this list is always empty. For concrete instances + /// defined resources are tracked in the component state or component type. + pub defined_resources: Vec, + + /// The list of all resources that are explicitly exported from this + /// instance type along with the path they're exported at. + pub explicit_resources: IndexMap>, } /// Represents a type of a component function. #[derive(Debug, Clone)] pub struct ComponentFuncType { - /// The effective type size for the component function type. - pub(crate) type_size: usize, + /// Metadata about this function type. + pub(crate) info: TypeInfo, /// The function parameters. - pub params: Box<[(Option, ComponentValType)]>, + pub params: Box<[(KebabString, ComponentValType)]>, /// The function's results. - pub results: Box<[(Option, ComponentValType)]>, + pub results: Box<[(Option, ComponentValType)]>, } impl ComponentFuncType { - /// Determines if component function type `a` is a subtype of `b`. - pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { - Self::internal_is_subtype_of(a, at.list, b, bt.list) - } - - pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { - // Subtyping rules: - // https://github.com/WebAssembly/component-model/blob/main/design/mvp/Subtyping.md - - // The subtype cannot have more parameters than the supertype - if b.params.len() < a.params.len() { - return false; - } - - // The supertype cannot have more results than the subtype - if a.results.len() < b.results.len() { - return false; - } - - for ((an, a), (bn, b)) in a.params.iter().zip(b.params.iter()) { - // All overlapping parameters must have the same name - if an != bn { - return false; - } - - // Contravariant on parameters - if !ComponentValType::internal_is_subtype_of(b, bt, a, at) { - return false; - } - } - - // All remaining parameters in the supertype must be optional - if !b - .params - .iter() - .skip(a.params.len()) - .all(|(_, b)| b.is_optional(bt)) - { - return false; - } - - for ((an, a), (bn, b)) in a.results.iter().zip(b.results.iter()) { - // All overlapping results must have the same name - if an != bn { - return false; - } - - // Covariant on results - if !ComponentValType::internal_is_subtype_of(a, at, b, bt) { - return false; - } - } - - true - } - /// Lowers the component function type to core parameter and result types for the /// canonical ABI. - pub(crate) fn lower(&self, types: &TypeList, import: bool) -> LoweringInfo { + pub(crate) fn lower(&self, types: &TypeList, is_lower: bool) -> LoweringInfo { let mut info = LoweringInfo::default(); for (_, ty) in self.params.iter() { - // When `import` is false, it means we're lifting a core function, - // check if the parameters needs realloc - if !import && !info.requires_realloc { - info.requires_realloc = ty.requires_realloc(types); + // Check to see if `ty` has a pointer somewhere in it, needed for + // any type that transitively contains either a string or a list. + // In this situation lowered functions must specify `memory`, and + // lifted functions must specify `realloc` as well. Lifted functions + // gain their memory requirement through the final clause of this + // function. + if is_lower { + if !info.requires_memory { + info.requires_memory = ty.contains_ptr(types); + } + } else { + if !info.requires_realloc { + info.requires_realloc = ty.contains_ptr(types); + } } if !ty.push_wasm_types(types, &mut info.params) { @@ -789,7 +768,7 @@ impl ComponentFuncType { info.requires_memory = true; // We need realloc as well when lifting a function - if !import { + if !is_lower { info.requires_realloc = true; } break; @@ -797,17 +776,19 @@ impl ComponentFuncType { } for (_, ty) in self.results.iter() { - // When `import` is true, it means we're lowering a component function, - // check if the result needs realloc - if import && !info.requires_realloc { - info.requires_realloc = ty.requires_realloc(types); + // Results of lowered functions that contains pointers must be + // allocated by the callee meaning that realloc is required. + // Results of lifted function are allocated by the guest which + // means that no realloc option is necessary. + if is_lower && !info.requires_realloc { + info.requires_realloc = ty.contains_ptr(types); } if !ty.push_wasm_types(types, &mut info.results) { // Too many results to return directly, either a retptr parameter will be used (import) // or a single pointer will be returned (export) info.results.clear(); - if import { + if is_lower { info.params.max = MAX_LOWERED_TYPES; assert!(info.params.push(ValType::I32)); } else { @@ -831,45 +812,36 @@ pub struct VariantCase { /// The variant case type. pub ty: Option, /// The name of the variant case refined by this one. - pub refines: Option, + pub refines: Option, } /// Represents a record type. #[derive(Debug, Clone)] pub struct RecordType { - /// The effective type size for the record type. - pub(crate) type_size: usize, + /// Metadata about this record type. + pub(crate) info: TypeInfo, /// The map of record fields. - pub fields: IndexMap, + pub fields: IndexMap, } /// Represents a variant type. #[derive(Debug, Clone)] pub struct VariantType { - /// The effective type size for the variant type. - pub(crate) type_size: usize, + /// Metadata about this variant type. + pub(crate) info: TypeInfo, /// The map of variant cases. - pub cases: IndexMap, + pub cases: IndexMap, } /// Represents a tuple type. #[derive(Debug, Clone)] pub struct TupleType { - /// The effective type size for the tuple type. - pub(crate) type_size: usize, + /// Metadata about this tuple type. + pub(crate) info: TypeInfo, /// The types of the tuple. pub types: Box<[ComponentValType]>, } -/// Represents a union type. -#[derive(Debug, Clone)] -pub struct UnionType { - /// The inclusive type count for the union type. - pub(crate) type_size: usize, - /// The types of the union. - pub types: Box<[ComponentValType]>, -} - /// Represents a component defined type. #[derive(Debug, Clone)] pub enum ComponentDefinedType { @@ -884,11 +856,9 @@ pub enum ComponentDefinedType { /// The type is a tuple. Tuple(TupleType), /// The type is a set of flags. - Flags(IndexSet), + Flags(IndexSet), /// The type is an enumeration. - Enum(IndexSet), - /// The type is a union. - Union(UnionType), + Enum(IndexSet), /// The type is an `option`. Option(ComponentValType), /// The type is a `result`. @@ -898,135 +868,50 @@ pub enum ComponentDefinedType { /// The `error` type. err: Option, }, + /// The type is an owned handle to the specified resource. + Own(TypeId), + /// The type is a borrowed handle to the specified resource. + Borrow(TypeId), } impl ComponentDefinedType { - pub(crate) fn requires_realloc(&self, types: &TypeList) -> bool { + pub(crate) fn contains_ptr(&self, types: &TypeList) -> bool { match self { - Self::Primitive(ty) => ty.requires_realloc(), - Self::Record(r) => r.fields.values().any(|ty| ty.requires_realloc(types)), - Self::Variant(v) => v.cases.values().any(|case| { - case.ty - .map(|ty| ty.requires_realloc(types)) - .unwrap_or(false) - }), + Self::Primitive(ty) => ty.contains_ptr(), + Self::Record(r) => r.fields.values().any(|ty| ty.contains_ptr(types)), + Self::Variant(v) => v + .cases + .values() + .any(|case| case.ty.map(|ty| ty.contains_ptr(types)).unwrap_or(false)), Self::List(_) => true, - Self::Tuple(t) => t.types.iter().any(|ty| ty.requires_realloc(types)), - Self::Union(u) => u.types.iter().any(|ty| ty.requires_realloc(types)), - Self::Flags(_) | Self::Enum(_) => false, - Self::Option(ty) => ty.requires_realloc(types), + Self::Tuple(t) => t.types.iter().any(|ty| ty.contains_ptr(types)), + Self::Flags(_) | Self::Enum(_) | Self::Own(_) | Self::Borrow(_) => false, + Self::Option(ty) => ty.contains_ptr(types), Self::Result { ok, err } => { - ok.map(|ty| ty.requires_realloc(types)).unwrap_or(false) - || err.map(|ty| ty.requires_realloc(types)).unwrap_or(false) - } - } - } - - /// Determines if component defined type `a` is a subtype of `b`. - pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { - Self::internal_is_subtype_of(a, at.list, b, bt.list) - } - - pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { - // Subtyping rules according to - // https://github.com/WebAssembly/component-model/blob/main/design/mvp/Subtyping.md - match (a, b) { - (Self::Primitive(a), Self::Primitive(b)) => PrimitiveValType::is_subtype_of(*a, *b), - (Self::Record(a), Self::Record(b)) => { - for (name, a) in a.fields.iter() { - if let Some(b) = b.fields.get(name) { - if !ComponentValType::internal_is_subtype_of(a, at, b, bt) { - return false; - } - } else { - // Superfluous fields can be ignored in the subtype - } - } - // Check for missing required fields in the supertype - for (name, b) in b.fields.iter() { - if !b.is_optional(bt) && !a.fields.contains_key(name) { - return false; - } - } - true - } - (Self::Variant(a), Self::Variant(b)) => { - for (name, a) in a.cases.iter() { - if let Some(b) = b.cases.get(name) { - // Covariant subtype on the case type - if !Self::is_optional_subtype_of(a.ty, at, b.ty, bt) { - return false; - } - } else if let Some(refines) = &a.refines { - if !b.cases.contains_key(refines) { - // The refinement case is not in the supertype - return false; - } - } else { - // This case is not in the supertype and there is no - // default - return false; - } - } - true - } - (Self::List(a), Self::List(b)) | (Self::Option(a), Self::Option(b)) => { - ComponentValType::internal_is_subtype_of(a, at, b, bt) - } - (Self::Tuple(a), Self::Tuple(b)) => { - if a.types.len() != b.types.len() { - return false; - } - a.types - .iter() - .zip(b.types.iter()) - .all(|(a, b)| ComponentValType::internal_is_subtype_of(a, at, b, bt)) + ok.map(|ty| ty.contains_ptr(types)).unwrap_or(false) + || err.map(|ty| ty.contains_ptr(types)).unwrap_or(false) } - (Self::Union(a), Self::Union(b)) => { - if a.types.len() != b.types.len() { - return false; - } - a.types - .iter() - .zip(b.types.iter()) - .all(|(a, b)| ComponentValType::internal_is_subtype_of(a, at, b, bt)) - } - (Self::Flags(a), Self::Flags(b)) | (Self::Enum(a), Self::Enum(b)) => a.is_subset(b), - (Self::Result { ok: ao, err: ae }, Self::Result { ok: bo, err: be }) => { - Self::is_optional_subtype_of(*ao, at, *bo, bt) - && Self::is_optional_subtype_of(*ae, at, *be, bt) - } - _ => false, } } - pub(crate) fn type_size(&self) -> usize { + pub(crate) fn info(&self, types: &TypeList) -> TypeInfo { match self { - Self::Primitive(_) => 1, - Self::Flags(_) | Self::Enum(_) => 1, - Self::Record(r) => r.type_size, - Self::Variant(v) => v.type_size, - Self::Tuple(t) => t.type_size, - Self::Union(u) => u.type_size, - Self::List(ty) | Self::Option(ty) => ty.type_size(), + Self::Primitive(_) | Self::Flags(_) | Self::Enum(_) | Self::Own(_) => TypeInfo::new(), + Self::Borrow(_) => TypeInfo::borrow(), + Self::Record(r) => r.info, + Self::Variant(v) => v.info, + Self::Tuple(t) => t.info, + Self::List(ty) | Self::Option(ty) => ty.info(types), Self::Result { ok, err } => { - ok.map(|ty| ty.type_size()).unwrap_or(1) + err.map(|ty| ty.type_size()).unwrap_or(1) + let default = TypeInfo::new(); + let mut info = ok.map(|ty| ty.info(types)).unwrap_or(default); + info.combine(err.map(|ty| ty.info(types)).unwrap_or(default), 0) + .unwrap(); + info } } } - fn is_optional_subtype_of( - a: Option, - at: &TypeList, - b: Option, - bt: &TypeList, - ) -> bool { - match (a, b) { - (None, None) | (Some(_), None) => true, - (None, Some(_)) => false, - (Some(a), Some(b)) => ComponentValType::internal_is_subtype_of(&a, at, &b, bt), - } - } fn push_wasm_types(&self, types: &TypeList, lowered_types: &mut LoweredTypes) -> bool { match self { Self::Primitive(ty) => push_primitive_wasm_types(ty, lowered_types), @@ -1047,8 +932,7 @@ impl ComponentDefinedType { Self::Flags(names) => { (0..(names.len() + 31) / 32).all(|_| lowered_types.push(ValType::I32)) } - Self::Enum(_) => lowered_types.push(ValType::I32), - Self::Union(u) => Self::push_variant_wasm_types(u.types.iter(), types, lowered_types), + Self::Enum(_) | Self::Own(_) | Self::Borrow(_) => lowered_types.push(ValType::I32), Self::Option(ty) => { Self::push_variant_wasm_types([ty].into_iter(), types, lowered_types) } @@ -1102,6 +986,49 @@ impl ComponentDefinedType { _ => panic!("unexpected wasm type for canonical ABI"), } } + + fn desc(&self) -> &'static str { + match self { + ComponentDefinedType::Record(_) => "record", + ComponentDefinedType::Primitive(_) => "primitive", + ComponentDefinedType::Variant(_) => "variant", + ComponentDefinedType::Tuple(_) => "tuple", + ComponentDefinedType::Enum(_) => "enum", + ComponentDefinedType::Flags(_) => "flags", + ComponentDefinedType::Option(_) => "option", + ComponentDefinedType::List(_) => "list", + ComponentDefinedType::Result { .. } => "result", + ComponentDefinedType::Own(_) => "own", + ComponentDefinedType::Borrow(_) => "borrow", + } + } +} + +/// An opaque identifier intended to be used to distinguish whether two +/// resource types are equivalent or not. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Copy)] +#[repr(packed(4))] // try to not waste 4 bytes in padding +pub struct ResourceId { + // This is a globally unique identifier which is assigned once per + // `TypeAlloc`. This ensures that resource identifiers from different + // instances of `Types`, for example, are considered unique. + // + // Technically 64-bits should be enough for all resource ids ever, but + // they're allocated so often it's predicted that an atomic increment + // per resource id is probably too expensive. To amortize that cost each + // top-level wasm component gets a single globally unique identifier, and + // then within a component contextually unique identifiers are handed out. + globally_unique_id: u64, + + // A contextually unique id within the globally unique id above. This is + // allocated within a `TypeAlloc` with its own counter, and allocations of + // this are cheap as nothing atomic is required. + // + // The 32-bit storage here should ideally be enough for any component + // containing resources. If memory usage becomes an issue (this struct is + // 12 bytes instead of 8 or 4) then this coudl get folded into the globally + // unique id with everything using an atomic increment perhaps. + contextually_unique_id: u32, } #[allow(clippy::large_enum_variant)] @@ -1148,233 +1075,303 @@ impl<'a> TypesRef<'a> { } } - fn types(&self, core: bool) -> Option<&'a [TypeId]> { - Some(match &self.kind { - TypesRefKind::Module(module) => { - if core { - &module.types - } else { - return None; - } - } - TypesRefKind::Component(component) => { - if core { - &component.core_types - } else { - &component.types - } - } - }) - } - /// Gets a type based on its type id. /// /// Returns `None` if the type id is unknown. - pub fn type_from_id(&self, id: TypeId) -> Option<&'a Type> { - self.list.get(id.index) + pub fn get(&self, id: TypeId) -> Option<&'a Type> { + self.list.get(id.index()) } - /// Gets a type id from a type index. + /// Gets a core WebAssembly type id from a type index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn id_from_type_index(&self, index: u32, core: bool) -> Option { - self.types(core)?.get(index as usize).copied() - } - - /// Gets a type at the given type index. + /// Note that this is in contrast to [`TypesRef::component_type_at`] which + /// gets a component type from its index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn type_at(&self, index: u32, core: bool) -> Option<&'a Type> { - self.type_from_id(*self.types(core)?.get(index as usize)?) - } - - /// Gets a defined core function type at the given type index. + /// # Panics /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn func_type_at(&self, index: u32) -> Option<&'a FuncType> { - match self.type_at(index, true)? { - Type::Func(ty) => Some(ty), - _ => None, + /// This will panic if the `index` provided is out of bounds. + pub fn core_type_at(&self, index: u32) -> TypeId { + match &self.kind { + TypesRefKind::Module(module) => module.types[index as usize], + TypesRefKind::Component(component) => component.core_types[index as usize], + } + } + + /// Gets a type id from a type index. + /// + /// # Panics + /// + /// Panics if `index` is not a valid function index or if this type + /// information represents a core module. + pub fn component_type_at(&self, index: u32) -> TypeId { + match &self.kind { + TypesRefKind::Module(_) => panic!("not a component"), + TypesRefKind::Component(component) => component.types[index as usize], + } + } + + /// Returns the number of core types defined so far. + pub fn core_type_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(module) => module.types.len() as u32, + TypesRefKind::Component(component) => component.core_types.len() as u32, + } + } + + /// Returns the number of component types defined so far. + pub fn component_type_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(_module) => 0, + TypesRefKind::Component(component) => component.types.len() as u32, } } /// Gets the type of a table at the given table index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn table_at(&self, index: u32) -> Option { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds. + pub fn table_at(&self, index: u32) -> TableType { let tables = match &self.kind { TypesRefKind::Module(module) => &module.tables, TypesRefKind::Component(component) => &component.core_tables, }; + tables[index as usize] + } - tables.get(index as usize).copied() + /// Returns the number of tables defined so far. + pub fn table_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(module) => module.tables.len() as u32, + TypesRefKind::Component(component) => component.core_tables.len() as u32, + } } /// Gets the type of a memory at the given memory index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn memory_at(&self, index: u32) -> Option { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds. + pub fn memory_at(&self, index: u32) -> MemoryType { let memories = match &self.kind { TypesRefKind::Module(module) => &module.memories, TypesRefKind::Component(component) => &component.core_memories, }; - memories.get(index as usize).copied() + memories[index as usize] + } + + /// Returns the number of memories defined so far. + pub fn memory_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(module) => module.memories.len() as u32, + TypesRefKind::Component(component) => component.core_memories.len() as u32, + } } /// Gets the type of a global at the given global index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn global_at(&self, index: u32) -> Option { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds. + pub fn global_at(&self, index: u32) -> GlobalType { let globals = match &self.kind { TypesRefKind::Module(module) => &module.globals, TypesRefKind::Component(component) => &component.core_globals, }; - globals.get(index as usize).copied() + globals[index as usize] + } + + /// Returns the number of globals defined so far. + pub fn global_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(module) => module.globals.len() as u32, + TypesRefKind::Component(component) => component.core_globals.len() as u32, + } } /// Gets the type of a tag at the given tag index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn tag_at(&self, index: u32) -> Option<&'a FuncType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds. + pub fn tag_at(&self, index: u32) -> TypeId { let tags = match &self.kind { TypesRefKind::Module(module) => &module.tags, TypesRefKind::Component(component) => &component.core_tags, }; + tags[index as usize] + } - Some( - self.list[*tags.get(index as usize)?] - .as_func_type() - .unwrap(), - ) + /// Returns the number of tags defined so far. + pub fn tag_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(module) => module.tags.len() as u32, + TypesRefKind::Component(component) => component.core_tags.len() as u32, + } } /// Gets the type of a core function at the given function index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn function_at(&self, index: u32) -> Option<&'a FuncType> { - let id = match &self.kind { - TypesRefKind::Module(module) => { - &module.types[*module.functions.get(index as usize)? as usize] - } - TypesRefKind::Component(component) => component.core_funcs.get(index as usize)?, - }; + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds. + pub fn function_at(&self, index: u32) -> TypeId { + match &self.kind { + TypesRefKind::Module(module) => module.types[module.functions[index as usize] as usize], + TypesRefKind::Component(component) => component.core_funcs[index as usize], + } + } - match &self.list[*id] { - Type::Func(ty) => Some(ty), - _ => None, + /// Gets the count of core functions defined so far. + /// + /// Note that this includes imported functions, defined functions, and for + /// components lowered/aliased functions. + pub fn function_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(module) => module.functions.len() as u32, + TypesRefKind::Component(component) => component.core_funcs.len() as u32, } } /// Gets the type of an element segment at the given element segment index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn element_at(&self, index: u32) -> Option { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds. + pub fn element_at(&self, index: u32) -> RefType { match &self.kind { - TypesRefKind::Module(module) => module.element_types.get(index as usize).copied(), - TypesRefKind::Component(_) => None, + TypesRefKind::Module(module) => module.element_types[index as usize], + TypesRefKind::Component(_) => { + panic!("no elements on a component") + } + } + } + + /// Returns the number of elements defined so far. + pub fn element_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(module) => module.element_types.len() as u32, + TypesRefKind::Component(_) => 0, } } /// Gets the type of a component function at the given function index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn component_function_at(&self, index: u32) -> Option<&'a ComponentFuncType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn component_function_at(&self, index: u32) -> TypeId { match &self.kind { - TypesRefKind::Module(_) => None, - TypesRefKind::Component(component) => Some( - self.list[*component.funcs.get(index as usize)?] - .as_component_func_type() - .unwrap(), - ), + TypesRefKind::Module(_) => panic!("not a component"), + TypesRefKind::Component(component) => component.funcs[index as usize], + } + } + + /// Returns the number of component functions defined so far. + pub fn component_function_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(_module) => 0, + TypesRefKind::Component(component) => component.funcs.len() as u32, } } /// Gets the type of a module at the given module index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn module_at(&self, index: u32) -> Option<&'a ModuleType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn module_at(&self, index: u32) -> TypeId { match &self.kind { - TypesRefKind::Module(_) => None, - TypesRefKind::Component(component) => Some( - self.list[*component.core_modules.get(index as usize)?] - .as_module_type() - .unwrap(), - ), + TypesRefKind::Module(_) => panic!("not a component"), + TypesRefKind::Component(component) => component.core_modules[index as usize], + } + } + + /// Returns the number of core wasm modules defined so far. + pub fn module_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(_module) => 0, + TypesRefKind::Component(component) => component.core_modules.len() as u32, } } /// Gets the type of a module instance at the given module instance index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn instance_at(&self, index: u32) -> Option<&'a InstanceType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn instance_at(&self, index: u32) -> TypeId { match &self.kind { - TypesRefKind::Module(_) => None, - TypesRefKind::Component(component) => { - let id = component.core_instances.get(index as usize)?; - match &self.list[*id] { - Type::Instance(ty) => Some(ty), - _ => None, - } - } + TypesRefKind::Module(_) => panic!("not a component"), + TypesRefKind::Component(component) => component.core_instances[index as usize], + } + } + + /// Returns the number of core wasm instances defined so far. + pub fn instance_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(_module) => 0, + TypesRefKind::Component(component) => component.core_instances.len() as u32, } } /// Gets the type of a component at the given component index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn component_at(&self, index: u32) -> Option<&'a ComponentType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn component_at(&self, index: u32) -> TypeId { match &self.kind { - TypesRefKind::Module(_) => None, - TypesRefKind::Component(component) => Some( - self.list[*component.components.get(index as usize)?] - .as_component_type() - .unwrap(), - ), + TypesRefKind::Module(_) => panic!("not a component"), + TypesRefKind::Component(component) => component.components[index as usize], + } + } + + /// Returns the number of components defined so far. + pub fn component_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(_module) => 0, + TypesRefKind::Component(component) => component.components.len() as u32, } } /// Gets the type of an component instance at the given component instance index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn component_instance_at(&self, index: u32) -> Option<&'a ComponentInstanceType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn component_instance_at(&self, index: u32) -> TypeId { match &self.kind { - TypesRefKind::Module(_) => None, - TypesRefKind::Component(component) => { - let id = component.instances.get(index as usize)?; - match &self.list[*id] { - Type::ComponentInstance(ty) => Some(ty), - _ => None, - } - } + TypesRefKind::Module(_) => panic!("not a component"), + TypesRefKind::Component(component) => component.instances[index as usize], + } + } + + /// Returns the number of component instances defined so far. + pub fn component_instance_count(&self) -> u32 { + match &self.kind { + TypesRefKind::Module(_module) => 0, + TypesRefKind::Component(component) => component.instances.len() as u32, } } /// Gets the type of a value at the given value index. /// - /// Returns `None` if the type index is out of bounds or the type has not - /// been parsed yet. - pub fn value_at(&self, index: u32) -> Option { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn value_at(&self, index: u32) -> ComponentValType { match &self.kind { - TypesRefKind::Module(_) => None, - TypesRefKind::Component(component) => { - component.values.get(index as usize).map(|(r, _)| *r) - } + TypesRefKind::Module(_) => panic!("not a component"), + TypesRefKind::Component(component) => component.values[index as usize].0, } } @@ -1417,70 +1414,34 @@ impl<'a> TypesRef<'a> { } /// Gets the component entity type for the given component import. - pub fn component_entity_type_from_import( - &self, - import: &ComponentImport, - ) -> Option { + pub fn component_entity_type_of_import(&self, name: &str) -> Option { match &self.kind { TypesRefKind::Module(_) => None, - TypesRefKind::Component(component) => Some(match import.ty { - ComponentTypeRef::Module(idx) => { - ComponentEntityType::Module(*component.core_types.get(idx as usize)?) - } - ComponentTypeRef::Func(idx) => { - ComponentEntityType::Func(*component.types.get(idx as usize)?) - } - ComponentTypeRef::Value(ty) => ComponentEntityType::Value(match ty { - crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(ty), - crate::ComponentValType::Type(idx) => { - ComponentValType::Type(*component.types.get(idx as usize)?) - } - }), - ComponentTypeRef::Type(_, idx) => { - ComponentEntityType::Type(*component.types.get(idx as usize)?) - } - ComponentTypeRef::Instance(idx) => { - ComponentEntityType::Instance(*component.types.get(idx as usize)?) - } - ComponentTypeRef::Component(idx) => { - ComponentEntityType::Component(*component.types.get(idx as usize)?) - } - }), + TypesRefKind::Component(component) => Some(*component.imports.get(name)?), } } - /// Gets the component entity type from the given component export. - pub fn component_entity_type_from_export( - &self, - export: &ComponentExport, - ) -> Option { + /// Gets the component entity type for the given component export. + pub fn component_entity_type_of_export(&self, name: &str) -> Option { match &self.kind { TypesRefKind::Module(_) => None, - TypesRefKind::Component(component) => Some(match export.kind { - ComponentExternalKind::Module => { - ComponentEntityType::Module(*component.core_modules.get(export.index as usize)?) - } - ComponentExternalKind::Func => { - ComponentEntityType::Func(*component.funcs.get(export.index as usize)?) - } - ComponentExternalKind::Value => ComponentEntityType::Value( - component - .values - .get(export.index as usize) - .map(|(r, _)| *r)?, - ), - ComponentExternalKind::Type => { - ComponentEntityType::Type(*component.types.get(export.index as usize)?) - } - ComponentExternalKind::Instance => { - ComponentEntityType::Instance(*component.instances.get(export.index as usize)?) - } - ComponentExternalKind::Component => ComponentEntityType::Component( - *component.components.get(export.index as usize)?, - ), - }), + TypesRefKind::Component(component) => Some(*component.exports.get(name)?), } } + + /// Attempts to lookup the type id that `ty` is an alias of. + /// + /// Returns `None` if `ty` wasn't listed as aliasing a prior type. + pub fn peel_alias(&self, ty: TypeId) -> Option { + self.list.peel_alias(ty) + } +} + +impl Index for TypesRef<'_> { + type Output = Type; + fn index(&self, id: TypeId) -> &Type { + &self.list[id] + } } impl Types { @@ -1512,29 +1473,30 @@ impl Types { /// Gets a type based on its type id. /// /// Returns `None` if the type id is unknown. - pub fn type_from_id(&self, id: TypeId) -> Option<&Type> { - self.as_ref().type_from_id(id) + pub fn get(&self, id: TypeId) -> Option<&Type> { + self.as_ref().get(id) } - /// Gets a type id from a type index. + /// Gets a core WebAssembly type at the given type index. /// - /// Returns `None` if the type index is out of bounds. - pub fn id_from_type_index(&self, index: u32, core: bool) -> Option { - self.as_ref().id_from_type_index(index, core) - } - - /// Gets a type at the given type index. + /// Note that this is in contrast to [`TypesRef::component_type_at`] which + /// gets a component type from its index. + /// + /// # Panics /// - /// Returns `None` if the index is out of bounds. - pub fn type_at(&self, index: u32, core: bool) -> Option<&Type> { - self.as_ref().type_at(index, core) + /// Panics if `index` is not a valid function index. + pub fn core_type_at(&self, index: u32) -> TypeId { + self.as_ref().core_type_at(index) } - /// Gets a defined core function type at the given type index. + /// Gets a component type from the given component type index. + /// + /// # Panics /// - /// Returns `None` if the index is out of bounds. - pub fn func_type_at(&self, index: u32) -> Option<&FuncType> { - self.as_ref().func_type_at(index) + /// Panics if `index` is not a valid function index or if this type + /// information represents a core module. + pub fn component_type_at(&self, index: u32) -> TypeId { + self.as_ref().component_type_at(index) } /// Gets the count of core types. @@ -1547,8 +1509,10 @@ impl Types { /// Gets the type of a table at the given table index. /// - /// Returns `None` if the index is out of bounds. - pub fn table_at(&self, index: u32) -> Option { + /// # Panics + /// + /// Panics if `index` is not a valid function index. + pub fn table_at(&self, index: u32) -> TableType { self.as_ref().table_at(index) } @@ -1562,100 +1526,99 @@ impl Types { /// Gets the type of a memory at the given memory index. /// - /// Returns `None` if the index is out of bounds. - pub fn memory_at(&self, index: u32) -> Option { + /// # Panics + /// + /// Panics if `index` is not a valid function index. + pub fn memory_at(&self, index: u32) -> MemoryType { self.as_ref().memory_at(index) } /// Gets the count of imported and defined memories. - pub fn memory_count(&self) -> usize { - match &self.kind { - TypesKind::Module(module) => module.memories.len(), - TypesKind::Component(component) => component.core_memories.len(), - } + pub fn memory_count(&self) -> u32 { + self.as_ref().memory_count() } /// Gets the type of a global at the given global index. /// - /// Returns `None` if the index is out of bounds. - pub fn global_at(&self, index: u32) -> Option { + /// # Panics + /// + /// Panics if `index` is not a valid function index. + pub fn global_at(&self, index: u32) -> GlobalType { self.as_ref().global_at(index) } /// Gets the count of imported and defined globals. - pub fn global_count(&self) -> usize { - match &self.kind { - TypesKind::Module(module) => module.globals.len(), - TypesKind::Component(component) => component.core_globals.len(), - } + pub fn global_count(&self) -> u32 { + self.as_ref().global_count() } /// Gets the type of a tag at the given tag index. /// - /// Returns `None` if the index is out of bounds. - pub fn tag_at(&self, index: u32) -> Option<&FuncType> { + /// # Panics + /// + /// Panics if `index` is not a valid function index. + pub fn tag_at(&self, index: u32) -> TypeId { self.as_ref().tag_at(index) } /// Gets the count of imported and defined tags. - pub fn tag_count(&self) -> usize { - match &self.kind { - TypesKind::Module(module) => module.tags.len(), - TypesKind::Component(component) => component.core_tags.len(), - } + pub fn tag_count(&self) -> u32 { + self.as_ref().tag_count() } /// Gets the type of a core function at the given function index. /// - /// Returns `None` if the index is out of bounds. - pub fn function_at(&self, index: u32) -> Option<&FuncType> { + /// # Panics + /// + /// Panics if `index` is not a valid function index. + pub fn function_at(&self, index: u32) -> TypeId { self.as_ref().function_at(index) } - /// Gets the count of imported and defined core functions. + /// Gets the count of core functions defined so far. /// - /// The count also includes aliased core functions in components. - pub fn function_count(&self) -> usize { - match &self.kind { - TypesKind::Module(module) => module.functions.len(), - TypesKind::Component(component) => component.core_funcs.len(), - } + /// Note that this includes imported functions, defined functions, and for + /// components lowered/aliased functions. + pub fn function_count(&self) -> u32 { + self.as_ref().function_count() } /// Gets the type of an element segment at the given element segment index. /// - /// Returns `None` if the index is out of bounds. - pub fn element_at(&self, index: u32) -> Option { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds. + pub fn element_at(&self, index: u32) -> RefType { self.as_ref().element_at(index) } /// Gets the count of element segments. - pub fn element_count(&self) -> usize { - match &self.kind { - TypesKind::Module(module) => module.element_types.len(), - TypesKind::Component(_) => 0, - } + pub fn element_count(&self) -> u32 { + self.as_ref().element_count() } /// Gets the type of a component function at the given function index. /// - /// Returns `None` if the index is out of bounds. - pub fn component_function_at(&self, index: u32) -> Option<&ComponentFuncType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn component_function_at(&self, index: u32) -> TypeId { self.as_ref().component_function_at(index) } /// Gets the count of imported, exported, or aliased component functions. - pub fn component_function_count(&self) -> usize { - match &self.kind { - TypesKind::Module(_) => 0, - TypesKind::Component(component) => component.funcs.len(), - } + pub fn component_function_count(&self) -> u32 { + self.as_ref().component_function_count() } /// Gets the type of a module at the given module index. /// - /// Returns `None` if the index is out of bounds. - pub fn module_at(&self, index: u32) -> Option<&ModuleType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn module_at(&self, index: u32) -> TypeId { self.as_ref().module_at(index) } @@ -1669,8 +1632,11 @@ impl Types { /// Gets the type of a module instance at the given module instance index. /// - /// Returns `None` if the index is out of bounds. - pub fn instance_at(&self, index: u32) -> Option<&InstanceType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn instance_at(&self, index: u32) -> TypeId { self.as_ref().instance_at(index) } @@ -1684,8 +1650,11 @@ impl Types { /// Gets the type of a component at the given component index. /// - /// Returns `None` if the index is out of bounds. - pub fn component_at(&self, index: u32) -> Option<&ComponentType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn component_at(&self, index: u32) -> TypeId { self.as_ref().component_at(index) } @@ -1699,8 +1668,11 @@ impl Types { /// Gets the type of an component instance at the given component instance index. /// - /// Returns `None` if the index is out of bounds. - pub fn component_instance_at(&self, index: u32) -> Option<&ComponentInstanceType> { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn component_instance_at(&self, index: u32) -> TypeId { self.as_ref().component_instance_at(index) } @@ -1714,8 +1686,11 @@ impl Types { /// Gets the type of a value at the given value index. /// - /// Returns `None` if the index is out of bounds. - pub fn value_at(&self, index: u32) -> Option { + /// # Panics + /// + /// This will panic if the `index` provided is out of bounds or if this type + /// information represents a core module. + pub fn value_at(&self, index: u32) -> ComponentValType { self.as_ref().value_at(index) } @@ -1737,20 +1712,29 @@ impl Types { self.as_ref().entity_type_from_export(export) } - /// Gets the component entity type for the given component import. - pub fn component_entity_type_from_import( - &self, - import: &ComponentImport, - ) -> Option { - self.as_ref().component_entity_type_from_import(import) + /// Gets the component entity type for the given component import name. + pub fn component_entity_type_of_import(&self, name: &str) -> Option { + self.as_ref().component_entity_type_of_import(name) } - /// Gets the component entity type from the given component export. - pub fn component_entity_type_from_export( - &self, - export: &ComponentExport, - ) -> Option { - self.as_ref().component_entity_type_from_export(export) + /// Gets the component entity type for the given component export name. + pub fn component_entity_type_of_export(&self, name: &str) -> Option { + self.as_ref().component_entity_type_of_export(name) + } + + /// Attempts to lookup the type id that `ty` is an alias of. + /// + /// Returns `None` if `ty` wasn't listed as aliasing a prior type. + pub fn peel_alias(&self, ty: TypeId) -> Option { + self.as_ref().peel_alias(ty) + } +} + +impl Index for Types { + type Output = Type; + + fn index(&self, id: TypeId) -> &Type { + &self.list[id] } } @@ -1775,13 +1759,23 @@ pub(crate) struct SnapshotList { // // Note that this list is sorted least-to-greatest in order of the index for // binary searching. - snapshots: Vec<(usize, Arc>)>, + snapshots: Vec>>, // This is the total length of all lists in the `snapshots` array. snapshots_total: usize, // The current list of types for the current snapshot that are being built. cur: Vec, + + unique_mappings: HashMap, + unique_counter: u32, +} + +struct Snapshot { + prior_types: usize, + unique_counter: u32, + unique_mappings: HashMap, + items: Vec, } impl SnapshotList { @@ -1794,28 +1788,15 @@ impl SnapshotList { // ... and failing that we do a binary search to figure out which bucket // it's in. Note the `i-1` in the `Err` case because if we don't find an // exact match the type is located in the previous bucket. - let i = match self.snapshots.binary_search_by_key(&index, |(i, _)| *i) { + let i = match self + .snapshots + .binary_search_by_key(&index, |snapshot| snapshot.prior_types) + { Ok(i) => i, Err(i) => i - 1, }; - let (len, list) = &self.snapshots[i]; - Some(&list[index - len]) - } - - /// Same as `<&mut [T]>::get_mut`, except only works for indexes into the - /// current snapshot being built. - /// - /// # Panics - /// - /// Panics if an index is passed in which falls within the - /// previously-snapshotted list of types. This should never happen in our - /// context and the panic is intended to weed out possible bugs in - /// wasmparser. - pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut T> { - if index >= self.snapshots_total { - return self.cur.get_mut(index - self.snapshots_total); - } - panic!("cannot get a mutable reference in snapshotted part of list") + let snapshot = &self.snapshots[i]; + Some(&snapshot.items[index - snapshot.prior_types]) } /// Same as `Vec::push` @@ -1843,23 +1824,74 @@ impl SnapshotList { // If the current chunk has new elements, commit them in to an // `Arc`-wrapped vector in the snapshots list. Note the `shrink_to_fit` // ahead of time to hopefully keep memory usage lower than it would - // otherwise be. + // otherwise be. Additionally note that the `unique_counter` is bumped + // here to ensure that the previous value of the unique counter is + // never used for an actual type so it's suitable for lookup via a + // binary search. let len = self.cur.len(); if len > 0 { + self.unique_counter += 1; self.cur.shrink_to_fit(); - self.snapshots - .push((self.snapshots_total, Arc::new(mem::take(&mut self.cur)))); + self.snapshots.push(Arc::new(Snapshot { + prior_types: self.snapshots_total, + unique_counter: self.unique_counter - 1, + unique_mappings: mem::take(&mut self.unique_mappings), + items: mem::take(&mut self.cur), + })); self.snapshots_total += len; } SnapshotList { snapshots: self.snapshots.clone(), snapshots_total: self.snapshots_total, + unique_mappings: HashMap::new(), + unique_counter: self.unique_counter, cur: Vec::new(), } } + + /// Modifies a `TypeId` to have the same contents but a fresh new unique id. + /// + /// This is used during aliasing with components to assign types a unique + /// identifier that isn't equivalent to anything else but still + /// points to the same underlying type. + pub fn with_unique(&mut self, mut ty: TypeId) -> TypeId { + self.unique_mappings + .insert(self.unique_counter, ty.unique_id); + ty.unique_id = self.unique_counter; + self.unique_counter += 1; + ty + } + + /// Attempts to lookup the type id that `ty` is an alias of. + /// + /// Returns `None` if `ty` wasn't listed as aliasing a prior type. + pub fn peel_alias(&self, ty: TypeId) -> Option { + // The unique counter in each snapshot is the unique counter at the + // time of the snapshot so it's guaranteed to never be used, meaning + // that `Ok` should never show up here. With an `Err` it's where the + // index would be placed meaning that the index in question is the + // smallest value over the unique id's value, meaning that slot has the + // mapping we're interested in. + let i = match self + .snapshots + .binary_search_by_key(&ty.unique_id, |snapshot| snapshot.unique_counter) + { + Ok(_) => unreachable!(), + Err(i) => i, + }; + + // If the `i` index is beyond the snapshot array then lookup in the + // current mappings instead since it may refer to a type not snapshot + // yet. + let unique_id = match self.snapshots.get(i) { + Some(snapshot) => *snapshot.unique_mappings.get(&ty.unique_id)?, + None => *self.unique_mappings.get(&ty.unique_id)?, + }; + Some(TypeId { unique_id, ..ty }) + } } -impl std::ops::Index for SnapshotList { +impl Index for SnapshotList { type Output = T; #[inline] @@ -1868,26 +1900,12 @@ impl std::ops::Index for SnapshotList { } } -impl std::ops::IndexMut for SnapshotList { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut T { - self.get_mut(index).unwrap() - } -} - -impl std::ops::Index for SnapshotList { +impl Index for SnapshotList { type Output = T; #[inline] fn index(&self, id: TypeId) -> &T { - self.get(id.index).unwrap() - } -} - -impl std::ops::IndexMut for SnapshotList { - #[inline] - fn index_mut(&mut self, id: TypeId) -> &mut T { - self.get_mut(id.index).unwrap() + self.get(id.index()).unwrap() } } @@ -1897,9 +1915,1391 @@ impl Default for SnapshotList { snapshots: Vec::new(), snapshots_total: 0, cur: Vec::new(), + unique_counter: 1, + unique_mappings: HashMap::new(), } } } /// A snapshot list of types. -pub(crate) type TypeList = SnapshotList; +#[derive(Default)] +pub(crate) struct TypeList { + types: SnapshotList, + infos: SnapshotList, +} + +impl TypeList { + pub fn info(&self, id: TypeId) -> TypeInfo { + self.infos[id] + } + + pub fn get(&self, index: usize) -> Option<&Type> { + self.types.get(index) + } + + pub fn len(&self) -> usize { + debug_assert_eq!(self.types.len(), self.infos.len()); + self.types.len() + } + + pub fn push(&mut self, ty: Type) { + let info = ty.calculate_info(self); + self.infos.push(info); + self.types.push(ty); + debug_assert_eq!(self.types.len(), self.infos.len()); + } + + pub fn reserve(&mut self, additional: usize) { + self.infos.reserve(additional); + self.types.reserve(additional); + } + + pub fn commit(&mut self) -> TypeList { + TypeList { + types: self.types.commit(), + infos: self.infos.commit(), + } + } + + /// See `SnapshotList::with_unique`. + pub fn with_unique(&mut self, ty: TypeId) -> TypeId { + self.types.with_unique(ty) + } + + /// See `SnapshotList::peel_alias`. + pub fn peel_alias(&self, ty: TypeId) -> Option { + self.types.peel_alias(ty) + } +} + +impl Index for TypeList { + type Output = Type; + + fn index(&self, index: TypeId) -> &Self::Output { + &self.types[index] + } +} + +/// Thin wrapper around `TypeList` which provides an allocator of unique ids for +/// types contained within this list. +pub(crate) struct TypeAlloc { + list: TypeList, + + // This is assigned at creation of a `TypeAlloc` and then never changed. + // It's used in one entry for all `ResourceId`s contained within. + globally_unique_id: u64, + + // This is a counter that's incremeneted each time `alloc_resource_id` is + // called. + next_resource_id: u32, +} + +impl Default for TypeAlloc { + fn default() -> TypeAlloc { + static NEXT_GLOBAL_ID: AtomicU64 = AtomicU64::new(0); + TypeAlloc { + list: TypeList::default(), + globally_unique_id: NEXT_GLOBAL_ID.fetch_add(1, Ordering::Relaxed), + next_resource_id: 0, + } + } +} + +impl Deref for TypeAlloc { + type Target = TypeList; + fn deref(&self) -> &TypeList { + &self.list + } +} + +impl DerefMut for TypeAlloc { + fn deref_mut(&mut self) -> &mut TypeList { + &mut self.list + } +} + +impl TypeAlloc { + /// Pushes a new type into this list, returning an identifier which can be + /// used to later retrieve it. + /// + /// The returned identifier is unique within this `TypeAlloc` and won't be + /// hash-equivalent to anything else. + pub fn push_ty(&mut self, ty: Type) -> TypeId { + let index = self.list.len(); + let index = u32::try_from(index).unwrap(); + self.list.push(ty); + TypeId { + index, + unique_id: 0, + } + } + + /// Allocates a new unique resource identifier. + /// + /// Note that uniqueness is only a property within this `TypeAlloc`. + pub fn alloc_resource_id(&mut self) -> ResourceId { + let contextually_unique_id = self.next_resource_id; + self.next_resource_id = self.next_resource_id.checked_add(1).unwrap(); + ResourceId { + globally_unique_id: self.globally_unique_id, + contextually_unique_id, + } + } + + /// Adds the set of "free variables" of the `id` provided to the `set` + /// provided. + /// + /// Free variables are defined as resources. Any resource, perhaps + /// transitively, referred to but not defined by `id` is added to the `set` + /// and returned. + pub fn free_variables_type_id(&self, id: TypeId, set: &mut IndexSet) { + match &self[id] { + // Core wasm constructs cannot reference resources. + Type::Sub(_) | Type::Module(_) | Type::Instance(_) => {} + + // Recurse on the imports/exports of components, but remove the + // imported and defined resources within the component itself. + // + // Technically this needs to add all the free variables of the + // exports, remove the defined resources, then add the free + // variables of imports, then remove the imported resources. Given + // prior validation of component types, however, the defined + // and imported resources are disjoint and imports can't refer to + // defined resources, so doing this all in one go should be + // equivalent. + Type::Component(i) => { + for ty in i.imports.values().chain(i.exports.values()) { + self.free_variables_component_entity(ty, set); + } + for (id, _path) in i.imported_resources.iter().chain(&i.defined_resources) { + set.remove(id); + } + } + + // Like components, add in all the free variables of referenced + // types but then remove those defined by this component instance + // itself. + Type::ComponentInstance(i) => { + for ty in i.exports.values() { + self.free_variables_component_entity(ty, set); + } + for id in i.defined_resources.iter() { + set.remove(id); + } + } + + Type::Resource(r) => { + set.insert(*r); + } + + Type::ComponentFunc(i) => { + for ty in i + .params + .iter() + .map(|(_, ty)| ty) + .chain(i.results.iter().map(|(_, ty)| ty)) + { + self.free_variables_valtype(ty, set); + } + } + + Type::Defined(i) => match i { + ComponentDefinedType::Primitive(_) + | ComponentDefinedType::Flags(_) + | ComponentDefinedType::Enum(_) => {} + ComponentDefinedType::Record(r) => { + for ty in r.fields.values() { + self.free_variables_valtype(ty, set); + } + } + ComponentDefinedType::Tuple(r) => { + for ty in r.types.iter() { + self.free_variables_valtype(ty, set); + } + } + ComponentDefinedType::Variant(r) => { + for ty in r.cases.values() { + if let Some(ty) = &ty.ty { + self.free_variables_valtype(ty, set); + } + } + } + ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + self.free_variables_valtype(ty, set); + } + ComponentDefinedType::Result { ok, err } => { + if let Some(ok) = ok { + self.free_variables_valtype(ok, set); + } + if let Some(err) = err { + self.free_variables_valtype(err, set); + } + } + ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => { + self.free_variables_type_id(*id, set); + } + }, + } + } + + /// Same as `free_variables_type_id`, but for `ComponentEntityType`. + pub fn free_variables_component_entity( + &self, + ty: &ComponentEntityType, + set: &mut IndexSet, + ) { + match ty { + ComponentEntityType::Module(id) + | ComponentEntityType::Func(id) + | ComponentEntityType::Instance(id) + | ComponentEntityType::Component(id) => self.free_variables_type_id(*id, set), + ComponentEntityType::Type { created, .. } => { + self.free_variables_type_id(*created, set); + } + ComponentEntityType::Value(ty) => self.free_variables_valtype(ty, set), + } + } + + /// Same as `free_variables_type_id`, but for `ComponentValType`. + fn free_variables_valtype(&self, ty: &ComponentValType, set: &mut IndexSet) { + match ty { + ComponentValType::Primitive(_) => {} + ComponentValType::Type(id) => self.free_variables_type_id(*id, set), + } + } + + /// Returns whether the type `id` is "named" where named types are presented + /// via the provided `set`. + /// + /// This requires that `id` is a `Defined` type. + pub(crate) fn type_named_type_id(&self, id: TypeId, set: &HashSet) -> bool { + let ty = self[id].unwrap_defined(); + match ty { + // Primitives are always considered named + ComponentDefinedType::Primitive(_) => true, + + // These structures are never allowed to be anonymous, so they + // themselves must be named. + ComponentDefinedType::Flags(_) + | ComponentDefinedType::Enum(_) + | ComponentDefinedType::Record(_) + | ComponentDefinedType::Variant(_) => set.contains(&id), + + // All types below here are allowed to be anonymous, but their + // own components must be appropriately named. + ComponentDefinedType::Tuple(r) => { + r.types.iter().all(|t| self.type_named_valtype(t, set)) + } + ComponentDefinedType::Result { ok, err } => { + ok.as_ref() + .map(|t| self.type_named_valtype(t, set)) + .unwrap_or(true) + && err + .as_ref() + .map(|t| self.type_named_valtype(t, set)) + .unwrap_or(true) + } + ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + self.type_named_valtype(ty, set) + } + + // own/borrow themselves don't have to be named, but the resource + // they refer to must be named. + ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => set.contains(id), + } + } + + pub(crate) fn type_named_valtype(&self, ty: &ComponentValType, set: &HashSet) -> bool { + match ty { + ComponentValType::Primitive(_) => true, + ComponentValType::Type(id) => self.type_named_type_id(*id, set), + } + } +} + +/// A helper trait to provide the functionality necessary to resources within a +/// type. +/// +/// This currently exists to abstract over `TypeAlloc` and `SubtypeArena` which +/// both need to perform remapping operations. +pub(crate) trait Remap: Index { + /// Pushes a new anonymous type within this object, returning an identifier + /// which can be used to refer to it. + fn push_ty(&mut self, ty: Type) -> TypeId; + + /// Applies a resource and type renaming map to the `id` specified, + /// returning `true` if the `id` was modified or `false` if it didn't need + /// changing. + /// + /// This will recursively modify the structure of the `id` specified and + /// update all references to resources found. The resource identifier keys + /// in the `map` specified will become the corresponding value, in addition + /// to any existing types in `map` becoming different tyeps. + /// + /// The `id` argument will be rewritten to a new identifier if `true` is + /// returned. + fn remap_type_id(&mut self, id: &mut TypeId, map: &mut Remapping) -> bool { + if let Some(new) = map.types.get(id) { + let changed = *new != *id; + *id = *new; + return changed; + } + + // This function attempts what ends up probably being a relatively + // minor optimization where a new `id` isn't manufactured unless + // something about the type actually changed. That means that if the + // type doesn't actually use any resources, for example, then no new + // id is allocated. + let mut any_changed = false; + + let map_map = |tmp: &mut IndexMap>, + any_changed: &mut bool, + map: &mut Remapping| { + for (id, path) in mem::take(tmp) { + let id = match map.resources.get(&id) { + Some(id) => { + *any_changed = true; + *id + } + None => id, + }; + tmp.insert(id, path); + } + }; + + let ty = match &self[*id] { + // Core wasm functions/modules/instances don't have resource types + // in them. + Type::Sub(_) | Type::Module(_) | Type::Instance(_) => return false, + + Type::Component(i) => { + let mut tmp = i.clone(); + for ty in tmp.imports.values_mut().chain(tmp.exports.values_mut()) { + if self.remap_component_entity(ty, map) { + any_changed = true; + } + } + for (id, _) in tmp + .imported_resources + .iter_mut() + .chain(&mut tmp.defined_resources) + { + if let Some(new) = map.resources.get(id) { + *id = *new; + any_changed = true; + } + } + map_map(&mut tmp.explicit_resources, &mut any_changed, map); + Type::Component(tmp) + } + + Type::ComponentInstance(i) => { + let mut tmp = i.clone(); + for ty in tmp.exports.values_mut() { + if self.remap_component_entity(ty, map) { + any_changed = true; + } + } + for id in tmp.defined_resources.iter_mut() { + if let Some(new) = map.resources.get(id) { + *id = *new; + any_changed = true; + } + } + map_map(&mut tmp.explicit_resources, &mut any_changed, map); + Type::ComponentInstance(tmp) + } + + Type::Resource(id) => { + let id = match map.resources.get(id).copied() { + Some(id) => id, + None => return false, + }; + any_changed = true; + Type::Resource(id) + } + + Type::ComponentFunc(i) => { + let mut tmp = i.clone(); + for ty in tmp + .params + .iter_mut() + .map(|(_, ty)| ty) + .chain(tmp.results.iter_mut().map(|(_, ty)| ty)) + { + if self.remap_valtype(ty, map) { + any_changed = true; + } + } + Type::ComponentFunc(tmp) + } + Type::Defined(i) => { + let mut tmp = i.clone(); + match &mut tmp { + ComponentDefinedType::Primitive(_) + | ComponentDefinedType::Flags(_) + | ComponentDefinedType::Enum(_) => {} + ComponentDefinedType::Record(r) => { + for ty in r.fields.values_mut() { + if self.remap_valtype(ty, map) { + any_changed = true; + } + } + } + ComponentDefinedType::Tuple(r) => { + for ty in r.types.iter_mut() { + if self.remap_valtype(ty, map) { + any_changed = true; + } + } + } + ComponentDefinedType::Variant(r) => { + for ty in r.cases.values_mut() { + if let Some(ty) = &mut ty.ty { + if self.remap_valtype(ty, map) { + any_changed = true; + } + } + } + } + ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + if self.remap_valtype(ty, map) { + any_changed = true; + } + } + ComponentDefinedType::Result { ok, err } => { + if let Some(ok) = ok { + if self.remap_valtype(ok, map) { + any_changed = true; + } + } + if let Some(err) = err { + if self.remap_valtype(err, map) { + any_changed = true; + } + } + } + ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => { + if self.remap_type_id(id, map) { + any_changed = true; + } + } + } + Type::Defined(tmp) + } + }; + + let new = if any_changed { self.push_ty(ty) } else { *id }; + let prev = map.types.insert(*id, new); + assert!(prev.is_none()); + let changed = *id != new; + *id = new; + changed + } + + /// Same as `remap_type_id`, but works with `ComponentEntityType`. + fn remap_component_entity( + &mut self, + ty: &mut ComponentEntityType, + map: &mut Remapping, + ) -> bool { + match ty { + ComponentEntityType::Module(id) + | ComponentEntityType::Func(id) + | ComponentEntityType::Instance(id) + | ComponentEntityType::Component(id) => self.remap_type_id(id, map), + ComponentEntityType::Type { + referenced, + created, + } => { + let changed = self.remap_type_id(referenced, map); + if *referenced == *created { + *created = *referenced; + changed + } else { + self.remap_type_id(created, map) || changed + } + } + ComponentEntityType::Value(ty) => self.remap_valtype(ty, map), + } + } + + /// Same as `remap_type_id`, but works with `ComponentValType`. + fn remap_valtype(&mut self, ty: &mut ComponentValType, map: &mut Remapping) -> bool { + match ty { + ComponentValType::Primitive(_) => false, + ComponentValType::Type(id) => self.remap_type_id(id, map), + } + } +} + +#[derive(Default)] +pub(crate) struct Remapping { + /// A mapping from old resource ID to new resource ID. + pub(crate) resources: HashMap, + + /// A mapping filled in during the remapping process which records how a + /// type was remapped, if applicable. This avoids remapping multiple + /// references to the same type and instead only processing it once. + types: HashMap, +} + +impl Remap for TypeAlloc { + fn push_ty(&mut self, ty: Type) -> TypeId { + ::push_ty(self, ty) + } +} + +impl Index for TypeAlloc { + type Output = Type; + + #[inline] + fn index(&self, id: TypeId) -> &Type { + &self.list[id] + } +} + +/// Helper structure used to perform subtyping computations. +/// +/// This type is used whenever a subtype needs to be tested in one direction or +/// the other. The methods of this type are the various entry points for +/// subtyping. +/// +/// Internally this contains arenas for two lists of types. The `a` arena is +/// intended to be used for lookup of the first argument to all of the methods +/// below, and the `b` arena is used for lookup of the second argument. +/// +/// Arenas here are used specifically for component-based subtyping queries. In +/// these situations new types must be created based on substitution mappings, +/// but the types all have temporary lifetimes. Everything in these arenas is +/// thrown away once the subtyping computation has finished. +/// +/// Note that this subtyping context also explicitly supports being created +/// from to different lists `a` and `b` originally, for testing subtyping +/// between two different components for example. +pub(crate) struct SubtypeCx<'a> { + pub(crate) a: SubtypeArena<'a>, + pub(crate) b: SubtypeArena<'a>, +} + +impl<'a> SubtypeCx<'a> { + pub(crate) fn new(a: &'a TypeList, b: &'a TypeList) -> SubtypeCx<'a> { + SubtypeCx { + a: SubtypeArena::new(a), + b: SubtypeArena::new(b), + } + } + + fn swap(&mut self) { + mem::swap(&mut self.a, &mut self.b); + } + + /// Executes the closure `f`, resetting the internal arenas to their + /// original size after the closure finishes. + /// + /// This enables `f` to modify the internal arenas while relying on all + /// changes being discarded after the closure finishes. + fn mark(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { + let a_len = self.a.list.len(); + let b_len = self.b.list.len(); + let result = f(self); + self.a.list.truncate(a_len); + self.b.list.truncate(b_len); + result + } + + /// Tests whether `a` is a subtype of `b`. + /// + /// Errors are reported at the `offset` specified. + pub fn component_entity_type( + &mut self, + a: &ComponentEntityType, + b: &ComponentEntityType, + offset: usize, + ) -> Result<()> { + use ComponentEntityType::*; + + match (a, b) { + (Module(a), Module(b)) => { + // For module type subtyping, all exports in the other module + // type must be present in this module type's exports (i.e. it + // can export *more* than what this module type needs). + // However, for imports, the check is reversed (i.e. it is okay + // to import *less* than what this module type needs). + self.swap(); + let a_imports = &self.b[*a].unwrap_module().imports; + let b_imports = &self.a[*b].unwrap_module().imports; + for (k, a) in a_imports { + match b_imports.get(k) { + Some(b) => self.entity_type(b, a, offset).with_context(|| { + format!("type mismatch in import `{}::{}`", k.0, k.1) + })?, + None => bail!(offset, "missing expected import `{}::{}`", k.0, k.1), + } + } + self.swap(); + let a = self.a[*a].unwrap_module(); + let b = self.b[*b].unwrap_module(); + for (k, b) in b.exports.iter() { + match a.exports.get(k) { + Some(a) => self + .entity_type(a, b, offset) + .with_context(|| format!("type mismatch in export `{k}`"))?, + None => bail!(offset, "missing expected export `{k}`"), + } + } + Ok(()) + } + (Module(_), b) => bail!(offset, "expected {}, found module", b.desc()), + + (Func(a), Func(b)) => { + let a = self.a[*a].unwrap_component_func(); + let b = self.b[*b].unwrap_component_func(); + + // Note that this intentionally diverges from the upstream + // specification in terms of subtyping. This is a full + // type-equality check which ensures that the structure of `a` + // exactly matches the structure of `b`. The rationale for this + // is: + // + // * Primarily in Wasmtime subtyping based on function types is + // not implemented. This includes both subtyping a host + // import and additionally handling subtyping as functions + // cross component boundaries. The host import subtyping (or + // component export subtyping) is not clear how to handle at + // all at this time. The subtyping of functions between + // components can more easily be handled by extending the + // `fact` compiler, but that hasn't been done yet. + // + // * The upstream specification is currently pretty + // intentionally vague precisely what subtyping is allowed. + // Implementing a strict check here is intended to be a + // conservative starting point for the component model which + // can be extended in the future if necessary. + // + // * The interaction with subtyping on bindings generation, for + // example, is a tricky problem that doesn't have a clear + // answer at this time. Effectively this is more rationale + // for being conservative in the first pass of the component + // model. + // + // So, in conclusion, the test here (and other places that + // reference this comment) is for exact type equality with no + // differences. + if a.params.len() != b.params.len() { + bail!( + offset, + "expected {} parameters, found {}", + b.params.len(), + a.params.len(), + ); + } + if a.results.len() != b.results.len() { + bail!( + offset, + "expected {} results, found {}", + b.results.len(), + a.results.len(), + ); + } + for ((an, a), (bn, b)) in a.params.iter().zip(b.params.iter()) { + if an != bn { + bail!(offset, "expected parameter named `{bn}`, found `{an}`"); + } + self.component_val_type(a, b, offset) + .with_context(|| format!("type mismatch in function parameter `{an}`"))?; + } + for ((an, a), (bn, b)) in a.results.iter().zip(b.results.iter()) { + if an != bn { + bail!(offset, "mismatched result names"); + } + self.component_val_type(a, b, offset) + .with_context(|| "type mismatch with result type")?; + } + Ok(()) + } + (Func(_), b) => bail!(offset, "expected {}, found func", b.desc()), + + (Value(a), Value(b)) => self.component_val_type(a, b, offset), + (Value(_), b) => bail!(offset, "expected {}, found value", b.desc()), + + (Type { referenced: a, .. }, Type { referenced: b, .. }) => { + use self::Type::*; + match (&self.a[*a], &self.b[*b]) { + (Defined(a), Defined(b)) => self.component_defined_type(a, b, offset), + (Defined(_), Resource(_)) => bail!(offset, "expected resource, found type"), + (Resource(a), Resource(b)) => { + if a == b { + Ok(()) + } else { + bail!(offset, "resource types are not the same") + } + } + (Resource(_), Defined(_)) => bail!(offset, "expected type, found resource"), + _ => unreachable!(), + } + } + (Type { .. }, b) => bail!(offset, "expected {}, found type", b.desc()), + + (Instance(a_id), Instance(b_id)) => { + // For instance type subtyping, all exports in the other + // instance type must be present in this instance type's + // exports (i.e. it can export *more* than what this instance + // type needs). + let a = self.a[*a_id].unwrap_component_instance(); + let b = self.b[*b_id].unwrap_component_instance(); + + let mut exports = Vec::with_capacity(b.exports.len()); + for (k, b) in b.exports.iter() { + match a.exports.get(k) { + Some(a) => exports.push((*a, *b)), + None => bail!(offset, "missing expected export `{k}`"), + } + } + for (i, (a, b)) in exports.iter().enumerate() { + let err = match self.component_entity_type(a, b, offset) { + Ok(()) => continue, + Err(e) => e, + }; + // On failure attach the name of this export as context to + // the error message to leave a breadcrumb trail. + let (name, _) = self.b[*b_id] + .unwrap_component_instance() + .exports + .get_index(i) + .unwrap(); + return Err( + err.with_context(|| format!("type mismatch in instance export `{name}`")) + ); + } + Ok(()) + } + (Instance(_), b) => bail!(offset, "expected {}, found instance", b.desc()), + + (Component(a), Component(b)) => { + // Components are ... tricky. They follow the same basic + // structure as core wasm modules, but they also have extra + // logic to handle resource types. Resources are effectively + // abstract types so this is sort of where an ML module system + // in the component model becomes a reality. + // + // This also leverages the `open_instance_type` method below + // heavily which internally has its own quite large suite of + // logic. More-or-less what's happening here is: + // + // 1. Pretend that the imports of B are given as values to the + // imports of A. If A didn't import anything, for example, + // that's great and the subtyping definitely passes there. + // This operation produces a mapping of all the resources of + // A's imports to resources in B's imports. + // + // 2. This mapping is applied to all of A's exports. This means + // that all exports of A referring to A's imported resources + // now instead refer to B's. Note, though that A's exports + // still refer to its own defined resources. + // + // 3. The same `open_instance_type` method used during the + // first step is used again, but this time on the exports + // in the reverse direction. This performs a similar + // operation, though, by creating a mapping from B's + // defined resources to A's defined resources. The map + // itself is discarded as it's not needed. + // + // The order that everything passed here is intentional, but + // also subtle. I personally think of it as + // `open_instance_type` takes a list of things to satisfy a + // signature and produces a mapping of resources in the + // signature to those provided in the list of things. The + // order of operations then goes: + // + // * Someone thinks they have a component of type B, but they + // actually have a component of type A (e.g. due to this + // subtype check passing). + // * This person provides the imports of B and that must be + // sufficient to satisfy the imports of A. This is the first + // `open_instance_type` check. + // * Now though the resources provided by B are substituted + // into A's exports since that's what was provided. + // * A's exports are then handed back to the original person, + // and these exports must satisfy the signature required by B + // since that's what they're expecting. + // * This is the second `open_instance_type` which, to get + // resource types to line up, will map from A's defined + // resources to B's defined resources. + // + // If all that passes then the resources should all line up + // perfectly. Any misalignment is reported as a subtyping + // error. + let b_imports = self.b[*b] + .unwrap_component() + .imports + .iter() + .map(|(name, ty)| (name.clone(), ty.clone())) + .collect(); + self.swap(); + let mut import_mapping = + self.open_instance_type(&b_imports, *a, ExternKind::Import, offset)?; + self.swap(); + self.mark(|this| { + let mut a_exports = this.a[*a] + .unwrap_component() + .exports + .iter() + .map(|(name, ty)| (name.clone(), ty.clone())) + .collect::>(); + for ty in a_exports.values_mut() { + this.a.remap_component_entity(ty, &mut import_mapping); + } + this.open_instance_type(&a_exports, *b, ExternKind::Export, offset)?; + Ok(()) + }) + } + (Component(_), b) => bail!(offset, "expected {}, found component", b.desc()), + } + } + + /// The building block for subtyping checks when components are + /// instantiated and when components are tested if they're subtypes of each + /// other. + /// + /// This method takes a number of arguments: + /// + /// * `a` - this is a list of typed items which can be thought of as + /// concrete values to test against `b`. + /// * `b` - this `TypeId` must point to `Type::Component`. + /// * `kind` - indicates whether the `imports` or `exports` of `b` are + /// being tested against for the values in `a`. + /// * `offset` - the binary offset at which to report errors if one happens. + /// + /// This will attempt to determine if the items in `a` satisfy the + /// signature required by the `kind` items of `b`. For example component + /// instantiation will have `a` as the list of arguments provided to + /// instantiation, `b` is the component being instantiated, and `kind` is + /// `ExternKind::Import`. + /// + /// This function, if successful, will return a mapping of the resources in + /// `b` to the resources in `a` provided. This mapping is guaranteed to + /// contain all the resources for `b` (all imported resources for + /// `ExternKind::Import` or all defined resources for `ExternKind::Export`). + pub fn open_instance_type( + &mut self, + a: &IndexMap, + b: TypeId, + kind: ExternKind, + offset: usize, + ) -> Result { + // First, determine the mapping from resources in `b` to those supplied + // by arguments in `a`. + // + // This loop will iterate over all the appropriate resources in `b` + // and find the corresponding resource in `args`. The exact lists + // in use here depend on the `kind` provided. This necessarily requires + // a sequence of string lookups to find the corresponding items in each + // list. + // + // The path to each resource in `resources` is precomputed as a list of + // indexes. The first index is into `b`'s list of `entities`, and gives + // the name that `b` assigns to the resource. Each subsequent index, + // if present, means that this resource was present through a layer of + // an instance type, and the index is into the instance type's exports. + // More information about this can be found on + // `ComponentState::imported_resources`. + // + // This loop will follow the list of indices for each resource and, at + // the same time, walk through the arguments supplied to instantiating + // the `component_type`. This means that within `component_type` + // index-based lookups are performed while in `args` name-based + // lookups are performed. + // + // Note that here it's possible that `args` doesn't actually supply the + // correct type of import for each item since argument checking has + // not proceeded yet. These type errors, however, aren't handled by + // this loop and are deferred below to the main subtyping check. That + // means that `mapping` won't necessarily have a mapping for all + // imported resources into `component_type`, but that should be ok. + let component_type = self.b[b].unwrap_component(); + let entities = match kind { + ExternKind::Import => &component_type.imports, + ExternKind::Export => &component_type.exports, + }; + let resources = match kind { + ExternKind::Import => &component_type.imported_resources, + ExternKind::Export => &component_type.defined_resources, + }; + let mut mapping = Remapping::default(); + 'outer: for (resource, path) in resources.iter() { + // Lookup the first path item in `imports` and the corresponding + // entry in `args` by name. + let (name, ty) = entities.get_index(path[0]).unwrap(); + let mut ty = *ty; + let mut arg = a.get(name); + + // Lookup all the subsequent `path` entries, if any, by index in + // `ty` and by name in `arg`. Type errors in `arg` are skipped over + // entirely. + for i in path.iter().skip(1).copied() { + let id = match ty { + ComponentEntityType::Instance(id) => id, + _ => unreachable!(), + }; + let (name, next_ty) = self.b[id] + .unwrap_component_instance() + .exports + .get_index(i) + .unwrap(); + ty = *next_ty; + arg = match arg { + Some(ComponentEntityType::Instance(id)) => { + self.a[*id].unwrap_component_instance().exports.get(name) + } + _ => continue 'outer, + }; + } + + // Double-check that `ty`, the leaf type of `component_type`, is + // indeed the expected resource. + if cfg!(debug_assertions) { + let id = match ty { + ComponentEntityType::Type { created, .. } => match &self.a[created] { + Type::Resource(r) => *r, + _ => unreachable!(), + }, + _ => unreachable!(), + }; + assert_eq!(id, *resource); + } + + // The leaf of `arg` should be a type which is a resource. If not + // it's skipped and this'll wind up generating an error later on in + // subtype checking below. + if let Some(ComponentEntityType::Type { created, .. }) = arg { + if let Type::Resource(r) = &self.b[*created] { + mapping.resources.insert(*resource, *r); + } + } + } + + // Now that a mapping from the resources in `b` to the resources in `a` + // has been determined it's possible to perform the actual subtype + // check. + // + // This subtype check notably needs to ensure that all resource types + // line up. To achieve this the `mapping` previously calculated is used + // to perform a substitution on each component entity type. + // + // The first loop here performs a name lookup to create a list of + // values from `a` to expected items in `b`. Once the list is created + // the substitution check is performed on each element. + let mut to_typecheck = Vec::new(); + for (name, expected) in entities.iter() { + match a.get(name) { + Some(arg) => to_typecheck.push((arg.clone(), expected.clone())), + None => bail!(offset, "missing {} named `{name}`", kind.desc()), + } + } + let mut type_map = HashMap::new(); + for (i, (actual, expected)) in to_typecheck.into_iter().enumerate() { + let result = self.mark(|this| { + let mut expected = expected; + this.b.remap_component_entity(&mut expected, &mut mapping); + mapping.types.clear(); + this.component_entity_type(&actual, &expected, offset) + }); + let err = match result { + Ok(()) => { + // On a successful type-check record a mapping of + // type-to-type in `type_map` for any type imports that were + // satisfied. This is then used afterwards when performing + // type substitution to remap all component-local types to + // those that were provided in the imports. + self.register_type_renamings(actual, expected, &mut type_map); + continue; + } + Err(e) => e, + }; + + // If an error happens then attach the name of the entity to the + // error message using the `i` iteration counter. + let component_type = self.b[b].unwrap_component(); + let entities = match kind { + ExternKind::Import => &component_type.imports, + ExternKind::Export => &component_type.exports, + }; + let (name, _) = entities.get_index(i).unwrap(); + return Err(err.with_context(|| format!("type mismatch for {} `{name}`", kind.desc()))); + } + mapping.types = type_map; + Ok(mapping) + } + + pub(crate) fn entity_type(&self, a: &EntityType, b: &EntityType, offset: usize) -> Result<()> { + macro_rules! limits_match { + ($a:expr, $b:expr) => {{ + let a = $a; + let b = $b; + a.initial >= b.initial + && match b.maximum { + Some(b_max) => match a.maximum { + Some(a_max) => a_max <= b_max, + None => false, + }, + None => true, + } + }}; + } + + match (a, b) { + (EntityType::Func(a), EntityType::Func(b)) => { + self.func_type(self.a[*a].unwrap_func(), self.b[*b].unwrap_func(), offset) + } + (EntityType::Func(_), b) => bail!(offset, "expected {}, found func", b.desc()), + (EntityType::Table(a), EntityType::Table(b)) => { + if a.element_type != b.element_type { + bail!( + offset, + "expected table element type {}, found {}", + b.element_type, + a.element_type, + ) + } + if limits_match!(a, b) { + Ok(()) + } else { + bail!(offset, "mismatch in table limits") + } + } + (EntityType::Table(_), b) => bail!(offset, "expected {}, found table", b.desc()), + (EntityType::Memory(a), EntityType::Memory(b)) => { + if a.shared != b.shared { + bail!(offset, "mismatch in the shared flag for memories") + } + if a.memory64 != b.memory64 { + bail!(offset, "mismatch in index type used for memories") + } + if limits_match!(a, b) { + Ok(()) + } else { + bail!(offset, "mismatch in memory limits") + } + } + (EntityType::Memory(_), b) => bail!(offset, "expected {}, found memory", b.desc()), + (EntityType::Global(a), EntityType::Global(b)) => { + if a.mutable != b.mutable { + bail!(offset, "global types differ in mutability") + } + if a.content_type == b.content_type { + Ok(()) + } else { + bail!( + offset, + "expected global type {}, found {}", + b.content_type, + a.content_type, + ) + } + } + (EntityType::Global(_), b) => bail!(offset, "expected {}, found global", b.desc()), + (EntityType::Tag(a), EntityType::Tag(b)) => { + self.func_type(self.a[*a].unwrap_func(), self.b[*b].unwrap_func(), offset) + } + (EntityType::Tag(_), b) => bail!(offset, "expected {}, found tag", b.desc()), + } + } + + fn func_type(&self, a: &FuncType, b: &FuncType, offset: usize) -> Result<()> { + if a == b { + Ok(()) + } else { + bail!( + offset, + "expected: {}\n\ + found: {}", + b.desc(), + a.desc(), + ) + } + } + + pub(crate) fn component_val_type( + &self, + a: &ComponentValType, + b: &ComponentValType, + offset: usize, + ) -> Result<()> { + match (a, b) { + (ComponentValType::Primitive(a), ComponentValType::Primitive(b)) => { + self.primitive_val_type(*a, *b, offset) + } + (ComponentValType::Type(a), ComponentValType::Type(b)) => self.component_defined_type( + self.a[*a].unwrap_defined(), + self.b[*b].unwrap_defined(), + offset, + ), + (ComponentValType::Primitive(a), ComponentValType::Type(b)) => { + match self.b[*b].unwrap_defined() { + ComponentDefinedType::Primitive(b) => self.primitive_val_type(*a, *b, offset), + b => bail!(offset, "expected {}, found {a}", b.desc()), + } + } + (ComponentValType::Type(a), ComponentValType::Primitive(b)) => { + match self.a[*a].unwrap_defined() { + ComponentDefinedType::Primitive(a) => self.primitive_val_type(*a, *b, offset), + a => bail!(offset, "expected {b}, found {}", a.desc()), + } + } + } + } + + fn component_defined_type( + &self, + a: &ComponentDefinedType, + b: &ComponentDefinedType, + offset: usize, + ) -> Result<()> { + use ComponentDefinedType::*; + + // Note that the implementation of subtyping here diverges from the + // upstream specification intentionally, see the documentation on + // function subtyping for more information. + match (a, b) { + (Primitive(a), Primitive(b)) => self.primitive_val_type(*a, *b, offset), + (Primitive(a), b) => bail!(offset, "expected {}, found {a}", b.desc()), + (Record(a), Record(b)) => { + if a.fields.len() != b.fields.len() { + bail!( + offset, + "expected {} fields, found {}", + b.fields.len(), + a.fields.len(), + ); + } + + for ((aname, a), (bname, b)) in a.fields.iter().zip(b.fields.iter()) { + if aname != bname { + bail!(offset, "expected field name `{bname}`, found `{aname}`"); + } + self.component_val_type(a, b, offset) + .with_context(|| format!("type mismatch in record field `{aname}`"))?; + } + Ok(()) + } + (Record(_), b) => bail!(offset, "expected {}, found record", b.desc()), + (Variant(a), Variant(b)) => { + if a.cases.len() != b.cases.len() { + bail!( + offset, + "expected {} cases, found {}", + b.cases.len(), + a.cases.len(), + ); + } + for ((aname, a), (bname, b)) in a.cases.iter().zip(b.cases.iter()) { + if aname != bname { + bail!(offset, "expected case named `{bname}`, found `{aname}`"); + } + match (&a.ty, &b.ty) { + (Some(a), Some(b)) => self + .component_val_type(a, b, offset) + .with_context(|| format!("type mismatch in variant case `{aname}`"))?, + (None, None) => {} + (None, Some(_)) => { + bail!(offset, "expected case `{aname}` to have a type, found none") + } + (Some(_), None) => bail!(offset, "expected case `{aname}` to have no type"), + } + } + Ok(()) + } + (Variant(_), b) => bail!(offset, "expected {}, found variant", b.desc()), + (List(a), List(b)) | (Option(a), Option(b)) => self.component_val_type(a, b, offset), + (List(_), b) => bail!(offset, "expected {}, found list", b.desc()), + (Option(_), b) => bail!(offset, "expected {}, found option", b.desc()), + (Tuple(a), Tuple(b)) => { + if a.types.len() != b.types.len() { + bail!( + offset, + "expected {} types, found {}", + b.types.len(), + a.types.len(), + ); + } + for (i, (a, b)) in a.types.iter().zip(b.types.iter()).enumerate() { + self.component_val_type(a, b, offset) + .with_context(|| format!("type mismatch in tuple field {i}"))?; + } + Ok(()) + } + (Tuple(_), b) => bail!(offset, "expected {}, found tuple", b.desc()), + (at @ Flags(a), Flags(b)) | (at @ Enum(a), Enum(b)) => { + let desc = match at { + Flags(_) => "flags", + _ => "enum", + }; + if a.len() == b.len() && a.iter().eq(b.iter()) { + Ok(()) + } else { + bail!(offset, "mismatch in {desc} elements") + } + } + (Flags(_), b) => bail!(offset, "expected {}, found flags", b.desc()), + (Enum(_), b) => bail!(offset, "expected {}, found enum", b.desc()), + (Result { ok: ao, err: ae }, Result { ok: bo, err: be }) => { + match (ao, bo) { + (None, None) => {} + (Some(a), Some(b)) => self + .component_val_type(a, b, offset) + .with_context(|| "type mismatch in ok variant")?, + (None, Some(_)) => bail!(offset, "expected ok type, but found none"), + (Some(_), None) => bail!(offset, "expected ok type to not be present"), + } + match (ae, be) { + (None, None) => {} + (Some(a), Some(b)) => self + .component_val_type(a, b, offset) + .with_context(|| "type mismatch in err variant")?, + (None, Some(_)) => bail!(offset, "expected err type, but found none"), + (Some(_), None) => bail!(offset, "expected err type to not be present"), + } + Ok(()) + } + (Result { .. }, b) => bail!(offset, "expected {}, found result", b.desc()), + (Own(a), Own(b)) | (Borrow(a), Borrow(b)) => { + let a = self.a[*a].unwrap_resource(); + let b = self.b[*b].unwrap_resource(); + if a == b { + Ok(()) + } else { + bail!(offset, "resource types are not the same") + } + } + (Own(_), b) => bail!(offset, "expected {}, found own", b.desc()), + (Borrow(_), b) => bail!(offset, "expected {}, found borrow", b.desc()), + } + } + + fn primitive_val_type( + &self, + a: PrimitiveValType, + b: PrimitiveValType, + offset: usize, + ) -> Result<()> { + // Note that this intentionally diverges from the upstream specification + // at this time and only considers exact equality for subtyping + // relationships. + // + // More information can be found in the subtyping implementation for + // component functions. + if a == b { + Ok(()) + } else { + bail!(offset, "expected primitive `{b}` found primitive `{a}`") + } + } + + fn register_type_renamings( + &self, + actual: ComponentEntityType, + expected: ComponentEntityType, + type_map: &mut HashMap, + ) { + match (expected, actual) { + ( + ComponentEntityType::Type { + created: expected, .. + }, + ComponentEntityType::Type { + created: actual, .. + }, + ) => { + let prev = type_map.insert(expected, actual); + assert!(prev.is_none()); + } + (ComponentEntityType::Instance(expected), ComponentEntityType::Instance(actual)) => { + let actual = self.a[actual].unwrap_component_instance(); + for (name, expected) in self.b[expected].unwrap_component_instance().exports.iter() + { + let actual = actual.exports[name]; + self.register_type_renamings(actual, *expected, type_map); + } + } + _ => {} + } + } +} + +/// A helper typed used purely during subtyping as part of `SubtypeCx`. +/// +/// This takes a `types` list as input which is the "base" of the ids that can +/// be indexed through this arena. All future types pushed into this, if any, +/// are stored in `self.list`. +/// +/// This is intended to have arena-like behavior where everything pushed onto +/// `self.list` is thrown away after a subtyping computation is performed. All +/// new types pushed into this arena are purely temporary. +pub(crate) struct SubtypeArena<'a> { + types: &'a TypeList, + list: Vec, +} + +impl<'a> SubtypeArena<'a> { + fn new(types: &'a TypeList) -> SubtypeArena<'a> { + SubtypeArena { + types, + list: Vec::new(), + } + } +} + +impl Index for SubtypeArena<'_> { + type Output = Type; + + fn index(&self, id: TypeId) -> &Type { + if id.index() < self.types.len() { + &self.types[id] + } else { + &self.list[id.index() - self.types.len()] + } + } +} + +impl Remap for SubtypeArena<'_> { + fn push_ty(&mut self, ty: Type) -> TypeId { + let index = self.list.len() + self.types.len(); + let index = u32::try_from(index).unwrap(); + self.list.push(ty); + TypeId { + index, + unique_id: 0, + } + } +} + +/// Helper trait for adding contextual information to an error, modeled after +/// `anyhow::Context`. +pub(crate) trait Context { + fn with_context(self, context: impl FnOnce() -> S) -> Self + where + S: Into; +} + +impl Context for Result { + fn with_context(self, context: impl FnOnce() -> S) -> Self + where + S: Into, + { + match self { + Ok(val) => Ok(val), + Err(e) => Err(e.with_context(context)), + } + } +} + +impl Context for BinaryReaderError { + fn with_context(mut self, context: impl FnOnce() -> S) -> Self + where + S: Into, + { + self.add_context(context().into()); + self + } +} diff --git a/crates/wasmparser/tests/big-module.rs b/crates/wasmparser/tests/big-module.rs new file mode 100644 index 0000000000..06cf02d630 --- /dev/null +++ b/crates/wasmparser/tests/big-module.rs @@ -0,0 +1,33 @@ +use wasm_encoder::*; + +#[test] +fn big_type_indices() { + const N: u32 = 100_000; + let mut module = Module::new(); + let mut types = TypeSection::new(); + for _ in 0..N { + types.function([], []); + } + module.section(&types); + let mut funcs = FunctionSection::new(); + funcs.function(N - 1); + module.section(&funcs); + + let mut elems = ElementSection::new(); + elems.declared(Elements::Functions(&[0])); + module.section(&elems); + + let mut code = CodeSection::new(); + let mut body = Function::new([]); + body.instruction(&Instruction::RefFunc(0)); + body.instruction(&Instruction::Drop); + body.instruction(&Instruction::End); + code.function(&body); + module.section(&code); + + let wasm = module.finish(); + + wasmparser::Validator::default() + .validate_all(&wasm) + .unwrap(); +} diff --git a/crates/wasmprinter/Cargo.toml b/crates/wasmprinter/Cargo.toml index b78352bde5..5c9acdfddf 100644 --- a/crates/wasmprinter/Cargo.toml +++ b/crates/wasmprinter/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "wasmprinter" -version = "0.2.39" +version = "0.2.70" authors = ["Alex Crichton "] -edition = "2021" +edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" readme = "README.md" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmprinter" @@ -13,13 +13,12 @@ Rust converter from the WebAssembly binary format to the text format. """ [dependencies] -anyhow = "1.0" -wasmparser = { path = '../wasmparser', version = '0.90.0' } +anyhow = { workspace = true } +wasmparser = { workspace = true } [dev-dependencies] diff = "0.1" -getopts = "0.2" -rayon = "1.0" +rayon = { workspace = true } tempfile = "3.0" wat = { path = "../wat" } wast = { path = "../wast" } diff --git a/crates/wasmprinter/README.md b/crates/wasmprinter/README.md index ee31c4cd2c..fe9dc460c5 100644 --- a/crates/wasmprinter/README.md +++ b/crates/wasmprinter/README.md @@ -16,11 +16,10 @@ ## Usage -This crate is published on `crates.io`, so you can depend on it with: +Add `wasmprinter` to your `Cargo.toml` -```toml -[dependencies] -wasmprinter = "0.2.0" +```sh +$ cargo add wasmprinter ``` You can then convert wasm binaries to strings like so: diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 4bd37249a5..1fa393b7b0 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -42,8 +42,13 @@ pub fn print_bytes(wasm: impl AsRef<[u8]>) -> Result { #[derive(Default)] pub struct Printer { print_offsets: bool, + print_skeleton: bool, printers: HashMap Result<()>>>, result: String, + /// The `i`th line in `result` is at offset `lines[i]`. + lines: Vec, + /// The binary offset for the `i`th line is `line_offsets[i]`. + line_offsets: Vec>, nesting: u32, line: usize, group_lines: Vec, @@ -51,7 +56,7 @@ pub struct Printer { #[derive(Default)] struct CoreState { - types: Vec>, + types: Vec>, funcs: u32, memories: u32, tags: u32, @@ -123,6 +128,12 @@ impl Printer { self.print_offsets = print; } + /// Whether or not to print only a "skeleton" which skips function bodies, + /// data segment contents, element segment contents, etc. + pub fn print_skeleton(&mut self, print: bool) { + self.print_skeleton = print; + } + /// Registers a custom `printer` function to get invoked whenever a custom /// section of name `section` is seen. /// @@ -160,6 +171,29 @@ impl Printer { Ok(mem::take(&mut self.result)) } + /// Get the line-by-line WAT disassembly for the given Wasm, along with the + /// binary offsets for each line. + pub fn offsets_and_lines<'a>( + &'a mut self, + wasm: &[u8], + ) -> Result, &'a str)> + 'a> { + self.print_contents(wasm)?; + + let end = self.result.len(); + let result = &self.result; + + let mut offsets = self.line_offsets.iter().copied(); + let mut lines = self.lines.iter().copied().peekable(); + + Ok(std::iter::from_fn(move || { + let offset = offsets.next()?; + let i = lines.next()?; + let j = lines.peek().copied().unwrap_or(end); + let line = &result[i..j]; + Some((offset, line)) + })) + } + fn read_names_and_code<'a>( &mut self, mut bytes: &'a [u8], @@ -178,14 +212,14 @@ impl Printer { match payload { Payload::FunctionSection(s) => { - if s.get_count() > MAX_WASM_FUNCTIONS { + if s.count() > MAX_WASM_FUNCTIONS { bail!( "module contains {} functions which exceeds the limit of {}", - s.get_count(), + s.count(), MAX_WASM_FUNCTIONS ); } - code.reserve(s.get_count() as usize); + code.reserve(s.count() as usize); } Payload::CodeSectionEntry(f) => { code.push(f); @@ -197,12 +231,17 @@ impl Printer { } bytes = &bytes[offset..]; } - Payload::CustomSection(c) if c.name() == "name" => { - let reader = NameSectionReader::new(c.data(), c.data_offset())?; - // Ignore any error associated with the name section. + // Ignore any error associated with the name sections. + Payload::CustomSection(c) if c.name() == "name" => { + let reader = NameSectionReader::new(c.data(), c.data_offset()); drop(self.register_names(state, reader)); } + Payload::CustomSection(c) if c.name() == "component-name" => { + let reader = ComponentNameSectionReader::new(c.data(), c.data_offset()); + drop(self.register_component_names(state, reader)); + } + Payload::End(_) => break, _ => {} } @@ -228,6 +267,11 @@ impl Printer { } fn print_contents(&mut self, mut bytes: &[u8]) -> Result<()> { + self.lines.clear(); + self.lines.push(0); + self.line_offsets.clear(); + self.line_offsets.push(Some(0)); + let mut expected = None; let mut states: Vec = Vec::new(); let mut parser = Parser::new(0); @@ -284,6 +328,7 @@ impl Printer { } } + let len = states.len(); let state = states.last_mut().unwrap(); // First up try to find the `name` subsection which we'll use to print @@ -293,17 +338,47 @@ impl Printer { code_printed = false; self.read_names_and_code(bytes, parser.clone(), state, &mut code)?; - if let Some(name) = state.name.as_ref() { - self.result.push(' '); - name.write(&mut self.result); + if len == 1 { + if let Some(name) = state.name.as_ref() { + self.result.push(' '); + name.write(&mut self.result); + } } } Payload::CustomSection(c) => { + let mut printed = false; let mut printers = mem::take(&mut self.printers); if let Some(printer) = printers.get_mut(c.name()) { printer(self, c.data_offset(), c.data())?; + printed = true; } self.printers = printers; + + // Attempt to print this custom section if it wasn't already + // handled specifically above. Note that custom sections are + // allowed to be invalid, so any parse error here is ignored + // and resets the output to what it was when this started. + // Otherwise I/O errors and other things are plumbed through + // in case they happen. + if printed { + continue; + } + let cur = self.result.len(); + let err = match self.print_custom_section(c.clone()) { + Ok(()) => continue, + Err(e) => e, + }; + if !err.is::() { + return Err(err); + } + self.result.truncate(cur); + let msg = format!("failed to parse custom section `{}`: {err}", c.name()); + for line in msg.lines() { + self.newline(c.data_offset()); + self.result.push_str(";; "); + self.result.push_str(line); + } + self.newline(c.range().end); } Payload::TypeSection(s) => self.print_types(states.last_mut().unwrap(), s)?, Payload::ImportSection(s) => { @@ -315,7 +390,7 @@ impl Printer { if mem::replace(&mut code_printed, true) { bail!("function section appeared twice in module"); } - if reader.get_count() == 0 { + if reader.count() == 0 { continue; } self.print_code(states.last_mut().unwrap(), &code, reader)?; @@ -409,9 +484,9 @@ impl Printer { Self::ensure_component(&states)?; self.print_canonical_functions(states.last_mut().unwrap(), s)?; } - Payload::ComponentStartSection(s) => { + Payload::ComponentStartSection { start, range } => { Self::ensure_component(&states)?; - self.print_component_start(states.last_mut().unwrap(), s)?; + self.print_component_start(states.last_mut().unwrap(), range.start, start)?; } Payload::ComponentImportSection(s) => { Self::ensure_component(&states)?; @@ -466,34 +541,24 @@ impl Printer { } fn register_names(&mut self, state: &mut State, names: NameSectionReader<'_>) -> Result<()> { - fn name_map(into: &mut HashMap, names: NameMap<'_>, name: &str) -> Result<()> { - let mut used = HashSet::new(); - let mut map = names.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; - into.insert( - naming.index, - Naming::new(naming.name, naming.index, name, &mut used), - ); - } - Ok(()) - } - fn indirect_name_map( into: &mut HashMap<(u32, u32), Naming>, names: IndirectNameMap<'_>, name: &str, ) -> Result<()> { - let mut outer_map = names.get_indirect_map()?; - for _ in 0..outer_map.get_indirect_count() { - let mut used = HashSet::new(); - let outer = outer_map.read()?; - let mut inner_map = outer.get_map()?; - for _ in 0..inner_map.get_count() { - let inner = inner_map.read()?; + for indirect in names { + let indirect = indirect?; + let mut used = match name { + // labels can be shadowed, so maintaining the used names is not useful. + "label" => None, + "local" => Some(HashSet::new()), + _ => unimplemented!("{name} is an unknown type of indirect names"), + }; + for naming in indirect.names { + let naming = naming?; into.insert( - (outer.indirect_index, inner.index), - Naming::new(inner.name, inner.index, name, &mut used), + (indirect.index, naming.index), + Naming::new(naming.name, naming.index, name, used.as_mut()), ); } } @@ -502,8 +567,8 @@ impl Printer { for section in names { match section? { - Name::Module(n) => { - let name = Naming::new(n.get_name()?, 0, "module", &mut HashSet::new()); + Name::Module { name, .. } => { + let name = Naming::new(name, 0, "module", None); state.name = Some(name); } Name::Function(n) => name_map(&mut state.core.func_names, n, "func")?, @@ -521,21 +586,72 @@ impl Printer { Ok(()) } - fn print_core_type(&mut self, states: &mut Vec, ty: wasmparser::CoreType) -> Result<()> { + fn register_component_names( + &mut self, + state: &mut State, + names: ComponentNameSectionReader<'_>, + ) -> Result<()> { + for section in names { + match section? { + ComponentName::Component { name, .. } => { + let name = Naming::new(name, 0, "component", None); + state.name = Some(name); + } + ComponentName::CoreFuncs(n) => { + name_map(&mut state.core.func_names, n, "core-func")? + } + ComponentName::CoreTypes(n) => { + name_map(&mut state.core.type_names, n, "core-type")? + } + ComponentName::CoreTables(n) => { + name_map(&mut state.core.table_names, n, "core-table")? + } + ComponentName::CoreMemories(n) => { + name_map(&mut state.core.memory_names, n, "core-memory")? + } + ComponentName::CoreGlobals(n) => { + name_map(&mut state.core.global_names, n, "core-global")? + } + ComponentName::CoreModules(n) => { + name_map(&mut state.core.module_names, n, "core-module")? + } + ComponentName::CoreInstances(n) => { + name_map(&mut state.core.instance_names, n, "core-instance")? + } + ComponentName::Types(n) => name_map(&mut state.component.type_names, n, "type")?, + ComponentName::Instances(n) => { + name_map(&mut state.component.instance_names, n, "instance")? + } + ComponentName::Components(n) => { + name_map(&mut state.component.component_names, n, "component")? + } + ComponentName::Funcs(n) => name_map(&mut state.component.func_names, n, "func")?, + ComponentName::Values(n) => name_map(&mut state.component.value_names, n, "value")?, + ComponentName::Unknown { .. } => (), + } + } + Ok(()) + } + + fn print_core_type(&mut self, states: &mut Vec, ty: CoreType) -> Result<()> { self.start_group("core type "); self.print_name( &states.last().unwrap().core.type_names, states.last().unwrap().core.types.len() as u32, )?; - self.result.push(' '); let ty = match ty { - wasmparser::CoreType::Func(ty) => { + CoreType::Func(ty) => { + self.result.push(' '); self.start_group("func"); self.print_func_type(states.last().unwrap(), &ty, None)?; self.end_group(); - Some(ty) + Some(SubType { + is_final: true, + supertype_idx: None, + structural_type: StructuralType::Func(ty), + }) } - wasmparser::CoreType::Module(decls) => { + CoreType::Module(decls) => { self.print_module_type(states, decls.into_vec())?; None } @@ -546,21 +662,66 @@ impl Printer { Ok(()) } - fn print_type(&mut self, state: &mut State, ty: wasmparser::Type) -> Result<()> { + fn print_rec(&mut self, state: &mut State, offset: usize, types: Vec) -> Result<()> { + self.start_group("rec"); + for ty in types { + self.newline(offset + 2); + self.print_type(state, ty)?; + } + self.end_group(); // `rec` + Ok(()) + } + + fn print_type(&mut self, state: &mut State, ty: SubType) -> Result<()> { self.start_group("type "); self.print_name(&state.core.type_names, state.core.types.len() as u32)?; self.result.push(' '); - let ty = match ty { - wasmparser::Type::Func(ty) => { + self.print_sub(state, &ty, None)?; + self.end_group(); // `type` + state.core.types.push(Some(ty)); + Ok(()) + } + + fn print_sub(&mut self, state: &State, ty: &SubType, names_for: Option) -> Result { + let r = if !ty.is_final || !ty.supertype_idx.is_none() { + self.start_group("sub"); + self.print_sub_type(state, ty)?; + let r = self.print_structural(state, &ty.structural_type, names_for)?; + self.end_group(); // `sub` + r + } else { + self.print_structural(state, &ty.structural_type, names_for)? + }; + Ok(r) + } + + fn print_structural( + &mut self, + state: &State, + ty: &StructuralType, + names_for: Option, + ) -> Result { + let r = match &ty { + StructuralType::Func(ty) => { self.start_group("func"); - self.print_func_type(state, &ty, None)?; - self.end_group(); - ty + let r = self.print_func_type(state, ty, names_for)?; + self.end_group(); // `func` + r + } + StructuralType::Array(ty) => { + self.start_group("array"); + let r = self.print_array_type(ty)?; + self.end_group(); // `array` + r + } + StructuralType::Struct(ty) => { + self.start_group("struct"); + let r = self.print_struct_type(ty)?; + self.end_group(); // `struct` + r } }; - self.end_group(); // `type` itself - state.core.types.push(Some(ty)); - Ok(()) + Ok(r) } fn print_core_types( @@ -579,9 +740,12 @@ impl Printer { fn print_types(&mut self, state: &mut State, parser: TypeSectionReader<'_>) -> Result<()> { for ty in parser.into_iter_with_offsets() { - let (offset, ty) = ty?; + let (offset, rec_group) = ty?; self.newline(offset); - self.print_type(state, ty)?; + match rec_group { + RecGroup::Many(items) => self.print_rec(state, offset, items)?, + RecGroup::Single(ty) => self.print_type(state, ty)?, + } } Ok(()) @@ -591,21 +755,16 @@ impl Printer { &mut self, state: &State, idx: u32, - always_print_type: bool, names_for: Option, ) -> Result> { - if always_print_type { - self.print_type_ref(state, idx, true, None)?; - } + self.print_core_type_ref(state, idx)?; match state.core.types.get(idx as usize) { - Some(Some(ty)) => self.print_func_type(state, ty, names_for).map(Some), - Some(None) | None => { - if !always_print_type { - self.print_type_ref(state, idx, true, None)?; - } - Ok(None) - } + Some(Some(SubType { + structural_type: StructuralType::Func(ty), + .. + })) => self.print_func_type(state, ty, names_for).map(Some), + Some(Some(_)) | Some(None) | None => Ok(None), } } @@ -643,6 +802,52 @@ impl Printer { Ok(ty.params().len() as u32) } + fn print_field_type(&mut self, ty: &FieldType) -> Result { + self.result.push(' '); + if ty.mutable { + self.result.push_str("(mut "); + } + self.print_storage_type(ty.element_type)?; + if ty.mutable { + self.result.push_str(")"); + } + Ok(0) + } + + fn print_array_type(&mut self, ty: &ArrayType) -> Result { + self.print_field_type(&ty.0) + } + + fn print_struct_type(&mut self, ty: &StructType) -> Result { + for field in ty.fields.iter() { + self.result.push_str(" (field"); + self.print_field_type(field)?; + self.result.push(')'); + } + Ok(0) + } + + fn print_sub_type(&mut self, state: &State, ty: &SubType) -> Result { + self.result.push(' '); + if ty.is_final { + self.result.push_str("final "); + } + for idx in &ty.supertype_idx { + self.print_name(&state.core.type_names, *idx)?; + self.result.push(' '); + } + Ok(0) + } + + fn print_storage_type(&mut self, ty: StorageType) -> Result<()> { + match ty { + StorageType::I8 => self.result.push_str("i8"), + StorageType::I16 => self.result.push_str("i16"), + StorageType::Val(val_type) => self.print_valtype(val_type)?, + } + Ok(()) + } + fn print_valtype(&mut self, ty: ValType) -> Result<()> { match ty { ValType::I32 => self.result.push_str("i32"), @@ -650,17 +855,51 @@ impl Printer { ValType::F32 => self.result.push_str("f32"), ValType::F64 => self.result.push_str("f64"), ValType::V128 => self.result.push_str("v128"), - ValType::FuncRef => self.result.push_str("funcref"), - ValType::ExternRef => self.result.push_str("externref"), + ValType::Ref(rt) => self.print_reftype(rt)?, } Ok(()) } - fn print_reftype(&mut self, ty: ValType) -> Result<()> { + fn print_reftype(&mut self, ty: RefType) -> Result<()> { + if ty.is_nullable() { + match ty.as_non_null() { + RefType::FUNC => self.result.push_str("funcref"), + RefType::EXTERN => self.result.push_str("externref"), + RefType::I31 => self.result.push_str("i31ref"), + RefType::ANY => self.result.push_str("anyref"), + RefType::NONE => self.result.push_str("nullref"), + RefType::NOEXTERN => self.result.push_str("nullexternref"), + RefType::NOFUNC => self.result.push_str("nullfuncref"), + RefType::EQ => self.result.push_str("eqref"), + RefType::STRUCT => self.result.push_str("structref"), + RefType::ARRAY => self.result.push_str("arrayref"), + _ => { + self.result.push_str("(ref null "); + self.print_heaptype(ty.heap_type())?; + self.result.push_str(")"); + } + } + } else { + self.result.push_str("(ref "); + self.print_heaptype(ty.heap_type())?; + self.result.push_str(")"); + } + Ok(()) + } + + fn print_heaptype(&mut self, ty: HeapType) -> Result<()> { match ty { - ValType::FuncRef => self.result.push_str("func"), - ValType::ExternRef => self.result.push_str("extern"), - _ => bail!("invalid reference type {:?}", ty), + HeapType::Func => self.result.push_str("func"), + HeapType::Extern => self.result.push_str("extern"), + HeapType::Any => self.result.push_str("any"), + HeapType::None => self.result.push_str("none"), + HeapType::NoExtern => self.result.push_str("noextern"), + HeapType::NoFunc => self.result.push_str("nofunc"), + HeapType::Eq => self.result.push_str("eq"), + HeapType::Struct => self.result.push_str("struct"), + HeapType::Array => self.result.push_str("array"), + HeapType::I31 => self.result.push_str("i31"), + HeapType::Indexed(i) => self.result.push_str(&format!("{}", u32::from(i))), } Ok(()) } @@ -695,12 +934,12 @@ impl Printer { fn print_import_ty(&mut self, state: &State, ty: &TypeRef, index: bool) -> Result<()> { match ty { TypeRef::Func(f) => { - self.start_group("func"); + self.start_group("func "); if index { - self.result.push(' '); self.print_name(&state.core.func_names, state.core.funcs)?; + self.result.push(' '); } - self.print_type_ref(state, *f, true, None)?; + self.print_core_type_ref(state, *f)?; } TypeRef::Table(f) => self.print_table_type(state, f, index)?, TypeRef::Memory(f) => self.print_memory_type(state, f, index)?, @@ -719,7 +958,7 @@ impl Printer { } self.print_limits(ty.initial, ty.maximum)?; self.result.push(' '); - self.print_valtype(ty.element_type)?; + self.print_reftype(ty.element_type)?; Ok(()) } @@ -742,9 +981,9 @@ impl Printer { fn print_tag_type(&mut self, state: &State, ty: &TagType, index: bool) -> Result<()> { self.start_group("tag "); if index { - write!(self.result, "(;{};)", state.core.tags)?; + write!(self.result, "(;{};) ", state.core.tags)?; } - self.print_core_functype_idx(state, ty.func_type_idx, true, None)?; + self.print_core_functype_idx(state, ty.func_type_idx, None)?; Ok(()) } @@ -779,7 +1018,14 @@ impl Printer { for table in parser.into_iter_with_offsets() { let (offset, table) = table?; self.newline(offset); - self.print_table_type(state, &table, true)?; + self.print_table_type(state, &table.ty, true)?; + match &table.init { + TableInit::RefNull => {} + TableInit::Expr(expr) => { + self.result.push_str(" "); + self.print_const_expr(state, expr)?; + } + } self.end_group(); state.core.tables += 1; } @@ -825,117 +1071,134 @@ impl Printer { &mut self, state: &mut State, code: &[FunctionBody<'_>], - mut funcs: FunctionSectionReader<'_>, + funcs: FunctionSectionReader<'_>, ) -> Result<()> { - if funcs.get_count() != code.len() as u32 { + if funcs.count() != code.len() as u32 { bail!("mismatch in function and code section counts"); } - for body in code { + for (body, ty) in code.iter().zip(funcs) { let mut body = body.get_binary_reader(); let offset = body.original_position(); - let ty = funcs.read()?; + let ty = ty?; self.newline(offset); self.start_group("func "); let func_idx = state.core.funcs; self.print_name(&state.core.func_names, func_idx)?; + self.result.push(' '); let params = self - .print_core_functype_idx(state, ty, true, Some(func_idx))? + .print_core_functype_idx(state, ty, Some(func_idx))? .unwrap_or(0); - let mut first = true; - let mut local_idx = 0; - let mut locals = NamedLocalPrinter::new("local"); - for _ in 0..body.read_var_u32()? { - let offset = body.original_position(); - let cnt = body.read_var_u32()?; - let ty = body.read_val_type()?; - if MAX_LOCALS - .checked_sub(local_idx) - .and_then(|s| s.checked_sub(cnt)) - .is_none() - { - bail!("function exceeds the maximum number of locals that can be printed"); - } - for _ in 0..cnt { - if first { - self.newline(offset); - first = false; - } - let name = state.core.local_names.get(&(func_idx, params + local_idx)); - locals.start_local(name, &mut self.result); - self.print_valtype(ty)?; - locals.end_local(&mut self.result); - local_idx += 1; - } - } - locals.finish(&mut self.result); - - state.core.labels = 0; - let nesting_start = self.nesting; - body.allow_memarg64(true); - - let mut buf = String::new(); - let mut op_printer = operator::PrintOperator::new(self, state); - while !body.eof() { - // TODO - let offset = body.original_position(); - mem::swap(&mut buf, &mut op_printer.printer.result); - let op_kind = body.visit_operator(&mut op_printer)??; - mem::swap(&mut buf, &mut op_printer.printer.result); - - match op_kind { - // The final `end` in a reader is not printed, it's implied - // in the text format. - operator::OpKind::End if body.eof() => break, - - // When we start a block we newline to the current - // indentation, then we increase the indentation so further - // instructions are tabbed over. - operator::OpKind::BlockStart => { - op_printer.printer.newline(offset); - op_printer.printer.nesting += 1; - } + if self.print_skeleton { + self.result.push_str(" ..."); + } else { + self.print_func_body(state, func_idx, params, &mut body)?; + } - // `else`/`catch` are special in that it's printed at - // the previous indentation, but it doesn't actually change - // our nesting level. - operator::OpKind::BlockMid => { - op_printer.printer.nesting -= 1; - op_printer.printer.newline(offset); - op_printer.printer.nesting += 1; - } + self.end_group(); - // Exiting a block prints `end` at the previous indentation - // level. `delegate` also ends a block like `end` for `try`. - operator::OpKind::End | operator::OpKind::Delegate - if op_printer.printer.nesting > nesting_start => - { - op_printer.printer.nesting -= 1; - op_printer.printer.newline(offset); - } + state.core.funcs += 1; + } + Ok(()) + } - // .. otherwise everything else just has a normal newline - // out in front. - _ => op_printer.printer.newline(offset), + fn print_func_body( + &mut self, + state: &mut State, + func_idx: u32, + params: u32, + body: &mut BinaryReader<'_>, + ) -> Result<()> { + let mut first = true; + let mut local_idx = 0; + let mut locals = NamedLocalPrinter::new("local"); + for _ in 0..body.read_var_u32()? { + let offset = body.original_position(); + let cnt = body.read_var_u32()?; + let ty = body.read()?; + if MAX_LOCALS + .checked_sub(local_idx) + .and_then(|s| s.checked_sub(cnt)) + .is_none() + { + bail!("function exceeds the maximum number of locals that can be printed"); + } + for _ in 0..cnt { + if first { + self.newline(offset); + first = false; + } + let name = state.core.local_names.get(&(func_idx, params + local_idx)); + locals.start_local(name, &mut self.result); + self.print_valtype(ty)?; + locals.end_local(&mut self.result); + local_idx += 1; + } + } + locals.finish(&mut self.result); + + state.core.labels = 0; + let nesting_start = self.nesting; + body.allow_memarg64(true); + + let mut buf = String::new(); + let mut op_printer = operator::PrintOperator::new(self, state); + while !body.eof() { + // TODO + let offset = body.original_position(); + mem::swap(&mut buf, &mut op_printer.printer.result); + let op_kind = body.visit_operator(&mut op_printer)??; + mem::swap(&mut buf, &mut op_printer.printer.result); + + match op_kind { + // The final `end` in a reader is not printed, it's implied + // in the text format. + operator::OpKind::End if body.eof() => break, + + // When we start a block we newline to the current + // indentation, then we increase the indentation so further + // instructions are tabbed over. + operator::OpKind::BlockStart => { + op_printer.printer.newline(offset); + op_printer.printer.nesting += 1; + } + + // `else`/`catch` are special in that it's printed at + // the previous indentation, but it doesn't actually change + // our nesting level. + operator::OpKind::BlockMid => { + op_printer.printer.nesting -= 1; + op_printer.printer.newline(offset); + op_printer.printer.nesting += 1; + } + + // Exiting a block prints `end` at the previous indentation + // level. `delegate` also ends a block like `end` for `try`. + operator::OpKind::End | operator::OpKind::Delegate + if op_printer.printer.nesting > nesting_start => + { + op_printer.printer.nesting -= 1; + op_printer.printer.newline(offset); } - op_printer.printer.result.push_str(&buf); - buf.truncate(0); - } - // If this was an invalid function body then the nesting may not - // have reset back to normal. Fix that up here and forcibly insert - // a newline as well in case the last instruction was something - // like an `if` which has a comment after it which could interfere - // with the closing paren printed for the func. - if self.nesting != nesting_start { - self.nesting = nesting_start; - self.newline(body.original_position()); + // .. otherwise everything else just has a normal newline + // out in front. + _ => op_printer.printer.newline(offset), } + op_printer.printer.result.push_str(&buf); + buf.truncate(0); + } - self.end_group(); - - state.core.funcs += 1; + // If this was an invalid function body then the nesting may not + // have reset back to normal. Fix that up here and forcibly insert + // a newline as well in case the last instruction was something + // like an `if` which has a comment after it which could interfere + // with the closing paren printed for the func. + if self.nesting != nesting_start { + self.nesting = nesting_start; + self.newline(body.original_position()); } + Ok(()) } @@ -949,6 +1212,10 @@ impl Printer { fn print_newline(&mut self, offset: Option) { self.result.push('\n'); + + self.lines.push(self.result.len()); + self.line_offsets.push(offset); + if self.print_offsets { match offset { Some(offset) => write!(self.result, "(;@{offset:<6x};)").unwrap(), @@ -965,56 +1232,6 @@ impl Printer { } } - fn mem_instr( - &mut self, - state: &State, - name: &str, - memarg: &MemArg, - default_align: u32, - ) -> Result<()> { - self.result.push_str(name); - if memarg.memory != 0 { - self.result.push(' '); - self.print_idx(&state.core.memory_names, memarg.memory)?; - } - if memarg.offset != 0 { - write!(self.result, " offset={}", memarg.offset)?; - } - if memarg.align >= 32 { - bail!("alignment in memarg too large"); - } - let align = 1 << memarg.align; - if default_align != align { - write!(self.result, " align={}", align)?; - } - Ok(()) - } - - fn print_blockty(&mut self, state: &mut State, ty: &BlockType, cur_depth: u32) -> Result<()> { - if let Some(name) = state - .core - .label_names - .get(&(state.core.funcs, state.core.labels)) - { - self.result.push(' '); - name.write(&mut self.result); - } - match ty { - BlockType::Empty => {} - BlockType::Type(t) => { - self.result.push_str(" (result "); - self.print_valtype(*t)?; - self.result.push(')'); - } - BlockType::FuncType(idx) => { - self.print_core_functype_idx(state, *idx, false, None)?; - } - } - write!(self.result, " ;; label = @{}", cur_depth)?; - state.core.labels += 1; - Ok(()) - } - fn print_exports(&mut self, state: &State, data: ExportSectionReader) -> Result<()> { for export in data.into_iter_with_offsets() { let (offset, export) = export?; @@ -1058,30 +1275,16 @@ impl Printer { Ok(()) } - fn print_type_ref( - &mut self, - state: &State, - idx: u32, - core: bool, - bounds: Option, - ) -> Result<()> { - self.result.push_str(" (type "); - let closing = match bounds { - Some(TypeBounds::Eq) => { - self.result.push_str("(eq "); - ")" - } - None => "", - }; - self.print_idx( - if core { - &state.core.type_names - } else { - &state.component.type_names - }, - idx, - )?; - self.result.push_str(closing); + fn print_core_type_ref(&mut self, state: &State, idx: u32) -> Result<()> { + self.result.push_str("(type "); + self.print_idx(&state.core.type_names, idx)?; + self.result.push(')'); + Ok(()) + } + + fn print_component_type_ref(&mut self, state: &State, idx: u32) -> Result<()> { + self.result.push_str("(type "); + self.print_idx(&state.component.type_names, idx)?; self.result.push(')'); Ok(()) } @@ -1124,27 +1327,36 @@ impl Printer { table_index, offset_expr, } => { - if *table_index != 0 { + let table_index = table_index.unwrap_or(0); + if table_index != 0 { self.result.push_str(" (table "); - self.print_idx(&state.core.table_names, *table_index)?; + self.print_idx(&state.core.table_names, table_index)?; self.result.push(')'); } self.result.push(' '); self.print_const_expr_sugar(state, offset_expr, "offset")?; } } - let mut items_reader = elem.items.get_items_reader()?; self.result.push(' '); - if items_reader.uses_exprs() { - self.print_valtype(elem.ty)?; + + if self.print_skeleton { + self.result.push_str("..."); } else { - self.print_reftype(elem.ty)?; - } - for _ in 0..items_reader.get_count() { - self.result.push(' '); - match items_reader.read()? { - ElementItem::Expr(expr) => self.print_const_expr_sugar(state, &expr, "item")?, - ElementItem::Func(idx) => self.print_idx(&state.core.func_names, idx)?, + match elem.items { + ElementItems::Functions(reader) => { + self.result.push_str("func"); + for idx in reader { + self.result.push(' '); + self.print_idx(&state.core.func_names, idx?)? + } + } + ElementItems::Expressions(ty, reader) => { + self.print_reftype(ty)?; + for expr in reader { + self.result.push(' '); + self.print_const_expr_sugar(state, &expr?, "item")? + } + } } } self.end_group(); @@ -1174,7 +1386,11 @@ impl Printer { self.result.push(' '); } } - self.print_bytes(data.data)?; + if self.print_skeleton { + self.result.push_str("..."); + } else { + self.print_bytes(data.data)?; + } self.end_group(); } Ok(()) @@ -1198,7 +1414,7 @@ impl Printer { if reader.eof() { break; } - match reader.visit_with_offset(&mut op_printer)?? { + match reader.visit_operator(&mut op_printer)?? { operator::OpKind::End if reader.eof() => {} _ if i == 0 => first_op = Some(mem::take(&mut op_printer.printer.result)), @@ -1241,7 +1457,7 @@ impl Printer { } else { op_printer.printer.result.push(' '); } - match reader.visit_with_offset(&mut op_printer)?? { + match reader.visit_operator(&mut op_printer)?? { operator::OpKind::End if reader.eof() => {} _ => { result.push_str(&op_printer.printer.result); @@ -1321,13 +1537,8 @@ impl Printer { Ok(()) } - fn print_tuple_or_union_type( - &mut self, - ty: &str, - state: &State, - tys: &[ComponentValType], - ) -> Result<()> { - self.start_group(ty); + fn print_tuple_type(&mut self, state: &State, tys: &[ComponentValType]) -> Result<()> { + self.start_group("tuple"); for ty in tys { self.result.push(' '); self.print_component_val_type(state, ty)?; @@ -1384,16 +1595,21 @@ impl Printer { ComponentDefinedType::Record(fields) => self.print_record_type(state, fields)?, ComponentDefinedType::Variant(cases) => self.print_variant_type(state, cases)?, ComponentDefinedType::List(ty) => self.print_list_type(state, ty)?, - ComponentDefinedType::Tuple(tys) => { - self.print_tuple_or_union_type("tuple", state, tys)? - } + ComponentDefinedType::Tuple(tys) => self.print_tuple_type(state, tys)?, ComponentDefinedType::Flags(names) => self.print_flag_or_enum_type("flags", names)?, ComponentDefinedType::Enum(cases) => self.print_flag_or_enum_type("enum", cases)?, - ComponentDefinedType::Union(tys) => { - self.print_tuple_or_union_type("union", state, tys)? - } ComponentDefinedType::Option(ty) => self.print_option_type(state, ty)?, ComponentDefinedType::Result { ok, err } => self.print_result_type(state, *ok, *err)?, + ComponentDefinedType::Own(idx) => { + self.start_group("own "); + self.print_idx(&state.component.type_names, *idx)?; + self.end_group(); + } + ComponentDefinedType::Borrow(idx) => { + self.start_group("borrow "); + self.print_idx(&state.component.type_names, *idx)?; + self.end_group(); + } } Ok(()) @@ -1457,26 +1673,19 @@ impl Printer { match decl { ComponentTypeDeclaration::CoreType(ty) => self.print_core_type(states, ty)?, ComponentTypeDeclaration::Type(ty) => self.print_component_type_def(states, ty)?, - ComponentTypeDeclaration::Alias(alias) => match alias { - ComponentAlias::InstanceExport { .. } => { - bail!("component types cannot alias instance exports") - } - ComponentAlias::CoreInstanceExport { .. } => { - bail!("component types cannot alias core instance exports") - } - ComponentAlias::Outer { kind, count, index } => { - self.print_component_outer_alias(states, kind, count, index)? - } - }, + ComponentTypeDeclaration::Alias(alias) => { + self.print_component_alias(states, alias)?; + } ComponentTypeDeclaration::Export { name, ty } => { self.start_group("export "); - self.print_str(name)?; + self.print_component_kind_name(states.last_mut().unwrap(), ty.kind())?; + self.print_component_import_name(name.into())?; self.result.push(' '); - self.print_component_import_ty(states.last().unwrap(), &ty, false)?; + self.print_component_import_ty(states.last_mut().unwrap(), &ty, false)?; self.end_group(); } ComponentTypeDeclaration::Import(import) => { - self.print_component_import(states.last_mut().unwrap(), &import, false)? + self.print_component_import(states.last_mut().unwrap(), &import, true)? } } } @@ -1498,22 +1707,15 @@ impl Printer { match decl { InstanceTypeDeclaration::CoreType(ty) => self.print_core_type(states, ty)?, InstanceTypeDeclaration::Type(ty) => self.print_component_type_def(states, ty)?, - InstanceTypeDeclaration::Alias(alias) => match alias { - ComponentAlias::InstanceExport { .. } => { - bail!("instance types cannot alias instance exports") - } - ComponentAlias::CoreInstanceExport { .. } => { - bail!("instance types cannot alias core instance exports") - } - ComponentAlias::Outer { kind, count, index } => { - self.print_component_outer_alias(states, kind, count, index)? - } - }, + InstanceTypeDeclaration::Alias(alias) => { + self.print_component_alias(states, alias)?; + } InstanceTypeDeclaration::Export { name, ty } => { self.start_group("export "); - self.print_str(name)?; + self.print_component_kind_name(states.last_mut().unwrap(), ty.kind())?; + self.print_component_import_name(name.into())?; self.result.push(' '); - self.print_component_import_ty(states.last().unwrap(), &ty, false)?; + self.print_component_import_ty(states.last_mut().unwrap(), &ty, false)?; self.end_group(); } } @@ -1567,71 +1769,13 @@ impl Printer { Ok(()) } - fn print_component_outer_alias( - &mut self, - states: &mut [State], - kind: ComponentOuterAliasKind, - count: u32, - index: u32, - ) -> Result<()> { - let state = states.last().unwrap(); - let outer = Self::outer_state(states, count)?; - self.start_group("alias outer "); - if let Some(name) = outer.name.as_ref() { - name.write(&mut self.result); - } else { - self.result.push_str(count.to_string().as_str()); - } - self.result.push(' '); - match kind { - ComponentOuterAliasKind::CoreModule => { - self.print_idx(&outer.core.module_names, index)?; - self.result.push(' '); - self.start_group("core module "); - self.print_name(&state.core.module_names, state.core.modules)?; - } - ComponentOuterAliasKind::CoreType => { - self.print_idx(&outer.core.type_names, index)?; - self.result.push(' '); - self.start_group("core type "); - self.print_name(&state.core.type_names, state.core.types.len() as u32)?; - } - ComponentOuterAliasKind::Type => { - self.print_idx(&outer.component.type_names, index)?; - self.result.push(' '); - self.start_group("type "); - self.print_name(&state.component.type_names, state.component.types)?; - } - ComponentOuterAliasKind::Component => { - self.print_idx(&outer.component.component_names, index)?; - self.result.push(' '); - self.start_group("component "); - self.print_name(&state.component.component_names, state.component.components)?; - } - } - self.end_group(); // kind - self.end_group(); // alias - - let state = states.last_mut().unwrap(); - match kind { - ComponentOuterAliasKind::CoreModule => state.core.modules += 1, - ComponentOuterAliasKind::CoreType => state.core.types.push(None), - ComponentOuterAliasKind::Type => state.component.types += 1, - ComponentOuterAliasKind::Component => state.component.components += 1, - } - - Ok(()) - } - fn print_component_func_type(&mut self, state: &State, ty: &ComponentFuncType) -> Result<()> { self.start_group("func"); for (name, ty) in ty.params.iter() { self.result.push(' '); self.start_group("param "); - if let Some(name) = name { - self.print_str(name)?; - self.result.push(' '); - } + self.print_str(name)?; + self.result.push(' '); self.print_component_val_type(state, ty)?; self.end_group() } @@ -1662,12 +1806,13 @@ impl Printer { let state = states.last_mut().unwrap(); self.print_name(&state.component.type_names, state.component.types)?; } - self.result.push(' '); match ty { ComponentType::Defined(ty) => { + self.result.push(' '); self.print_defined_type(states.last_mut().unwrap(), &ty)?; } ComponentType::Func(ty) => { + self.result.push(' '); self.print_component_func_type(states.last_mut().unwrap(), &ty)?; } ComponentType::Component(decls) => { @@ -1676,6 +1821,19 @@ impl Printer { ComponentType::Instance(decls) => { self.print_instance_type(states, decls.into_vec())?; } + ComponentType::Resource { rep, dtor } => { + self.result.push_str(" "); + self.start_group("resource"); + self.result.push_str(" (rep "); + self.print_valtype(rep)?; + self.result.push_str(")"); + if let Some(dtor) = dtor { + self.result.push_str(" (dtor (func "); + self.print_idx(&states.last().unwrap().core.func_names, dtor)?; + self.result.push_str("))"); + } + self.end_group(); + } } self.end_group(); @@ -1707,26 +1865,6 @@ impl Printer { let (offset, import) = import?; self.newline(offset); self.print_component_import(state, &import, true)?; - match import.ty { - ComponentTypeRef::Module(_) => { - state.core.modules += 1; - } - ComponentTypeRef::Func(_) => { - state.component.funcs += 1; - } - ComponentTypeRef::Value(_) => { - state.component.values += 1; - } - ComponentTypeRef::Type(..) => { - state.component.types += 1; - } - ComponentTypeRef::Instance(_) => { - state.component.instances += 1; - } - ComponentTypeRef::Component(_) => { - state.component.components += 1; - } - } } Ok(()) @@ -1739,36 +1877,50 @@ impl Printer { index: bool, ) -> Result<()> { self.start_group("import "); - self.print_str(import.name)?; + self.print_component_import_name(import.name)?; self.result.push(' '); self.print_component_import_ty(state, &import.ty, index)?; self.end_group(); Ok(()) } + fn print_component_import_name(&mut self, name: ComponentExternName<'_>) -> Result<()> { + match name { + ComponentExternName::Kebab(s) => self.print_str(s), + ComponentExternName::Interface(s) => { + self.start_group("interface "); + self.print_str(s)?; + self.end_group(); + Ok(()) + } + } + } + fn print_component_import_ty( &mut self, - state: &State, + state: &mut State, ty: &ComponentTypeRef, index: bool, ) -> Result<()> { match ty { ComponentTypeRef::Module(idx) => { - self.start_group("core module"); + self.start_group("core module "); if index { - self.result.push(' '); self.print_name(&state.core.module_names, state.core.modules as u32)?; + self.result.push(' '); + state.core.modules += 1; } - self.print_type_ref(state, *idx, true, None)?; + self.print_component_type_ref(state, *idx)?; self.end_group(); } ComponentTypeRef::Func(idx) => { - self.start_group("func"); + self.start_group("func "); if index { - self.result.push(' '); self.print_name(&state.component.func_names, state.component.funcs)?; + self.result.push(' '); + state.component.funcs += 1; } - self.print_type_ref(state, *idx, false, None)?; + self.print_component_type_ref(state, *idx)?; self.end_group(); } ComponentTypeRef::Value(ty) => { @@ -1776,34 +1928,53 @@ impl Printer { if index { self.print_name(&state.component.value_names, state.component.values)?; self.result.push(' '); + state.component.values += 1; } match ty { ComponentValType::Primitive(ty) => self.print_primitive_val_type(ty), ComponentValType::Type(idx) => { - self.print_type_ref(state, *idx, false, None)?; + self.print_component_type_ref(state, *idx)?; } } self.end_group(); } - ComponentTypeRef::Type(bounds, idx) => { - self.print_type_ref(state, *idx, false, Some(*bounds))?; + ComponentTypeRef::Type(bounds) => { + self.result.push_str("(type "); + if index { + self.print_name(&state.component.type_names, state.component.types)?; + self.result.push(' '); + state.component.types += 1; + } + match bounds { + TypeBounds::Eq(idx) => { + self.result.push_str("(eq "); + self.print_idx(&state.component.type_names, *idx)?; + self.result.push(')'); + } + TypeBounds::SubResource => { + self.result.push_str("(sub resource)"); + } + }; + self.result.push(')'); } ComponentTypeRef::Instance(idx) => { - self.start_group("instance"); + self.start_group("instance "); if index { - self.result.push(' '); self.print_name(&state.component.instance_names, state.component.instances)?; + self.result.push(' '); + state.component.instances += 1; } - self.print_type_ref(state, *idx, false, None)?; + self.print_component_type_ref(state, *idx)?; self.end_group(); } ComponentTypeRef::Component(idx) => { - self.start_group("component"); + self.start_group("component "); if index { - self.result.push(' '); self.print_name(&state.component.component_names, state.component.components)?; + self.result.push(' '); + state.component.components += 1; } - self.print_type_ref(state, *idx, false, None)?; + self.print_component_type_ref(state, *idx)?; self.end_group(); } } @@ -1818,7 +1989,7 @@ impl Printer { for export in parser.into_iter_with_offsets() { let (offset, export) = export?; self.newline(offset); - self.print_component_export(state, &export)?; + self.print_component_export(state, &export, true)?; } Ok(()) } @@ -1827,15 +1998,58 @@ impl Printer { &mut self, state: &mut State, export: &ComponentExport, + named: bool, ) -> Result<()> { self.start_group("export "); - self.print_str(export.name)?; + if named { + self.print_component_kind_name(state, export.kind)?; + } + self.print_component_import_name(export.name.into())?; self.result.push(' '); self.print_component_external_kind(state, export.kind, export.index)?; + if let Some(ty) = &export.ty { + self.result.push(' '); + self.print_component_import_ty(state, &ty, false)?; + } self.end_group(); Ok(()) } + fn print_component_kind_name( + &mut self, + state: &mut State, + kind: ComponentExternalKind, + ) -> Result<()> { + match kind { + ComponentExternalKind::Func => { + self.print_name(&state.component.func_names, state.component.funcs)?; + state.component.funcs += 1; + } + ComponentExternalKind::Module => { + self.print_name(&state.core.module_names, state.core.modules)?; + state.core.modules += 1; + } + ComponentExternalKind::Value => { + self.print_name(&state.component.value_names, state.component.values)?; + state.component.values += 1; + } + ComponentExternalKind::Type => { + self.print_name(&state.component.type_names, state.component.types)?; + state.component.types += 1; + } + ComponentExternalKind::Instance => { + self.print_name(&state.component.instance_names, state.component.instances)?; + state.component.instances += 1; + } + ComponentExternalKind::Component => { + self.print_name(&state.component.component_names, state.component.components)?; + state.component.components += 1; + } + } + self.result.push(' '); + Ok(()) + } + fn print_component_external_kind( &mut self, state: &State, @@ -1951,6 +2165,36 @@ impl Printer { self.end_group(); state.core.funcs += 1; } + CanonicalFunction::ResourceNew { resource } => { + self.start_group("core func "); + self.print_name(&state.core.func_names, state.core.funcs)?; + self.result.push(' '); + self.start_group("canon resource.new "); + self.print_idx(&state.component.type_names, resource)?; + self.end_group(); + self.end_group(); + state.core.funcs += 1; + } + CanonicalFunction::ResourceDrop { resource } => { + self.start_group("core func "); + self.print_name(&state.core.func_names, state.core.funcs)?; + self.result.push(' '); + self.start_group("canon resource.drop "); + self.print_idx(&state.component.type_names, resource)?; + self.end_group(); + self.end_group(); + state.core.funcs += 1; + } + CanonicalFunction::ResourceRep { resource } => { + self.start_group("core func "); + self.print_name(&state.core.func_names, state.core.funcs)?; + self.result.push(' '); + self.start_group("canon resource.rep "); + self.print_idx(&state.component.type_names, resource)?; + self.end_group(); + self.end_group(); + state.core.funcs += 1; + } } } @@ -1963,9 +2207,9 @@ impl Printer { self.newline(offset); self.start_group("core instance "); self.print_name(&state.core.instance_names, state.core.instances)?; - self.result.push(' '); match instance { Instance::Instantiate { module_index, args } => { + self.result.push(' '); self.start_group("instantiate "); self.print_idx(&state.core.module_names, module_index)?; for arg in args.iter() { @@ -2016,7 +2260,7 @@ impl Printer { ComponentInstance::FromExports(exports) => { for export in exports.iter() { self.newline(offset); - self.print_component_export(state, export)?; + self.print_component_export(state, export, false)?; } } } @@ -2056,11 +2300,9 @@ impl Printer { fn print_component_start( &mut self, state: &mut State, - mut parser: ComponentStartSectionReader, + pos: usize, + start: ComponentStartFunction, ) -> Result<()> { - let pos = parser.original_position(); - let start = parser.read()?; - self.newline(pos); self.start_group("start "); self.print_idx(&state.component.func_names, start.func_index)?; @@ -2095,112 +2337,169 @@ impl Printer { for alias in parser.into_iter_with_offsets() { let (offset, alias) = alias?; self.newline(offset); - match alias { - ComponentAlias::InstanceExport { - kind, - instance_index, - name, - } => { - let state = states.last_mut().unwrap(); - self.start_group("alias export "); - self.print_idx(&state.component.instance_names, instance_index)?; - self.result.push(' '); - self.print_str(name)?; - self.result.push(' '); - match kind { - ComponentExternalKind::Module => { - self.start_group("core module "); - self.print_name(&state.core.module_names, state.core.modules)?; - self.end_group(); - state.core.modules += 1; - } - ComponentExternalKind::Component => { - self.start_group("component "); - self.print_name( - &state.component.component_names, - state.component.components, - )?; - self.end_group(); - state.component.components += 1; - } - ComponentExternalKind::Instance => { - self.start_group("instance "); - self.print_name( - &state.component.instance_names, - state.component.instances, - )?; - self.end_group(); - state.component.instances += 1; - } - ComponentExternalKind::Func => { - self.start_group("func "); - self.print_name(&state.component.func_names, state.component.funcs)?; - self.end_group(); - state.component.funcs += 1; - } - ComponentExternalKind::Value => { - self.start_group("value "); - self.print_name(&state.component.value_names, state.component.values)?; - self.end_group(); - state.component.values += 1; - } - ComponentExternalKind::Type => { - self.start_group("type "); - self.print_name(&state.component.type_names, state.component.types)?; - self.end_group(); - state.component.types += 1; - } + self.print_component_alias(states, alias)?; + } + Ok(()) + } + + fn print_component_alias( + &mut self, + states: &mut [State], + alias: ComponentAlias<'_>, + ) -> Result<()> { + match alias { + ComponentAlias::InstanceExport { + kind, + instance_index, + name, + } => { + let state = states.last_mut().unwrap(); + self.start_group("alias export "); + self.print_idx(&state.component.instance_names, instance_index)?; + self.result.push(' '); + self.print_str(name)?; + self.result.push(' '); + match kind { + ComponentExternalKind::Module => { + self.start_group("core module "); + self.print_name(&state.core.module_names, state.core.modules)?; + self.end_group(); + state.core.modules += 1; + } + ComponentExternalKind::Component => { + self.start_group("component "); + self.print_name( + &state.component.component_names, + state.component.components, + )?; + self.end_group(); + state.component.components += 1; + } + ComponentExternalKind::Instance => { + self.start_group("instance "); + self.print_name( + &state.component.instance_names, + state.component.instances, + )?; + self.end_group(); + state.component.instances += 1; + } + ComponentExternalKind::Func => { + self.start_group("func "); + self.print_name(&state.component.func_names, state.component.funcs)?; + self.end_group(); + state.component.funcs += 1; + } + ComponentExternalKind::Value => { + self.start_group("value "); + self.print_name(&state.component.value_names, state.component.values)?; + self.end_group(); + state.component.values += 1; + } + ComponentExternalKind::Type => { + self.start_group("type "); + self.print_name(&state.component.type_names, state.component.types)?; + self.end_group(); + state.component.types += 1; } + } - self.end_group(); // alias export + self.end_group(); // alias export + } + ComponentAlias::CoreInstanceExport { + instance_index, + kind, + name, + } => { + let state = states.last_mut().unwrap(); + self.start_group("alias core export "); + self.print_idx(&state.core.instance_names, instance_index)?; + self.result.push(' '); + self.print_str(name)?; + self.result.push(' '); + match kind { + ExternalKind::Func => { + self.start_group("core func "); + self.print_name(&state.core.func_names, state.core.funcs)?; + self.end_group(); + state.core.funcs += 1; + } + ExternalKind::Table => { + self.start_group("core table "); + self.print_name(&state.core.table_names, state.core.tables)?; + self.end_group(); + state.core.tables += 1; + } + ExternalKind::Memory => { + self.start_group("core memory "); + self.print_name(&state.core.memory_names, state.core.memories)?; + self.end_group(); + state.core.memories += 1; + } + ExternalKind::Global => { + self.start_group("core global "); + self.print_name(&state.core.global_names, state.core.globals)?; + self.end_group(); + state.core.globals += 1; + } + ExternalKind::Tag => { + self.start_group("core tag "); + write!(self.result, "(;{};)", state.core.tags)?; + self.end_group(); + state.core.tags += 1; + } } - ComponentAlias::CoreInstanceExport { - instance_index, - kind, - name, - } => { - let state = states.last_mut().unwrap(); - self.start_group("alias core export "); - self.print_idx(&state.core.instance_names, instance_index)?; - self.result.push(' '); - self.print_str(name)?; - self.result.push(' '); - match kind { - ExternalKind::Func => { - self.start_group("core func "); - self.print_name(&state.core.func_names, state.core.funcs)?; - self.end_group(); - state.core.funcs += 1; - } - ExternalKind::Table => { - self.start_group("core table "); - self.print_name(&state.core.table_names, state.core.tables)?; - self.end_group(); - state.core.tables += 1; - } - ExternalKind::Memory => { - self.start_group("core memory "); - self.print_name(&state.core.memory_names, state.core.memories)?; - self.end_group(); - state.core.memories += 1; - } - ExternalKind::Global => { - self.start_group("core global "); - self.print_name(&state.core.global_names, state.core.globals)?; - self.end_group(); - state.core.globals += 1; - } - ExternalKind::Tag => { - self.start_group("core tag "); - write!(self.result, "(;{};)", state.core.tags)?; - self.end_group(); - state.core.tags += 1; - } + self.end_group(); // alias export + } + + ComponentAlias::Outer { kind, count, index } => { + let state = states.last().unwrap(); + let outer = Self::outer_state(states, count)?; + self.start_group("alias outer "); + if let Some(name) = outer.name.as_ref() { + name.write(&mut self.result); + } else { + self.result.push_str(count.to_string().as_str()); + } + self.result.push(' '); + match kind { + ComponentOuterAliasKind::CoreModule => { + self.print_idx(&outer.core.module_names, index)?; + self.result.push(' '); + self.start_group("core module "); + self.print_name(&state.core.module_names, state.core.modules)?; + } + ComponentOuterAliasKind::CoreType => { + self.print_idx(&outer.core.type_names, index)?; + self.result.push(' '); + self.start_group("core type "); + self.print_name(&state.core.type_names, state.core.types.len() as u32)?; + } + ComponentOuterAliasKind::Type => { + self.print_idx(&outer.component.type_names, index)?; + self.result.push(' '); + self.start_group("type "); + self.print_name(&state.component.type_names, state.component.types)?; + } + ComponentOuterAliasKind::Component => { + self.print_idx(&outer.component.component_names, index)?; + self.result.push(' '); + self.start_group("component "); + self.print_name( + &state.component.component_names, + state.component.components, + )?; } - self.end_group(); // alias export } - ComponentAlias::Outer { kind, count, index } => { - self.print_component_outer_alias(states, kind, count, index)? + self.end_group(); // kind + self.end_group(); // alias + + let state = states.last_mut().unwrap(); + match kind { + ComponentOuterAliasKind::CoreModule => state.core.modules += 1, + ComponentOuterAliasKind::CoreType => state.core.types.push(None), + ComponentOuterAliasKind::Type => state.component.types += 1, + ComponentOuterAliasKind::Component => state.component.components += 1, } } } @@ -2249,6 +2548,136 @@ impl Printer { self.result.push(to_hex((byte >> 4) & 0xf)); self.result.push(to_hex(byte & 0xf)); } + + fn print_custom_section(&mut self, section: CustomSectionReader<'_>) -> Result<()> { + match section.name() { + "producers" => { + self.newline(section.range().start); + self.print_producers_section(ProducersSectionReader::new( + section.data(), + section.data_offset(), + )?) + } + "dylink.0" => { + self.newline(section.range().start); + self.print_dylink0_section(Dylink0SectionReader::new( + section.data(), + section.data_offset(), + )) + } + _ => Ok(()), + } + } + + fn print_producers_section(&mut self, section: ProducersSectionReader<'_>) -> Result<()> { + self.start_group("@producers"); + for field in section { + let field = field?; + for value in field.values.into_iter_with_offsets() { + let (offset, value) = value?; + self.newline(offset); + self.start_group(field.name); + self.result.push_str(" "); + self.print_str(value.name)?; + self.result.push_str(" "); + self.print_str(value.version)?; + self.end_group(); + } + } + self.end_group(); + Ok(()) + } + + fn print_dylink0_section(&mut self, mut section: Dylink0SectionReader<'_>) -> Result<()> { + self.start_group("@dylink.0"); + loop { + let start = section.original_position(); + let next = match section.next() { + Some(Ok(next)) => next, + Some(Err(e)) => return Err(e.into()), + None => break, + }; + match next { + Dylink0Subsection::MemInfo(info) => { + self.newline(start); + self.start_group("mem-info"); + if info.memory_size > 0 || info.memory_alignment > 0 { + write!( + self.result, + " (memory {} {})", + info.memory_size, info.memory_alignment + )?; + } + if info.table_size > 0 || info.table_alignment > 0 { + write!( + self.result, + " (table {} {})", + info.table_size, info.table_alignment + )?; + } + self.end_group(); + } + Dylink0Subsection::Needed(needed) => { + self.newline(start); + self.start_group("needed"); + for s in needed { + self.result.push_str(" "); + self.print_str(s)?; + } + self.end_group(); + } + Dylink0Subsection::ExportInfo(info) => { + for info in info { + self.newline(start); + self.start_group("export-info "); + self.print_str(info.name)?; + self.print_dylink0_flags(info.flags)?; + self.end_group(); + } + } + Dylink0Subsection::ImportInfo(info) => { + for info in info { + self.newline(start); + self.start_group("import-info "); + self.print_str(info.module)?; + self.result.push_str(" "); + self.print_str(info.field)?; + self.print_dylink0_flags(info.flags)?; + self.end_group(); + } + } + Dylink0Subsection::Unknown { ty, .. } => { + bail!("don't know how to print dylink.0 subsection id {ty}"); + } + } + } + self.end_group(); + Ok(()) + } + + fn print_dylink0_flags(&mut self, mut flags: u32) -> Result<()> { + macro_rules! print_flag { + ($($name:ident = $text:tt)*) => ({$( + if flags & wasmparser::$name != 0 { + flags &= !wasmparser::$name; + self.result.push_str(concat!(" ", $text)); + } + )*}) + } + print_flag! { + WASM_SYM_BINDING_WEAK = "binding-weak" + WASM_SYM_BINDING_LOCAL = "binding-local" + WASM_SYM_VISIBILITY_HIDDEN = "visibility-hidden" + WASM_SYM_UNDEFINED = "undefined" + WASM_SYM_EXPORTED = "exported" + WASM_SYM_EXPLICIT_NAME = "explicit-name" + WASM_SYM_NO_STRIP = "no-strip" + } + if flags != 0 { + write!(self.result, " {:#x}", flags)?; + } + Ok(()) + } } struct NamedLocalPrinter { @@ -2403,7 +2832,12 @@ impl Printer { } impl Naming { - fn new<'a>(name: &'a str, index: u32, group: &str, used: &mut HashSet<&'a str>) -> Naming { + fn new<'a>( + name: &'a str, + index: u32, + group: &str, + used: Option<&mut HashSet<&'a str>>, + ) -> Naming { let mut identifier = None; // If the `name` provided can't be used as the raw identifier for the @@ -2414,8 +2848,8 @@ impl Naming { // * Identifiers have a fixed set of valid characters // * For wasmprinter's purposes we "reserve" identifiers with the `#` // prefix, which is in theory rare to encounter in practice. - // * If the name has already been used for some other item then it can't - // be reused. + // * If the name has already been used for some other item and cannot + // be reused (e.g. because shadowing in this context is not possible). // // If any of these conditions match then we generate a unique identifier // based on `name` but not it exactly. By factoring in the `group`, @@ -2427,7 +2861,7 @@ impl Naming { if name.is_empty() || name.chars().any(|c| !is_idchar(c)) || name.starts_with('#') - || !used.insert(name) + || used.map(|set| !set.insert(name)).unwrap_or(false) { let mut id = String::new(); id.push('#'); @@ -2517,3 +2951,15 @@ impl Naming { } } } + +fn name_map(into: &mut HashMap, names: NameMap<'_>, name: &str) -> Result<()> { + let mut used = HashSet::new(); + for naming in names { + let naming = naming?; + into.insert( + naming.index, + Naming::new(naming.name, naming.index, name, Some(&mut used)), + ); + } + Ok(()) +} diff --git a/crates/wasmprinter/src/operator.rs b/crates/wasmprinter/src/operator.rs index dbb19e1920..df4c46d8d1 100644 --- a/crates/wasmprinter/src/operator.rs +++ b/crates/wasmprinter/src/operator.rs @@ -1,7 +1,7 @@ use super::{Printer, State}; -use anyhow::Result; +use anyhow::{bail, Result}; use std::fmt::Write; -use wasmparser::{BlockType, BrTable, Ieee32, Ieee64, MemArg, ValType, VisitOperator, V128}; +use wasmparser::{BlockType, BrTable, MemArg, VisitOperator}; pub struct PrintOperator<'a, 'b> { pub(super) printer: &'a mut Printer, @@ -26,8 +26,36 @@ impl<'a, 'b> PrintOperator<'a, 'b> { &mut self.printer.result } - fn print_blockty(&mut self, ty: &BlockType) -> Result<()> { - self.printer.print_blockty(self.state, ty, self.cur_depth()) + fn blockty(&mut self, ty: BlockType) -> Result<()> { + if let Some(name) = self + .state + .core + .label_names + .get(&(self.state.core.funcs, self.state.core.labels)) + { + name.write(&mut self.printer.result); + self.printer.result.push(' '); + } + match ty { + BlockType::Empty => {} + BlockType::Type(t) => { + self.push_str("(result "); + self.printer.print_valtype(t)?; + self.push_str(") "); + } + BlockType::FuncType(idx) => { + self.printer + .print_core_functype_idx(self.state, idx, None)?; + self.printer.result.push(' '); + } + } + // Note that 1 is added to the current depth here since if a block type + // is being printed then a block is being created which will increase + // the label depth of the block itself. + let depth = self.cur_depth(); + write!(self.result(), ";; label = @{}", depth + 1)?; + self.state.core.labels += 1; + Ok(()) } fn cur_depth(&self) -> u32 { @@ -41,51 +69,102 @@ impl<'a, 'b> PrintOperator<'a, 'b> { } } - fn print_func_idx(&mut self, idx: u32) -> Result<()> { + fn tag_index(&mut self, index: u32) -> Result<()> { + write!(self.result(), "{index}")?; + Ok(()) + } + + fn relative_depth(&mut self, depth: u32) -> Result<()> { + let label = self.label(depth); + write!(self.result(), "{depth} (;{label};)")?; + Ok(()) + } + + fn targets(&mut self, targets: BrTable<'_>) -> Result<()> { + for (i, item) in targets.targets().chain([Ok(targets.default())]).enumerate() { + if i > 0 { + self.push_str(" "); + } + self.relative_depth(item?)?; + } + Ok(()) + } + + fn function_index(&mut self, idx: u32) -> Result<()> { self.printer.print_idx(&self.state.core.func_names, idx) } - fn print_table_idx(&mut self, idx: u32) -> Result<()> { - self.printer.print_idx(&self.state.core.table_names, idx) + fn local_index(&mut self, idx: u32) -> Result<()> { + self.printer + .print_local_idx(self.state, self.state.core.funcs, idx) } - fn print_global_idx(&mut self, idx: u32) -> Result<()> { + fn global_index(&mut self, idx: u32) -> Result<()> { self.printer.print_idx(&self.state.core.global_names, idx) } - fn print_memory_idx(&mut self, idx: u32) -> Result<()> { - self.printer.print_idx(&self.state.core.memory_names, idx) + fn table_index(&mut self, idx: u32) -> Result<()> { + self.printer.print_idx(&self.state.core.table_names, idx) } - fn print_data_idx(&mut self, idx: u32) -> Result<()> { - self.printer.print_idx(&self.state.core.data_names, idx) + fn table(&mut self, idx: u32) -> Result<()> { + self.table_index(idx) } - fn print_element_idx(&mut self, idx: u32) -> Result<()> { - self.printer.print_idx(&self.state.core.element_names, idx) + fn memory_index(&mut self, idx: u32) -> Result<()> { + self.printer.print_idx(&self.state.core.memory_names, idx) } - fn print_local_idx(&mut self, idx: u32) -> Result<()> { - self.printer - .print_local_idx(self.state, self.state.core.funcs, idx) + fn type_index(&mut self, idx: u32) -> Result<()> { + self.push_str(" "); + self.printer.print_core_type_ref(self.state, idx) + } + + fn data_index(&mut self, idx: u32) -> Result<()> { + self.printer.print_idx(&self.state.core.data_names, idx) } - fn print_type_ref(&mut self, idx: u32) -> Result<()> { - self.printer.print_type_ref(self.state, idx, true, None) + fn elem_index(&mut self, idx: u32) -> Result<()> { + self.printer.print_idx(&self.state.core.element_names, idx) } - fn print_valtype(&mut self, ty: ValType) -> Result<()> { - self.printer.print_valtype(ty) + fn lane(&mut self, lane: u8) -> Result<()> { + write!(self.result(), "{lane}")?; + Ok(()) } - fn instr(&mut self, name: &str) -> Result { - self.push_str(name); - Ok(OpKind::Normal) + fn lanes(&mut self, lanes: [u8; 16]) -> Result<()> { + for (i, lane) in lanes.iter().enumerate() { + if i > 0 { + self.push_str(" "); + } + write!(self.result(), "{lane}")?; + } + Ok(()) } - fn mem_instr(&mut self, name: &str, memarg: &MemArg, align: u32) -> Result { - self.printer.mem_instr(self.state, name, memarg, align)?; - Ok(OpKind::Normal) + fn memarg(&mut self, memarg: MemArg) -> Result<()> { + // Remove the leading ' ' inserted by the macro below since memarg may + // not actually print anything if all of its parameters are defaulted. + // Ideally we wouldn't rely on the ability to pop here but this ends up + // being the easiest. + assert_eq!(self.printer.result.pop(), Some(' ')); + + if memarg.memory != 0 { + self.result().push(' '); + self.memory_index(memarg.memory)?; + } + if memarg.offset != 0 { + write!(self.result(), " offset={}", memarg.offset)?; + } + if memarg.align != memarg.max_align { + if memarg.align >= 32 { + bail!("alignment in memarg too large"); + } + let align = 1 << memarg.align; + write!(self.result(), " align={}", align)?; + } + Ok(()) } } @@ -97,1810 +176,698 @@ pub enum OpKind { Normal, } -impl<'a> VisitOperator<'a> for PrintOperator<'_, '_> { - type Output = Result; - - fn visit_unreachable(&mut self, _pos: usize) -> Self::Output { - self.instr("unreachable") - } - fn visit_nop(&mut self, _pos: usize) -> Self::Output { - self.instr("nop") - } - fn visit_block(&mut self, _pos: usize, ty: BlockType) -> Self::Output { - self.push_str("block"); - self.print_blockty(&ty)?; - Ok(OpKind::BlockStart) - } - fn visit_loop(&mut self, _pos: usize, ty: BlockType) -> Self::Output { - self.push_str("loop"); - self.print_blockty(&ty)?; - Ok(OpKind::BlockStart) - } - fn visit_if(&mut self, _pos: usize, ty: BlockType) -> Self::Output { - self.push_str("if"); - self.print_blockty(&ty)?; - Ok(OpKind::BlockStart) - } - fn visit_else(&mut self, _pos: usize) -> Self::Output { - self.push_str("else"); - Ok(OpKind::BlockMid) - } - fn visit_try(&mut self, _pos: usize, ty: BlockType) -> Self::Output { - self.push_str("try"); - self.print_blockty(&ty)?; - Ok(OpKind::BlockStart) - } - fn visit_catch(&mut self, _pos: usize, index: u32) -> Self::Output { - write!(self.result(), "catch {index}")?; - Ok(OpKind::BlockMid) - } - fn visit_throw(&mut self, _pos: usize, index: u32) -> Self::Output { - write!(self.result(), "throw {index}")?; - Ok(OpKind::Normal) - } - fn visit_rethrow(&mut self, _pos: usize, relative_depth: u32) -> Self::Output { - let label = self.label(relative_depth); - write!(self.result(), "rethrow {relative_depth} (;{label};)")?; - Ok(OpKind::Normal) - } - fn visit_delegate(&mut self, _pos: usize, relative_depth: u32) -> Self::Output { - let label = self.label(relative_depth); - write!(self.result(), "delegate {relative_depth} (;{label};)")?; - Ok(OpKind::Delegate) - } - fn visit_catch_all(&mut self, _pos: usize) -> Self::Output { - self.push_str("catch_all"); - Ok(OpKind::BlockMid) - } - fn visit_end(&mut self, _pos: usize) -> Self::Output { - self.push_str("end"); - Ok(OpKind::End) - } - fn visit_br(&mut self, _pos: usize, relative_depth: u32) -> Self::Output { - let label = self.label(relative_depth); - write!(self.result(), "br {relative_depth} (;{label};)")?; - Ok(OpKind::Normal) - } - fn visit_br_if(&mut self, _pos: usize, relative_depth: u32) -> Self::Output { - let label = self.label(relative_depth); - write!(self.result(), "br_if {relative_depth} (;{label};)")?; - Ok(OpKind::Normal) - } - fn visit_br_table(&mut self, _pos: usize, table: BrTable<'a>) -> Self::Output { - self.push_str("br_table"); - for item in table.targets().chain(Some(Ok(table.default()))) { - let item = item?; - let label = self.label(item); - write!(self.result(), " {item} (;{label};)")?; +macro_rules! define_visit { + // General structure of all the operator printer methods: + // + // * Print the name of the insruction as defined in this macro + // * Print any payload, as necessary + // * Return the `OpKind`, as defined by this macro + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident )*) => ($( + fn $visit(&mut self $( , $($arg: $argty),* )?) -> Self::Output { + self.push_str(define_visit!(name $op)); + $( + define_visit!(payload self $op $($arg)*); + )? + Ok(define_visit!(kind $op)) } - Ok(OpKind::Normal) - } - fn visit_return(&mut self, _pos: usize) -> Self::Output { - self.instr("return") - } - fn visit_call(&mut self, _pos: usize, function_index: u32) -> Self::Output { - self.push_str("call "); - self.print_func_idx(function_index)?; - Ok(OpKind::Normal) - } - fn visit_return_call(&mut self, _pos: usize, function_index: u32) -> Self::Output { - self.push_str("return_call "); - self.print_func_idx(function_index)?; - Ok(OpKind::Normal) - } - fn visit_call_indirect( - &mut self, - _pos: usize, - index: u32, - table_index: u32, - _table_byte: u8, - ) -> Self::Output { - self.push_str("call_indirect"); - if table_index != 0 { - self.push_str(" "); - self.print_table_idx(table_index)?; + )*); + + // Macro case to classify instructions based on their `$op` naming into an + // `OpKind`. There are a few special cases here but the vast majority of + // operators fall into the `Normal` category. + (kind Block) => (OpKind::BlockStart); + (kind Loop) => (OpKind::BlockStart); + (kind If) => (OpKind::BlockStart); + (kind Try) => (OpKind::BlockStart); + (kind Else) => (OpKind::BlockMid); + (kind Catch) => (OpKind::BlockMid); + (kind CatchAll) => (OpKind::BlockMid); + (kind End) => (OpKind::End); + (kind Delegate) => (OpKind::Delegate); + (kind $other:tt) => (OpKind::Normal); + + // How to print the payload of an instruction. There are a number of + // instructions that have special cases such as avoiding printing anything + // when an index is 0 or similar. The final case in this list is the + // catch-all which prints each payload individually based on the name of the + // payload field. + (payload $self:ident CallIndirect $ty:ident $table:ident $byte:ident) => ( + if $table != 0 { + $self.push_str(" "); + $self.table_index($table)?; } - self.print_type_ref(index)?; - Ok(OpKind::Normal) - } - fn visit_return_call_indirect( - &mut self, - _pos: usize, - index: u32, - table_index: u32, - ) -> Self::Output { - self.push_str("return_call_indirect"); - if table_index != 0 { - self.push_str(" "); - self.print_table_idx(table_index)?; + $self.type_index($ty)?; + let _ = $byte; + ); + (payload $self:ident ReturnCallIndirect $ty:ident $table:ident) => ( + if $table != 0 { + $self.push_str(" "); + $self.table_index($table)?; } - self.print_type_ref(index)?; - Ok(OpKind::Normal) - } - - fn visit_drop(&mut self, _pos: usize) -> Self::Output { - self.instr("drop") - } - fn visit_select(&mut self, _pos: usize) -> Self::Output { - self.instr("select") - } - fn visit_typed_select(&mut self, _pos: usize, ty: ValType) -> Self::Output { - self.push_str("select (result "); - self.print_valtype(ty)?; - self.instr(")") - } - - fn visit_ref_null(&mut self, _pos: usize, ty: ValType) -> Self::Output { - self.push_str("ref.null "); - self.printer.print_reftype(ty)?; - Ok(OpKind::Normal) - } - fn visit_ref_is_null(&mut self, _pos: usize) -> Self::Output { - self.instr("ref.is_null") - } - fn visit_ref_func(&mut self, _pos: usize, function_index: u32) -> Self::Output { - self.push_str("ref.func "); - self.print_func_idx(function_index)?; - Ok(OpKind::Normal) - } - - fn visit_local_get(&mut self, _pos: usize, local_index: u32) -> Self::Output { - self.push_str("local.get "); - self.print_local_idx(local_index)?; - Ok(OpKind::Normal) - } - fn visit_local_set(&mut self, _pos: usize, local_index: u32) -> Self::Output { - self.push_str("local.set "); - self.print_local_idx(local_index)?; - Ok(OpKind::Normal) - } - fn visit_local_tee(&mut self, _pos: usize, local_index: u32) -> Self::Output { - self.push_str("local.tee "); - self.print_local_idx(local_index)?; - Ok(OpKind::Normal) - } - fn visit_global_get(&mut self, _pos: usize, global_index: u32) -> Self::Output { - self.push_str("global.get "); - self.print_global_idx(global_index)?; - Ok(OpKind::Normal) - } - fn visit_global_set(&mut self, _pos: usize, global_index: u32) -> Self::Output { - self.push_str("global.set "); - self.print_global_idx(global_index)?; - Ok(OpKind::Normal) - } - fn visit_table_get(&mut self, _pos: usize, table: u32) -> Self::Output { - self.push_str("table.get "); - self.print_table_idx(table)?; - Ok(OpKind::Normal) - } - fn visit_table_set(&mut self, _pos: usize, table: u32) -> Self::Output { - self.push_str("table.set "); - self.print_table_idx(table)?; - Ok(OpKind::Normal) - } - fn visit_table_init(&mut self, _pos: usize, segment: u32, table: u32) -> Self::Output { - self.push_str("table.init "); - if table != 0 { - self.print_table_idx(table)?; - self.push_str(" "); + $self.type_index($ty)?; + ); + (payload $self:ident CallRef $ty:ident) => ( + $self.push_str(" "); + $self.printer.print_idx(&$self.state.core.type_names, $ty)?; + ); + (payload $self:ident ReturnCallRef $ty:ident) => ( + $self.push_str(" "); + $self.printer.print_idx(&$self.state.core.type_names, $ty)?; + ); + (payload $self:ident TypedSelect $ty:ident) => ( + $self.push_str(" (result "); + $self.printer.print_valtype($ty)?; + $self.push_str(")") + ); + (payload $self:ident RefNull $hty:ident) => ( + $self.push_str(" "); + $self.printer.print_heaptype($hty)?; + ); + (payload $self:ident TableInit $segment:ident $table:ident) => ( + $self.push_str(" "); + if $table != 0 { + $self.table_index($table)?; + $self.push_str(" "); } - self.print_element_idx(segment)?; - Ok(OpKind::Normal) - } - fn visit_elem_drop(&mut self, _pos: usize, segment: u32) -> Self::Output { - self.push_str("elem.drop "); - self.print_element_idx(segment)?; - Ok(OpKind::Normal) - } - fn visit_table_copy(&mut self, _pos: usize, dst: u32, src: u32) -> Self::Output { - self.push_str("table.copy"); - if dst != 0 || src != 0 { - self.push_str(" "); - self.print_table_idx(dst)?; - self.push_str(" "); - self.print_table_idx(src)?; + $self.elem_index($segment)?; + ); + (payload $self:ident TableCopy $dst:ident $src:ident) => ( + if $src != 0 || $dst != 0 { + $self.push_str(" "); + $self.table_index($dst)?; + $self.push_str(" "); + $self.table_index($src)?; } - Ok(OpKind::Normal) - } - fn visit_table_grow(&mut self, _pos: usize, table: u32) -> Self::Output { - self.push_str("table.grow "); - self.print_table_idx(table)?; - Ok(OpKind::Normal) - } - fn visit_table_size(&mut self, _pos: usize, table: u32) -> Self::Output { - self.push_str("table.size "); - self.print_table_idx(table)?; - Ok(OpKind::Normal) - } - fn visit_table_fill(&mut self, _pos: usize, table: u32) -> Self::Output { - self.push_str("table.fill "); - self.print_table_idx(table)?; - Ok(OpKind::Normal) - } - fn visit_i32_load(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.load", &memarg, 4) - } - fn visit_i64_load(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.load", &memarg, 8) - } - fn visit_f32_load(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("f32.load", &memarg, 4) - } - fn visit_f64_load(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("f64.load", &memarg, 8) - } - fn visit_i32_load8_s(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.load8_s", &memarg, 1) - } - fn visit_i32_load8_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.load8_u", &memarg, 1) - } - fn visit_i32_load16_s(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.load16_s", &memarg, 2) - } - fn visit_i32_load16_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.load16_u", &memarg, 2) - } - fn visit_i64_load8_s(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.load8_s", &memarg, 1) - } - fn visit_i64_load8_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.load8_u", &memarg, 1) - } - fn visit_i64_load16_s(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.load16_s", &memarg, 2) - } - fn visit_i64_load16_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.load16_u", &memarg, 2) - } - fn visit_i64_load32_s(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.load32_s", &memarg, 4) - } - fn visit_i64_load32_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.load32_u", &memarg, 4) - } - fn visit_i32_store(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.store", &memarg, 4) - } - fn visit_i64_store(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.store", &memarg, 8) - } - fn visit_f32_store(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("f32.store", &memarg, 4) - } - fn visit_f64_store(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("f64.store", &memarg, 8) - } - fn visit_i32_store8(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.store8", &memarg, 1) - } - fn visit_i32_store16(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.store16", &memarg, 2) - } - fn visit_i64_store8(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.store8", &memarg, 1) - } - fn visit_i64_store16(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.store16", &memarg, 2) - } - fn visit_i64_store32(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.store32", &memarg, 4) - } - fn visit_memory_size(&mut self, _pos: usize, mem: u32, _mem_byte: u8) -> Self::Output { - self.push_str("memory.size"); - if mem != 0 { - self.push_str(" "); - self.print_memory_idx(mem)?; + ); + (payload $self:ident $mem_op:ident $mem:ident mem_byte) => ( + if $mem != 0 { + $self.push_str(" "); + $self.memory_index($mem)?; } - Ok(OpKind::Normal) - } - fn visit_memory_grow(&mut self, _pos: usize, mem: u32, _mem_byte: u8) -> Self::Output { - self.push_str("memory.grow"); - if mem != 0 { - self.push_str(" "); - self.print_memory_idx(mem)?; + ); + (payload $self:ident MemoryInit $segment:ident $mem:ident) => ( + if $mem != 0 { + $self.push_str(" "); + $self.memory_index($mem)?; } - Ok(OpKind::Normal) - } - fn visit_memory_init(&mut self, _pos: usize, segment: u32, mem: u32) -> Self::Output { - self.push_str("memory.init "); - if mem != 0 { - self.print_memory_idx(mem)?; - self.push_str(" "); + $self.push_str(" "); + $self.data_index($segment)?; + ); + (payload $self:ident MemoryCopy $dst:ident $src:ident) => ( + if $src != 0 || $dst != 0 { + $self.push_str(" "); + $self.memory_index($dst)?; + $self.push_str(" "); + $self.memory_index($src)?; } - self.print_data_idx(segment)?; - Ok(OpKind::Normal) - } - fn visit_data_drop(&mut self, _pos: usize, segment: u32) -> Self::Output { - self.push_str("data.drop "); - self.print_data_idx(segment)?; - Ok(OpKind::Normal) - } - fn visit_memory_copy(&mut self, _pos: usize, dst: u32, src: u32) -> Self::Output { - self.push_str("memory.copy"); - if dst != 0 || src != 0 { - self.push_str(" "); - self.print_memory_idx(dst)?; - self.push_str(" "); - self.print_memory_idx(src)?; + ); + (payload $self:ident MemoryFill $mem:ident) => ( + if $mem != 0 { + $self.push_str(" "); + $self.memory_index($mem)?; } - Ok(OpKind::Normal) - } - fn visit_memory_fill(&mut self, _pos: usize, mem: u32) -> Self::Output { - self.push_str("memory.fill"); - if mem != 0 { - self.push_str(" "); - self.print_memory_idx(mem)?; + ); + (payload $self:ident MemoryDiscard $mem:ident) => ( + if $mem != 0 { + $self.push_str(" "); + $self.memory_index($mem)?; } - Ok(OpKind::Normal) - } - fn visit_i32_const(&mut self, _pos: usize, value: i32) -> Self::Output { - write!(self.result(), "i32.const {value}")?; - Ok(OpKind::Normal) - } - fn visit_i64_const(&mut self, _pos: usize, value: i64) -> Self::Output { - write!(self.result(), "i64.const {value}")?; - Ok(OpKind::Normal) - } - fn visit_f32_const(&mut self, _pos: usize, value: Ieee32) -> Self::Output { - self.push_str("f32.const "); - self.printer.print_f32(value.bits())?; - Ok(OpKind::Normal) - } - fn visit_f64_const(&mut self, _pos: usize, value: Ieee64) -> Self::Output { - self.push_str("f64.const "); - self.printer.print_f64(value.bits())?; - Ok(OpKind::Normal) - } - fn visit_i32_eqz(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.eqz") - } - fn visit_i32_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.eq") - } - fn visit_i32_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.ne") - } - fn visit_i32_lt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.lt_s") - } - fn visit_i32_lt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.lt_u") - } - fn visit_i32_gt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.gt_s") - } - fn visit_i32_gt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.gt_u") - } - fn visit_i32_le_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.le_s") - } - fn visit_i32_le_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.le_u") - } - fn visit_i32_ge_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.ge_s") - } - fn visit_i32_ge_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.ge_u") - } - fn visit_i64_eqz(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.eqz") - } - fn visit_i64_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.eq") - } - fn visit_i64_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.ne") - } - fn visit_i64_lt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.lt_s") - } - fn visit_i64_lt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.lt_u") - } - fn visit_i64_gt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.gt_s") - } - fn visit_i64_gt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.gt_u") - } - fn visit_i64_le_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.le_s") - } - fn visit_i64_le_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.le_u") - } - fn visit_i64_ge_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.ge_s") - } - fn visit_i64_ge_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.ge_u") - } - fn visit_f32_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.eq") - } - fn visit_f32_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.ne") - } - fn visit_f32_lt(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.lt") - } - fn visit_f32_gt(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.gt") - } - fn visit_f32_le(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.le") - } - fn visit_f32_ge(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.ge") - } - fn visit_f64_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.eq") - } - fn visit_f64_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.ne") - } - fn visit_f64_lt(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.lt") - } - fn visit_f64_gt(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.gt") - } - fn visit_f64_le(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.le") - } - fn visit_f64_ge(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.ge") - } - fn visit_i32_clz(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.clz") - } - fn visit_i32_ctz(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.ctz") - } - fn visit_i32_popcnt(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.popcnt") - } - fn visit_i32_add(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.add") - } - fn visit_i32_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.sub") - } - fn visit_i32_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.mul") - } - fn visit_i32_div_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.div_s") - } - fn visit_i32_div_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.div_u") - } - fn visit_i32_rem_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.rem_s") - } - fn visit_i32_rem_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.rem_u") - } - fn visit_i32_and(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.and") - } - fn visit_i32_or(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.or") - } - fn visit_i32_xor(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.xor") - } - fn visit_i32_shl(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.shl") - } - fn visit_i32_shr_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.shr_s") - } - fn visit_i32_shr_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.shr_u") - } - fn visit_i32_rotl(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.rotl") - } - fn visit_i32_rotr(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.rotr") - } - - fn visit_i64_clz(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.clz") - } - fn visit_i64_ctz(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.ctz") - } - fn visit_i64_popcnt(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.popcnt") - } - fn visit_i64_add(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.add") - } - fn visit_i64_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.sub") - } - fn visit_i64_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.mul") - } - fn visit_i64_div_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.div_s") - } - fn visit_i64_div_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.div_u") - } - fn visit_i64_rem_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.rem_s") - } - fn visit_i64_rem_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.rem_u") - } - fn visit_i64_and(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.and") - } - fn visit_i64_or(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.or") - } - fn visit_i64_xor(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.xor") - } - fn visit_i64_shl(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.shl") - } - fn visit_i64_shr_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.shr_s") - } - fn visit_i64_shr_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.shr_u") - } - fn visit_i64_rotl(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.rotl") - } - fn visit_i64_rotr(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.rotr") - } - - fn visit_f32_abs(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.abs") - } - fn visit_f32_neg(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.neg") - } - fn visit_f32_ceil(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.ceil") - } - fn visit_f32_floor(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.floor") - } - fn visit_f32_trunc(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.trunc") - } - fn visit_f32_nearest(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.nearest") - } - fn visit_f32_sqrt(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.sqrt") - } - fn visit_f32_add(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.add") - } - fn visit_f32_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.sub") - } - fn visit_f32_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.mul") - } - fn visit_f32_div(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.div") - } - fn visit_f32_min(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.min") - } - fn visit_f32_max(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.max") - } - fn visit_f32_copysign(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.copysign") - } - - fn visit_f64_abs(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.abs") - } - fn visit_f64_neg(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.neg") - } - fn visit_f64_ceil(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.ceil") - } - fn visit_f64_floor(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.floor") - } - fn visit_f64_trunc(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.trunc") - } - fn visit_f64_nearest(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.nearest") - } - fn visit_f64_sqrt(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.sqrt") - } - fn visit_f64_add(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.add") - } - fn visit_f64_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.sub") - } - fn visit_f64_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.mul") - } - fn visit_f64_div(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.div") - } - fn visit_f64_min(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.min") - } - fn visit_f64_max(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.max") - } - fn visit_f64_copysign(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.copysign") - } - - fn visit_i32_wrap_i64(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.wrap_i64") - } - fn visit_i32_trunc_f32_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.trunc_f32_s") - } - fn visit_i32_trunc_f32_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.trunc_f32_u") - } - fn visit_i32_trunc_f64_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.trunc_f64_s") - } - fn visit_i32_trunc_f64_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.trunc_f64_u") - } - fn visit_i64_extend_i32_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.extend_i32_s") - } - fn visit_i64_extend_i32_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.extend_i32_u") - } - fn visit_i64_trunc_f32_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.trunc_f32_s") - } - fn visit_i64_trunc_f32_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.trunc_f32_u") - } - fn visit_i64_trunc_f64_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.trunc_f64_s") - } - fn visit_i64_trunc_f64_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.trunc_f64_u") - } + ); + (payload $self:ident I32Const $val:ident) => (write!($self.result(), " {}", $val)?); + (payload $self:ident I64Const $val:ident) => (write!($self.result(), " {}", $val)?); + (payload $self:ident F32Const $val:ident) => ( + $self.push_str(" "); + $self.printer.print_f32($val.bits())?; + ); + (payload $self:ident F64Const $val:ident) => ( + $self.push_str(" "); + $self.printer.print_f64($val.bits())?; + ); + (payload $self:ident V128Const $val:ident) => ( + $self.push_str(" i32x4"); + for chunk in $val.bytes().chunks(4) { + write!( + $self.result(), + " 0x{:02x}{:02x}{:02x}{:02x}", + chunk[3], + chunk[2], + chunk[1], + chunk[0], + )?; + } + ); + (payload $self:ident $op:ident $($arg:ident)*) => ( + $( + $self.push_str(" "); + $self.$arg($arg)?; + )* + ); + + (name Block) => ("block"); + (name If) => ("if"); + (name Else) => ("else"); + (name Loop) => ("loop"); + (name End) => ("end"); + (name Unreachable) => ("unreachable"); + (name Nop) => ("nop"); + (name Br) => ("br"); + (name BrIf) => ("br_if"); + (name BrOnNull) => ("br_on_null"); + (name BrOnNonNull) => ("br_on_non_null"); + (name BrTable) => ("br_table"); + (name Return) => ("return"); + (name Call) => ("call"); + (name CallIndirect) => ("call_indirect"); + (name CallRef) => ("call_ref"); + (name ReturnCall) => ("return_call"); + (name ReturnCallIndirect) => ("return_call_indirect"); + (name ReturnCallRef) => ("return_call_ref"); + (name Drop) => ("drop"); + (name Select) => ("select"); + (name TypedSelect) => ("select"); + (name LocalGet) => ("local.get"); + (name LocalSet) => ("local.set"); + (name LocalTee) => ("local.tee"); + (name GlobalGet) => ("global.get"); + (name GlobalSet) => ("global.set"); + (name TableGet) => ("table.get"); + (name TableSet) => ("table.set"); + (name I32Load) => ("i32.load"); + (name I64Load) => ("i64.load"); + (name F32Load) => ("f32.load"); + (name F64Load) => ("f64.load"); + (name I32Load8S) => ("i32.load8_s"); + (name I32Load8U) => ("i32.load8_u"); + (name I32Load16S) => ("i32.load16_s"); + (name I32Load16U) => ("i32.load16_u"); + (name I64Load8S) => ("i64.load8_s"); + (name I64Load8U) => ("i64.load8_u"); + (name I64Load16S) => ("i64.load16_s"); + (name I64Load16U) => ("i64.load16_u"); + (name I64Load32S) => ("i64.load32_s"); + (name I64Load32U) => ("i64.load32_u"); + (name I32Store) => ("i32.store"); + (name I64Store) => ("i64.store"); + (name F32Store) => ("f32.store"); + (name F64Store) => ("f64.store"); + (name I32Store8) => ("i32.store8"); + (name I32Store16) => ("i32.store16"); + (name I64Store8) => ("i64.store8"); + (name I64Store16) => ("i64.store16"); + (name I64Store32) => ("i64.store32"); + (name MemorySize) => ("memory.size"); + (name MemoryGrow) => ("memory.grow"); + (name MemoryInit) => ("memory.init"); + (name MemoryCopy) => ("memory.copy"); + (name MemoryFill) => ("memory.fill"); + (name MemoryDiscard) => ("memory.discard"); + (name DataDrop) => ("data.drop"); + (name ElemDrop) => ("elem.drop"); + (name TableInit) => ("table.init"); + (name TableCopy) => ("table.copy"); + (name TableFill) => ("table.fill"); + (name TableSize) => ("table.size"); + (name TableGrow) => ("table.grow"); + (name RefAsNonNull) => ("ref.as_non_null"); + (name RefNull) => ("ref.null"); + (name RefIsNull) => ("ref.is_null"); + (name RefFunc) => ("ref.func"); + (name I32Const) => ("i32.const"); + (name I64Const) => ("i64.const"); + (name F32Const) => ("f32.const"); + (name F64Const) => ("f64.const"); + (name I32Clz) => ("i32.clz"); + (name I32Ctz) => ("i32.ctz"); + (name I32Popcnt) => ("i32.popcnt"); + (name I32Add) => ("i32.add"); + (name I32Sub) => ("i32.sub"); + (name I32Mul) => ("i32.mul"); + (name I32DivS) => ("i32.div_s"); + (name I32DivU) => ("i32.div_u"); + (name I32RemS) => ("i32.rem_s"); + (name I32RemU) => ("i32.rem_u"); + (name I32And) => ("i32.and"); + (name I32Or) => ("i32.or"); + (name I32Xor) => ("i32.xor"); + (name I32Shl) => ("i32.shl"); + (name I32ShrS) => ("i32.shr_s"); + (name I32ShrU) => ("i32.shr_u"); + (name I32Rotl) => ("i32.rotl"); + (name I32Rotr) => ("i32.rotr"); + (name I64Clz) => ("i64.clz"); + (name I64Ctz) => ("i64.ctz"); + (name I64Popcnt) => ("i64.popcnt"); + (name I64Add) => ("i64.add"); + (name I64Sub) => ("i64.sub"); + (name I64Mul) => ("i64.mul"); + (name I64DivS) => ("i64.div_s"); + (name I64DivU) => ("i64.div_u"); + (name I64RemS) => ("i64.rem_s"); + (name I64RemU) => ("i64.rem_u"); + (name I64And) => ("i64.and"); + (name I64Or) => ("i64.or"); + (name I64Xor) => ("i64.xor"); + (name I64Shl) => ("i64.shl"); + (name I64ShrS) => ("i64.shr_s"); + (name I64ShrU) => ("i64.shr_u"); + (name I64Rotl) => ("i64.rotl"); + (name I64Rotr) => ("i64.rotr"); + (name F32Abs) => ("f32.abs"); + (name F32Neg) => ("f32.neg"); + (name F32Ceil) => ("f32.ceil"); + (name F32Floor) => ("f32.floor"); + (name F32Trunc) => ("f32.trunc"); + (name F32Nearest) => ("f32.nearest"); + (name F32Sqrt) => ("f32.sqrt"); + (name F32Add) => ("f32.add"); + (name F32Sub) => ("f32.sub"); + (name F32Mul) => ("f32.mul"); + (name F32Div) => ("f32.div"); + (name F32Min) => ("f32.min"); + (name F32Max) => ("f32.max"); + (name F32Copysign) => ("f32.copysign"); + (name F64Abs) => ("f64.abs"); + (name F64Neg) => ("f64.neg"); + (name F64Ceil) => ("f64.ceil"); + (name F64Floor) => ("f64.floor"); + (name F64Trunc) => ("f64.trunc"); + (name F64Nearest) => ("f64.nearest"); + (name F64Sqrt) => ("f64.sqrt"); + (name F64Add) => ("f64.add"); + (name F64Sub) => ("f64.sub"); + (name F64Mul) => ("f64.mul"); + (name F64Div) => ("f64.div"); + (name F64Min) => ("f64.min"); + (name F64Max) => ("f64.max"); + (name F64Copysign) => ("f64.copysign"); + (name I32Eqz) => ("i32.eqz"); + (name I32Eq) => ("i32.eq"); + (name I32Ne) => ("i32.ne"); + (name I32LtS) => ("i32.lt_s"); + (name I32LtU) => ("i32.lt_u"); + (name I32GtS) => ("i32.gt_s"); + (name I32GtU) => ("i32.gt_u"); + (name I32LeS) => ("i32.le_s"); + (name I32LeU) => ("i32.le_u"); + (name I32GeS) => ("i32.ge_s"); + (name I32GeU) => ("i32.ge_u"); + (name I64Eqz) => ("i64.eqz"); + (name I64Eq) => ("i64.eq"); + (name I64Ne) => ("i64.ne"); + (name I64LtS) => ("i64.lt_s"); + (name I64LtU) => ("i64.lt_u"); + (name I64GtS) => ("i64.gt_s"); + (name I64GtU) => ("i64.gt_u"); + (name I64LeS) => ("i64.le_s"); + (name I64LeU) => ("i64.le_u"); + (name I64GeS) => ("i64.ge_s"); + (name I64GeU) => ("i64.ge_u"); + (name F32Eq) => ("f32.eq"); + (name F32Ne) => ("f32.ne"); + (name F32Lt) => ("f32.lt"); + (name F32Gt) => ("f32.gt"); + (name F32Le) => ("f32.le"); + (name F32Ge) => ("f32.ge"); + (name F64Eq) => ("f64.eq"); + (name F64Ne) => ("f64.ne"); + (name F64Lt) => ("f64.lt"); + (name F64Gt) => ("f64.gt"); + (name F64Le) => ("f64.le"); + (name F64Ge) => ("f64.ge"); + (name I32WrapI64) => ("i32.wrap_i64"); + (name I32TruncF32S) => ("i32.trunc_f32_s"); + (name I32TruncF32U) => ("i32.trunc_f32_u"); + (name I32TruncF64S) => ("i32.trunc_f64_s"); + (name I32TruncF64U) => ("i32.trunc_f64_u"); + (name I64ExtendI32S) => ("i64.extend_i32_s"); + (name I64ExtendI32U) => ("i64.extend_i32_u"); + (name I64TruncF32S) => ("i64.trunc_f32_s"); + (name I64TruncF32U) => ("i64.trunc_f32_u"); + (name I64TruncF64S) => ("i64.trunc_f64_s"); + (name I64TruncF64U) => ("i64.trunc_f64_u"); + (name F32ConvertI32S) => ("f32.convert_i32_s"); + (name F32ConvertI32U) => ("f32.convert_i32_u"); + (name F32ConvertI64S) => ("f32.convert_i64_s"); + (name F32ConvertI64U) => ("f32.convert_i64_u"); + (name F32DemoteF64) => ("f32.demote_f64"); + (name F64ConvertI32S) => ("f64.convert_i32_s"); + (name F64ConvertI32U) => ("f64.convert_i32_u"); + (name F64ConvertI64S) => ("f64.convert_i64_s"); + (name F64ConvertI64U) => ("f64.convert_i64_u"); + (name F64PromoteF32) => ("f64.promote_f32"); + (name I32ReinterpretF32) => ("i32.reinterpret_f32"); + (name I64ReinterpretF64) => ("i64.reinterpret_f64"); + (name F32ReinterpretI32) => ("f32.reinterpret_i32"); + (name F64ReinterpretI64) => ("f64.reinterpret_i64"); + (name I32TruncSatF32S) => ("i32.trunc_sat_f32_s"); + (name I32TruncSatF32U) => ("i32.trunc_sat_f32_u"); + (name I32TruncSatF64S) => ("i32.trunc_sat_f64_s"); + (name I32TruncSatF64U) => ("i32.trunc_sat_f64_u"); + (name I64TruncSatF32S) => ("i64.trunc_sat_f32_s"); + (name I64TruncSatF32U) => ("i64.trunc_sat_f32_u"); + (name I64TruncSatF64S) => ("i64.trunc_sat_f64_s"); + (name I64TruncSatF64U) => ("i64.trunc_sat_f64_u"); + (name I32Extend8S) => ("i32.extend8_s"); + (name I32Extend16S) => ("i32.extend16_s"); + (name I64Extend8S) => ("i64.extend8_s"); + (name I64Extend16S) => ("i64.extend16_s"); + (name I64Extend32S) => ("i64.extend32_s"); + (name MemoryAtomicNotify) => ("memory.atomic.notify"); + (name MemoryAtomicWait32) => ("memory.atomic.wait32"); + (name MemoryAtomicWait64) => ("memory.atomic.wait64"); + (name AtomicFence) => ("atomic.fence"); + (name I32AtomicLoad) => ("i32.atomic.load"); + (name I64AtomicLoad) => ("i64.atomic.load"); + (name I32AtomicLoad8U) => ("i32.atomic.load8_u"); + (name I32AtomicLoad16U) => ("i32.atomic.load16_u"); + (name I64AtomicLoad8U) => ("i64.atomic.load8_u"); + (name I64AtomicLoad16U) => ("i64.atomic.load16_u"); + (name I64AtomicLoad32U) => ("i64.atomic.load32_u"); + (name I32AtomicStore) => ("i32.atomic.store"); + (name I64AtomicStore) => ("i64.atomic.store"); + (name I32AtomicStore8) => ("i32.atomic.store8"); + (name I32AtomicStore16) => ("i32.atomic.store16"); + (name I64AtomicStore8) => ("i64.atomic.store8"); + (name I64AtomicStore16) => ("i64.atomic.store16"); + (name I64AtomicStore32) => ("i64.atomic.store32"); + (name I32AtomicRmwAdd) => ("i32.atomic.rmw.add"); + (name I64AtomicRmwAdd) => ("i64.atomic.rmw.add"); + (name I32AtomicRmw8AddU) => ("i32.atomic.rmw8.add_u"); + (name I32AtomicRmw16AddU) => ("i32.atomic.rmw16.add_u"); + (name I64AtomicRmw8AddU) => ("i64.atomic.rmw8.add_u"); + (name I64AtomicRmw16AddU) => ("i64.atomic.rmw16.add_u"); + (name I64AtomicRmw32AddU) => ("i64.atomic.rmw32.add_u"); + (name I32AtomicRmwSub) => ("i32.atomic.rmw.sub"); + (name I64AtomicRmwSub) => ("i64.atomic.rmw.sub"); + (name I32AtomicRmw8SubU) => ("i32.atomic.rmw8.sub_u"); + (name I32AtomicRmw16SubU) => ("i32.atomic.rmw16.sub_u"); + (name I64AtomicRmw8SubU) => ("i64.atomic.rmw8.sub_u"); + (name I64AtomicRmw16SubU) => ("i64.atomic.rmw16.sub_u"); + (name I64AtomicRmw32SubU) => ("i64.atomic.rmw32.sub_u"); + (name I32AtomicRmwAnd) => ("i32.atomic.rmw.and"); + (name I64AtomicRmwAnd) => ("i64.atomic.rmw.and"); + (name I32AtomicRmw8AndU) => ("i32.atomic.rmw8.and_u"); + (name I32AtomicRmw16AndU) => ("i32.atomic.rmw16.and_u"); + (name I64AtomicRmw8AndU) => ("i64.atomic.rmw8.and_u"); + (name I64AtomicRmw16AndU) => ("i64.atomic.rmw16.and_u"); + (name I64AtomicRmw32AndU) => ("i64.atomic.rmw32.and_u"); + (name I32AtomicRmwOr) => ("i32.atomic.rmw.or"); + (name I64AtomicRmwOr) => ("i64.atomic.rmw.or"); + (name I32AtomicRmw8OrU) => ("i32.atomic.rmw8.or_u"); + (name I32AtomicRmw16OrU) => ("i32.atomic.rmw16.or_u"); + (name I64AtomicRmw8OrU) => ("i64.atomic.rmw8.or_u"); + (name I64AtomicRmw16OrU) => ("i64.atomic.rmw16.or_u"); + (name I64AtomicRmw32OrU) => ("i64.atomic.rmw32.or_u"); + (name I32AtomicRmwXor) => ("i32.atomic.rmw.xor"); + (name I64AtomicRmwXor) => ("i64.atomic.rmw.xor"); + (name I32AtomicRmw8XorU) => ("i32.atomic.rmw8.xor_u"); + (name I32AtomicRmw16XorU) => ("i32.atomic.rmw16.xor_u"); + (name I64AtomicRmw8XorU) => ("i64.atomic.rmw8.xor_u"); + (name I64AtomicRmw16XorU) => ("i64.atomic.rmw16.xor_u"); + (name I64AtomicRmw32XorU) => ("i64.atomic.rmw32.xor_u"); + (name I32AtomicRmwXchg) => ("i32.atomic.rmw.xchg"); + (name I64AtomicRmwXchg) => ("i64.atomic.rmw.xchg"); + (name I32AtomicRmw8XchgU) => ("i32.atomic.rmw8.xchg_u"); + (name I32AtomicRmw16XchgU) => ("i32.atomic.rmw16.xchg_u"); + (name I64AtomicRmw8XchgU) => ("i64.atomic.rmw8.xchg_u"); + (name I64AtomicRmw16XchgU) => ("i64.atomic.rmw16.xchg_u"); + (name I64AtomicRmw32XchgU) => ("i64.atomic.rmw32.xchg_u"); + (name I32AtomicRmwCmpxchg) => ("i32.atomic.rmw.cmpxchg"); + (name I64AtomicRmwCmpxchg) => ("i64.atomic.rmw.cmpxchg"); + (name I32AtomicRmw8CmpxchgU) => ("i32.atomic.rmw8.cmpxchg_u"); + (name I32AtomicRmw16CmpxchgU) => ("i32.atomic.rmw16.cmpxchg_u"); + (name I64AtomicRmw8CmpxchgU) => ("i64.atomic.rmw8.cmpxchg_u"); + (name I64AtomicRmw16CmpxchgU) => ("i64.atomic.rmw16.cmpxchg_u"); + (name I64AtomicRmw32CmpxchgU) => ("i64.atomic.rmw32.cmpxchg_u"); + (name V128Load) => ("v128.load"); + (name V128Load8x8S) => ("v128.load8x8_s"); + (name V128Load8x8U) => ("v128.load8x8_u"); + (name V128Load16x4S) => ("v128.load16x4_s"); + (name V128Load16x4U) => ("v128.load16x4_u"); + (name V128Load32x2S) => ("v128.load32x2_s"); + (name V128Load32x2U) => ("v128.load32x2_u"); + (name V128Load8Splat) => ("v128.load8_splat"); + (name V128Load16Splat) => ("v128.load16_splat"); + (name V128Load32Splat) => ("v128.load32_splat"); + (name V128Load64Splat) => ("v128.load64_splat"); + (name V128Load32Zero) => ("v128.load32_zero"); + (name V128Load64Zero) => ("v128.load64_zero"); + (name V128Store) => ("v128.store"); + (name V128Load8Lane) => ("v128.load8_lane"); + (name V128Load16Lane) => ("v128.load16_lane"); + (name V128Load32Lane) => ("v128.load32_lane"); + (name V128Load64Lane) => ("v128.load64_lane"); + (name V128Store8Lane) => ("v128.store8_lane"); + (name V128Store16Lane) => ("v128.store16_lane"); + (name V128Store32Lane) => ("v128.store32_lane"); + (name V128Store64Lane) => ("v128.store64_lane"); + (name V128Const) => ("v128.const"); + (name I8x16Shuffle) => ("i8x16.shuffle"); + (name I8x16ExtractLaneS) => ("i8x16.extract_lane_s"); + (name I8x16ExtractLaneU) => ("i8x16.extract_lane_u"); + (name I8x16ReplaceLane) => ("i8x16.replace_lane"); + (name I16x8ExtractLaneS) => ("i16x8.extract_lane_s"); + (name I16x8ExtractLaneU) => ("i16x8.extract_lane_u"); + (name I16x8ReplaceLane) => ("i16x8.replace_lane"); + (name I32x4ExtractLane) => ("i32x4.extract_lane"); + (name I32x4ReplaceLane) => ("i32x4.replace_lane"); + (name I64x2ExtractLane) => ("i64x2.extract_lane"); + (name I64x2ReplaceLane) => ("i64x2.replace_lane"); + (name F32x4ExtractLane) => ("f32x4.extract_lane"); + (name F32x4ReplaceLane) => ("f32x4.replace_lane"); + (name F64x2ExtractLane) => ("f64x2.extract_lane"); + (name F64x2ReplaceLane) => ("f64x2.replace_lane"); + (name I8x16Swizzle) => ("i8x16.swizzle"); + (name I8x16Splat) => ("i8x16.splat"); + (name I16x8Splat) => ("i16x8.splat"); + (name I32x4Splat) => ("i32x4.splat"); + (name I64x2Splat) => ("i64x2.splat"); + (name F32x4Splat) => ("f32x4.splat"); + (name F64x2Splat) => ("f64x2.splat"); + (name I8x16Eq) => ("i8x16.eq"); + (name I8x16Ne) => ("i8x16.ne"); + (name I8x16LtS) => ("i8x16.lt_s"); + (name I8x16LtU) => ("i8x16.lt_u"); + (name I8x16GtS) => ("i8x16.gt_s"); + (name I8x16GtU) => ("i8x16.gt_u"); + (name I8x16LeS) => ("i8x16.le_s"); + (name I8x16LeU) => ("i8x16.le_u"); + (name I8x16GeS) => ("i8x16.ge_s"); + (name I8x16GeU) => ("i8x16.ge_u"); + (name I16x8Eq) => ("i16x8.eq"); + (name I16x8Ne) => ("i16x8.ne"); + (name I16x8LtS) => ("i16x8.lt_s"); + (name I16x8LtU) => ("i16x8.lt_u"); + (name I16x8GtS) => ("i16x8.gt_s"); + (name I16x8GtU) => ("i16x8.gt_u"); + (name I16x8LeS) => ("i16x8.le_s"); + (name I16x8LeU) => ("i16x8.le_u"); + (name I16x8GeS) => ("i16x8.ge_s"); + (name I16x8GeU) => ("i16x8.ge_u"); + (name I32x4Eq) => ("i32x4.eq"); + (name I32x4Ne) => ("i32x4.ne"); + (name I32x4LtS) => ("i32x4.lt_s"); + (name I32x4LtU) => ("i32x4.lt_u"); + (name I32x4GtS) => ("i32x4.gt_s"); + (name I32x4GtU) => ("i32x4.gt_u"); + (name I32x4LeS) => ("i32x4.le_s"); + (name I32x4LeU) => ("i32x4.le_u"); + (name I32x4GeS) => ("i32x4.ge_s"); + (name I32x4GeU) => ("i32x4.ge_u"); + (name I64x2Eq) => ("i64x2.eq"); + (name I64x2Ne) => ("i64x2.ne"); + (name I64x2LtS) => ("i64x2.lt_s"); + (name I64x2GtS) => ("i64x2.gt_s"); + (name I64x2LeS) => ("i64x2.le_s"); + (name I64x2GeS) => ("i64x2.ge_s"); + (name F32x4Eq) => ("f32x4.eq"); + (name F32x4Ne) => ("f32x4.ne"); + (name F32x4Lt) => ("f32x4.lt"); + (name F32x4Gt) => ("f32x4.gt"); + (name F32x4Le) => ("f32x4.le"); + (name F32x4Ge) => ("f32x4.ge"); + (name F64x2Eq) => ("f64x2.eq"); + (name F64x2Ne) => ("f64x2.ne"); + (name F64x2Lt) => ("f64x2.lt"); + (name F64x2Gt) => ("f64x2.gt"); + (name F64x2Le) => ("f64x2.le"); + (name F64x2Ge) => ("f64x2.ge"); + (name V128Not) => ("v128.not"); + (name V128And) => ("v128.and"); + (name V128AndNot) => ("v128.andnot"); + (name V128Or) => ("v128.or"); + (name V128Xor) => ("v128.xor"); + (name V128Bitselect) => ("v128.bitselect"); + (name V128AnyTrue) => ("v128.any_true"); + (name I8x16Abs) => ("i8x16.abs"); + (name I8x16Neg) => ("i8x16.neg"); + (name I8x16Popcnt) => ("i8x16.popcnt"); + (name I8x16AllTrue) => ("i8x16.all_true"); + (name I8x16Bitmask) => ("i8x16.bitmask"); + (name I8x16NarrowI16x8S) => ("i8x16.narrow_i16x8_s"); + (name I8x16NarrowI16x8U) => ("i8x16.narrow_i16x8_u"); + (name I8x16Shl) => ("i8x16.shl"); + (name I8x16ShrS) => ("i8x16.shr_s"); + (name I8x16ShrU) => ("i8x16.shr_u"); + (name I8x16Add) => ("i8x16.add"); + (name I8x16AddSatS) => ("i8x16.add_sat_s"); + (name I8x16AddSatU) => ("i8x16.add_sat_u"); + (name I8x16Sub) => ("i8x16.sub"); + (name I8x16SubSatS) => ("i8x16.sub_sat_s"); + (name I8x16SubSatU) => ("i8x16.sub_sat_u"); + (name I8x16MinS) => ("i8x16.min_s"); + (name I8x16MinU) => ("i8x16.min_u"); + (name I8x16MaxS) => ("i8x16.max_s"); + (name I8x16MaxU) => ("i8x16.max_u"); + (name I8x16AvgrU) => ("i8x16.avgr_u"); + (name I16x8ExtAddPairwiseI8x16S) => ("i16x8.extadd_pairwise_i8x16_s"); + (name I16x8ExtAddPairwiseI8x16U) => ("i16x8.extadd_pairwise_i8x16_u"); + (name I16x8Abs) => ("i16x8.abs"); + (name I16x8Neg) => ("i16x8.neg"); + (name I16x8Q15MulrSatS) => ("i16x8.q15mulr_sat_s"); + (name I16x8AllTrue) => ("i16x8.all_true"); + (name I16x8Bitmask) => ("i16x8.bitmask"); + (name I16x8NarrowI32x4S) => ("i16x8.narrow_i32x4_s"); + (name I16x8NarrowI32x4U) => ("i16x8.narrow_i32x4_u"); + (name I16x8ExtendLowI8x16S) => ("i16x8.extend_low_i8x16_s"); + (name I16x8ExtendHighI8x16S) => ("i16x8.extend_high_i8x16_s"); + (name I16x8ExtendLowI8x16U) => ("i16x8.extend_low_i8x16_u"); + (name I16x8ExtendHighI8x16U) => ("i16x8.extend_high_i8x16_u"); + (name I16x8Shl) => ("i16x8.shl"); + (name I16x8ShrS) => ("i16x8.shr_s"); + (name I16x8ShrU) => ("i16x8.shr_u"); + (name I16x8Add) => ("i16x8.add"); + (name I16x8AddSatS) => ("i16x8.add_sat_s"); + (name I16x8AddSatU) => ("i16x8.add_sat_u"); + (name I16x8Sub) => ("i16x8.sub"); + (name I16x8SubSatS) => ("i16x8.sub_sat_s"); + (name I16x8SubSatU) => ("i16x8.sub_sat_u"); + (name I16x8Mul) => ("i16x8.mul"); + (name I16x8MinS) => ("i16x8.min_s"); + (name I16x8MinU) => ("i16x8.min_u"); + (name I16x8MaxS) => ("i16x8.max_s"); + (name I16x8MaxU) => ("i16x8.max_u"); + (name I16x8AvgrU) => ("i16x8.avgr_u"); + (name I16x8ExtMulLowI8x16S) => ("i16x8.extmul_low_i8x16_s"); + (name I16x8ExtMulHighI8x16S) => ("i16x8.extmul_high_i8x16_s"); + (name I16x8ExtMulLowI8x16U) => ("i16x8.extmul_low_i8x16_u"); + (name I16x8ExtMulHighI8x16U) => ("i16x8.extmul_high_i8x16_u"); + (name I32x4ExtAddPairwiseI16x8S) => ("i32x4.extadd_pairwise_i16x8_s"); + (name I32x4ExtAddPairwiseI16x8U) => ("i32x4.extadd_pairwise_i16x8_u"); + (name I32x4Abs) => ("i32x4.abs"); + (name I32x4Neg) => ("i32x4.neg"); + (name I32x4AllTrue) => ("i32x4.all_true"); + (name I32x4Bitmask) => ("i32x4.bitmask"); + (name I32x4ExtendLowI16x8S) => ("i32x4.extend_low_i16x8_s"); + (name I32x4ExtendHighI16x8S) => ("i32x4.extend_high_i16x8_s"); + (name I32x4ExtendLowI16x8U) => ("i32x4.extend_low_i16x8_u"); + (name I32x4ExtendHighI16x8U) => ("i32x4.extend_high_i16x8_u"); + (name I32x4Shl) => ("i32x4.shl"); + (name I32x4ShrS) => ("i32x4.shr_s"); + (name I32x4ShrU) => ("i32x4.shr_u"); + (name I32x4Add) => ("i32x4.add"); + (name I32x4Sub) => ("i32x4.sub"); + (name I32x4Mul) => ("i32x4.mul"); + (name I32x4MinS) => ("i32x4.min_s"); + (name I32x4MinU) => ("i32x4.min_u"); + (name I32x4MaxS) => ("i32x4.max_s"); + (name I32x4MaxU) => ("i32x4.max_u"); + (name I32x4DotI16x8S) => ("i32x4.dot_i16x8_s"); + (name I32x4ExtMulLowI16x8S) => ("i32x4.extmul_low_i16x8_s"); + (name I32x4ExtMulHighI16x8S) => ("i32x4.extmul_high_i16x8_s"); + (name I32x4ExtMulLowI16x8U) => ("i32x4.extmul_low_i16x8_u"); + (name I32x4ExtMulHighI16x8U) => ("i32x4.extmul_high_i16x8_u"); + (name I64x2Abs) => ("i64x2.abs"); + (name I64x2Neg) => ("i64x2.neg"); + (name I64x2AllTrue) => ("i64x2.all_true"); + (name I64x2Bitmask) => ("i64x2.bitmask"); + (name I64x2ExtendLowI32x4S) => ("i64x2.extend_low_i32x4_s"); + (name I64x2ExtendHighI32x4S) => ("i64x2.extend_high_i32x4_s"); + (name I64x2ExtendLowI32x4U) => ("i64x2.extend_low_i32x4_u"); + (name I64x2ExtendHighI32x4U) => ("i64x2.extend_high_i32x4_u"); + (name I64x2Shl) => ("i64x2.shl"); + (name I64x2ShrS) => ("i64x2.shr_s"); + (name I64x2ShrU) => ("i64x2.shr_u"); + (name I64x2Add) => ("i64x2.add"); + (name I64x2Sub) => ("i64x2.sub"); + (name I64x2Mul) => ("i64x2.mul"); + (name I64x2ExtMulLowI32x4S) => ("i64x2.extmul_low_i32x4_s"); + (name I64x2ExtMulHighI32x4S) => ("i64x2.extmul_high_i32x4_s"); + (name I64x2ExtMulLowI32x4U) => ("i64x2.extmul_low_i32x4_u"); + (name I64x2ExtMulHighI32x4U) => ("i64x2.extmul_high_i32x4_u"); + (name F32x4Ceil) => ("f32x4.ceil"); + (name F32x4Floor) => ("f32x4.floor"); + (name F32x4Trunc) => ("f32x4.trunc"); + (name F32x4Nearest) => ("f32x4.nearest"); + (name F32x4Abs) => ("f32x4.abs"); + (name F32x4Neg) => ("f32x4.neg"); + (name F32x4Sqrt) => ("f32x4.sqrt"); + (name F32x4Add) => ("f32x4.add"); + (name F32x4Sub) => ("f32x4.sub"); + (name F32x4Mul) => ("f32x4.mul"); + (name F32x4Div) => ("f32x4.div"); + (name F32x4Min) => ("f32x4.min"); + (name F32x4Max) => ("f32x4.max"); + (name F32x4PMin) => ("f32x4.pmin"); + (name F32x4PMax) => ("f32x4.pmax"); + (name F64x2Ceil) => ("f64x2.ceil"); + (name F64x2Floor) => ("f64x2.floor"); + (name F64x2Trunc) => ("f64x2.trunc"); + (name F64x2Nearest) => ("f64x2.nearest"); + (name F64x2Abs) => ("f64x2.abs"); + (name F64x2Neg) => ("f64x2.neg"); + (name F64x2Sqrt) => ("f64x2.sqrt"); + (name F64x2Add) => ("f64x2.add"); + (name F64x2Sub) => ("f64x2.sub"); + (name F64x2Mul) => ("f64x2.mul"); + (name F64x2Div) => ("f64x2.div"); + (name F64x2Min) => ("f64x2.min"); + (name F64x2Max) => ("f64x2.max"); + (name F64x2PMin) => ("f64x2.pmin"); + (name F64x2PMax) => ("f64x2.pmax"); + (name I32x4TruncSatF32x4S) => ("i32x4.trunc_sat_f32x4_s"); + (name I32x4TruncSatF32x4U) => ("i32x4.trunc_sat_f32x4_u"); + (name F32x4ConvertI32x4S) => ("f32x4.convert_i32x4_s"); + (name F32x4ConvertI32x4U) => ("f32x4.convert_i32x4_u"); + (name I32x4TruncSatF64x2SZero) => ("i32x4.trunc_sat_f64x2_s_zero"); + (name I32x4TruncSatF64x2UZero) => ("i32x4.trunc_sat_f64x2_u_zero"); + (name F64x2ConvertLowI32x4S) => ("f64x2.convert_low_i32x4_s"); + (name F64x2ConvertLowI32x4U) => ("f64x2.convert_low_i32x4_u"); + (name F32x4DemoteF64x2Zero) => ("f32x4.demote_f64x2_zero"); + (name F64x2PromoteLowF32x4) => ("f64x2.promote_low_f32x4"); + (name Try) => ("try"); + (name Catch) => ("catch"); + (name Throw) => ("throw"); + (name Rethrow) => ("rethrow"); + (name Delegate) => ("delegate"); + (name CatchAll) => ("catch_all"); + (name I8x16RelaxedSwizzle) => ("i8x16.relaxed_swizzle"); + (name I32x4RelaxedTruncF32x4S) => ("i32x4.relaxed_trunc_f32x4_s"); + (name I32x4RelaxedTruncF32x4U) => ("i32x4.relaxed_trunc_f32x4_u"); + (name I32x4RelaxedTruncF64x2SZero) => ("i32x4.relaxed_trunc_f64x2_s_zero"); + (name I32x4RelaxedTruncF64x2UZero) => ("i32x4.relaxed_trunc_f64x2_u_zero"); + (name F32x4RelaxedMadd) => ("f32x4.relaxed_madd"); + (name F32x4RelaxedNmadd) => ("f32x4.relaxed_nmadd"); + (name F64x2RelaxedMadd) => ("f64x2.relaxed_madd"); + (name F64x2RelaxedNmadd) => ("f64x2.relaxed_nmadd"); + (name I8x16RelaxedLaneselect) => ("i8x16.relaxed_laneselect"); + (name I16x8RelaxedLaneselect) => ("i16x8.relaxed_laneselect"); + (name I32x4RelaxedLaneselect) => ("i32x4.relaxed_laneselect"); + (name I64x2RelaxedLaneselect) => ("i64x2.relaxed_laneselect"); + (name F32x4RelaxedMin) => ("f32x4.relaxed_min"); + (name F32x4RelaxedMax) => ("f32x4.relaxed_max"); + (name F64x2RelaxedMin) => ("f64x2.relaxed_min"); + (name F64x2RelaxedMax) => ("f64x2.relaxed_max"); + (name I16x8RelaxedQ15mulrS) => ("i16x8.relaxed_q15mulr_s"); + (name I16x8RelaxedDotI8x16I7x16S) => ("i16x8.relaxed_dot_i8x16_i7x16_s"); + (name I32x4RelaxedDotI8x16I7x16AddS) => ("i32x4.relaxed_dot_i8x16_i7x16_add_s"); + (name RefI31) => ("ref.i31"); + (name I31GetS) => ("i31.get_s"); + (name I31GetU) => ("i31.get_u"); +} - fn visit_f32_convert_i32_s(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.convert_i32_s") - } - fn visit_f32_convert_i32_u(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.convert_i32_u") - } - fn visit_f32_convert_i64_s(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.convert_i64_s") - } - fn visit_f32_convert_i64_u(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.convert_i64_u") - } - fn visit_f32_demote_f64(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.demote_f64") - } - fn visit_f64_convert_i32_s(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.convert_i32_s") - } - fn visit_f64_convert_i32_u(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.convert_i32_u") - } - fn visit_f64_convert_i64_s(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.convert_i64_s") - } - fn visit_f64_convert_i64_u(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.convert_i64_u") - } - fn visit_f64_promote_f32(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.promote_f32") - } - fn visit_i32_reinterpret_f32(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.reinterpret_f32") - } - fn visit_i64_reinterpret_f64(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.reinterpret_f64") - } - fn visit_f32_reinterpret_i32(&mut self, _pos: usize) -> Self::Output { - self.instr("f32.reinterpret_i32") - } - fn visit_f64_reinterpret_i64(&mut self, _pos: usize) -> Self::Output { - self.instr("f64.reinterpret_i64") - } - fn visit_i32_extend8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.extend8_s") - } - fn visit_i32_extend16_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.extend16_s") - } - fn visit_i64_extend8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.extend8_s") - } - fn visit_i64_extend16_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.extend16_s") - } - fn visit_i64_extend32_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.extend32_s") - } +impl<'a> VisitOperator<'a> for PrintOperator<'_, '_> { + type Output = Result; - fn visit_i32_trunc_sat_f32_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.trunc_sat_f32_s") - } - fn visit_i32_trunc_sat_f32_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.trunc_sat_f32_u") - } - fn visit_i32_trunc_sat_f64_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.trunc_sat_f64_s") - } - fn visit_i32_trunc_sat_f64_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32.trunc_sat_f64_u") - } - fn visit_i64_trunc_sat_f32_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.trunc_sat_f32_s") - } - fn visit_i64_trunc_sat_f32_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.trunc_sat_f32_u") - } - fn visit_i64_trunc_sat_f64_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.trunc_sat_f64_s") - } - fn visit_i64_trunc_sat_f64_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64.trunc_sat_f64_u") - } - - fn visit_memory_atomic_notify(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("memory.atomic.notify", &memarg, 4) - } - fn visit_memory_atomic_wait32(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("memory.atomic.wait32", &memarg, 4) - } - fn visit_memory_atomic_wait64(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("memory.atomic.wait64", &memarg, 8) - } - - fn visit_i32_atomic_load(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.load", &memarg, 4) - } - fn visit_i64_atomic_load(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.load", &memarg, 8) - } - fn visit_i32_atomic_load8_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.load8_u", &memarg, 1) - } - fn visit_i32_atomic_load16_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.load16_u", &memarg, 2) - } - fn visit_i64_atomic_load8_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.load8_u", &memarg, 1) - } - fn visit_i64_atomic_load16_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.load16_u", &memarg, 2) - } - fn visit_i64_atomic_load32_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.load32_u", &memarg, 4) - } - fn visit_i32_atomic_store(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.store", &memarg, 4) - } - fn visit_i32_atomic_store8(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.store8", &memarg, 1) - } - fn visit_i32_atomic_store16(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.store16", &memarg, 2) - } - fn visit_i64_atomic_store(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.store", &memarg, 8) - } - fn visit_i64_atomic_store8(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.store8", &memarg, 1) - } - fn visit_i64_atomic_store16(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.store16", &memarg, 2) - } - fn visit_i64_atomic_store32(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.store32", &memarg, 4) - } - - fn visit_i32_atomic_rmw_add(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw.add", &memarg, 4) - } - fn visit_i32_atomic_rmw8_add_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw8.add_u", &memarg, 1) - } - fn visit_i32_atomic_rmw16_add_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw16.add_u", &memarg, 2) - } - fn visit_i64_atomic_rmw_add(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw.add", &memarg, 8) - } - fn visit_i64_atomic_rmw8_add_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw8.add_u", &memarg, 1) - } - fn visit_i64_atomic_rmw16_add_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw16.add_u", &memarg, 2) - } - fn visit_i64_atomic_rmw32_add_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw32.add_u", &memarg, 4) - } - - fn visit_i32_atomic_rmw_sub(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw.sub", &memarg, 4) - } - fn visit_i32_atomic_rmw8_sub_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw8.sub_u", &memarg, 1) - } - fn visit_i32_atomic_rmw16_sub_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw16.sub_u", &memarg, 2) - } - fn visit_i64_atomic_rmw_sub(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw.sub", &memarg, 8) - } - fn visit_i64_atomic_rmw8_sub_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw8.sub_u", &memarg, 1) - } - fn visit_i64_atomic_rmw16_sub_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw16.sub_u", &memarg, 2) - } - fn visit_i64_atomic_rmw32_sub_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw32.sub_u", &memarg, 4) - } - - fn visit_i32_atomic_rmw_and(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw.and", &memarg, 4) - } - fn visit_i32_atomic_rmw8_and_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw8.and_u", &memarg, 1) - } - fn visit_i32_atomic_rmw16_and_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw16.and_u", &memarg, 2) - } - fn visit_i64_atomic_rmw_and(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw.and", &memarg, 8) - } - fn visit_i64_atomic_rmw8_and_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw8.and_u", &memarg, 1) - } - fn visit_i64_atomic_rmw16_and_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw16.and_u", &memarg, 2) - } - fn visit_i64_atomic_rmw32_and_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw32.and_u", &memarg, 4) - } - - fn visit_i32_atomic_rmw_or(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw.or", &memarg, 4) - } - fn visit_i32_atomic_rmw8_or_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw8.or_u", &memarg, 1) - } - fn visit_i32_atomic_rmw16_or_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw16.or_u", &memarg, 2) - } - fn visit_i64_atomic_rmw_or(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw.or", &memarg, 8) - } - fn visit_i64_atomic_rmw8_or_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw8.or_u", &memarg, 1) - } - fn visit_i64_atomic_rmw16_or_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw16.or_u", &memarg, 2) - } - fn visit_i64_atomic_rmw32_or_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw32.or_u", &memarg, 4) - } - - fn visit_i32_atomic_rmw_xor(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw.xor", &memarg, 4) - } - fn visit_i32_atomic_rmw8_xor_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw8.xor_u", &memarg, 1) - } - fn visit_i32_atomic_rmw16_xor_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw16.xor_u", &memarg, 2) - } - fn visit_i64_atomic_rmw_xor(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw.xor", &memarg, 8) - } - fn visit_i64_atomic_rmw8_xor_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw8.xor_u", &memarg, 1) - } - fn visit_i64_atomic_rmw16_xor_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw16.xor_u", &memarg, 2) - } - fn visit_i64_atomic_rmw32_xor_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw32.xor_u", &memarg, 4) - } - - fn visit_i32_atomic_rmw_xchg(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw.xchg", &memarg, 4) - } - fn visit_i32_atomic_rmw8_xchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw8.xchg_u", &memarg, 1) - } - fn visit_i32_atomic_rmw16_xchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw16.xchg_u", &memarg, 2) - } - fn visit_i64_atomic_rmw_xchg(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw.xchg", &memarg, 8) - } - fn visit_i64_atomic_rmw8_xchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw8.xchg_u", &memarg, 1) - } - fn visit_i64_atomic_rmw16_xchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw16.xchg_u", &memarg, 2) - } - fn visit_i64_atomic_rmw32_xchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw32.xchg_u", &memarg, 4) - } - - fn visit_i32_atomic_rmw_cmpxchg(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw.cmpxchg", &memarg, 4) - } - fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw8.cmpxchg_u", &memarg, 1) - } - fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i32.atomic.rmw16.cmpxchg_u", &memarg, 2) - } - fn visit_i64_atomic_rmw_cmpxchg(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw.cmpxchg", &memarg, 8) - } - fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw8.cmpxchg_u", &memarg, 1) - } - fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw16.cmpxchg_u", &memarg, 2) - } - fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("i64.atomic.rmw32.cmpxchg_u", &memarg, 4) - } - - fn visit_atomic_fence(&mut self, _pos: usize, _flags: u8) -> Self::Output { - self.instr("atomic.fence") - } - - fn visit_v128_load(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load", &memarg, 16) - } - fn visit_v128_store(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.store", &memarg, 16) - } - fn visit_v128_const(&mut self, _pos: usize, value: V128) -> Self::Output { - write!(self.result(), "v128.const i32x4")?; - for chunk in value.bytes().chunks(4) { - write!( - self.result(), - " 0x{:02x}{:02x}{:02x}{:02x}", - chunk[3], - chunk[2], - chunk[1], - chunk[0], - )?; - } - Ok(OpKind::Normal) - } - fn visit_i8x16_splat(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.splat") - } - fn visit_i16x8_splat(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.splat") - } - fn visit_i32x4_splat(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.splat") - } - fn visit_i64x2_splat(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.splat") - } - fn visit_f32x4_splat(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.splat") - } - fn visit_f64x2_splat(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.splat") - } - fn visit_i8x16_extract_lane_s(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i8x16.extract_lane_s {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i8x16_extract_lane_u(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i8x16.extract_lane_u {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i16x8_extract_lane_s(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i16x8.extract_lane_s {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i16x8_extract_lane_u(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i16x8.extract_lane_u {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i32x4_extract_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i32x4.extract_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i64x2_extract_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i64x2.extract_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i8x16_replace_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i8x16.replace_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i16x8_replace_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i16x8.replace_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i32x4_replace_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i32x4.replace_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_i64x2_replace_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "i64x2.replace_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_f32x4_extract_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "f32x4.extract_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_f32x4_replace_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "f32x4.replace_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_f64x2_extract_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "f64x2.extract_lane {lane}")?; - Ok(OpKind::Normal) - } - fn visit_f64x2_replace_lane(&mut self, _pos: usize, lane: u8) -> Self::Output { - write!(self.result(), "f64x2.replace_lane {lane}")?; - Ok(OpKind::Normal) - } - - fn visit_f32x4_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.eq") - } - fn visit_f32x4_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.ne") - } - fn visit_f32x4_lt(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.lt") - } - fn visit_f32x4_gt(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.gt") - } - fn visit_f32x4_le(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.le") - } - fn visit_f32x4_ge(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.ge") - } - - fn visit_f64x2_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.eq") - } - fn visit_f64x2_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.ne") - } - fn visit_f64x2_lt(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.lt") - } - fn visit_f64x2_gt(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.gt") - } - fn visit_f64x2_le(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.le") - } - fn visit_f64x2_ge(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.ge") - } - - fn visit_f32x4_add(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.add") - } - fn visit_f32x4_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.sub") - } - fn visit_f32x4_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.mul") - } - fn visit_f32x4_div(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.div") - } - fn visit_f32x4_min(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.min") - } - fn visit_f32x4_max(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.max") - } - fn visit_f32x4_pmin(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.pmin") - } - fn visit_f32x4_pmax(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.pmax") - } - - fn visit_f64x2_add(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.add") - } - fn visit_f64x2_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.sub") - } - fn visit_f64x2_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.mul") - } - fn visit_f64x2_div(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.div") - } - fn visit_f64x2_min(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.min") - } - fn visit_f64x2_max(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.max") - } - fn visit_f64x2_pmin(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.pmin") - } - fn visit_f64x2_pmax(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.pmax") - } - - fn visit_f32x4_relaxed_min(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.relaxed_min") - } - fn visit_f32x4_relaxed_max(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.relaxed_max") - } - fn visit_f64x2_relaxed_min(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.relaxed_min") - } - fn visit_f64x2_relaxed_max(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.relaxed_max") - } - - fn visit_i8x16_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.eq") - } - fn visit_i8x16_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.ne") - } - fn visit_i8x16_lt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.lt_s") - } - fn visit_i8x16_lt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.lt_u") - } - fn visit_i8x16_gt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.gt_s") - } - fn visit_i8x16_gt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.gt_u") - } - fn visit_i8x16_le_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.le_s") - } - fn visit_i8x16_le_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.le_u") - } - fn visit_i8x16_ge_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.ge_s") - } - fn visit_i8x16_ge_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.ge_u") - } - - fn visit_i16x8_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.eq") - } - fn visit_i16x8_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.ne") - } - fn visit_i16x8_lt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.lt_s") - } - fn visit_i16x8_lt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.lt_u") - } - fn visit_i16x8_gt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.gt_s") - } - fn visit_i16x8_gt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.gt_u") - } - fn visit_i16x8_le_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.le_s") - } - fn visit_i16x8_le_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.le_u") - } - fn visit_i16x8_ge_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.ge_s") - } - fn visit_i16x8_ge_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.ge_u") - } - - fn visit_i32x4_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.eq") - } - fn visit_i32x4_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.ne") - } - fn visit_i32x4_lt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.lt_s") - } - fn visit_i32x4_lt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.lt_u") - } - fn visit_i32x4_gt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.gt_s") - } - fn visit_i32x4_gt_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.gt_u") - } - fn visit_i32x4_le_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.le_s") - } - fn visit_i32x4_le_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.le_u") - } - fn visit_i32x4_ge_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.ge_s") - } - fn visit_i32x4_ge_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.ge_u") - } - - fn visit_i64x2_eq(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.eq") - } - fn visit_i64x2_ne(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.ne") - } - fn visit_i64x2_lt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.lt_s") - } - fn visit_i64x2_gt_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.gt_s") - } - fn visit_i64x2_le_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.le_s") - } - fn visit_i64x2_ge_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.ge_s") - } - - fn visit_v128_and(&mut self, _pos: usize) -> Self::Output { - self.instr("v128.and") - } - fn visit_v128_andnot(&mut self, _pos: usize) -> Self::Output { - self.instr("v128.andnot") - } - fn visit_v128_or(&mut self, _pos: usize) -> Self::Output { - self.instr("v128.or") - } - fn visit_v128_xor(&mut self, _pos: usize) -> Self::Output { - self.instr("v128.xor") - } - - fn visit_i8x16_add(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.add") - } - fn visit_i8x16_add_sat_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.add_sat_s") - } - fn visit_i8x16_add_sat_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.add_sat_u") - } - fn visit_i8x16_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.sub") - } - fn visit_i8x16_sub_sat_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.sub_sat_s") - } - fn visit_i8x16_sub_sat_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.sub_sat_u") - } - fn visit_i8x16_min_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.min_s") - } - fn visit_i8x16_min_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.min_u") - } - fn visit_i8x16_max_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.max_s") - } - fn visit_i8x16_max_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.max_u") - } - - fn visit_i16x8_add(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.add") - } - fn visit_i16x8_add_sat_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.add_sat_s") - } - fn visit_i16x8_add_sat_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.add_sat_u") - } - fn visit_i16x8_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.sub") - } - fn visit_i16x8_sub_sat_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.sub_sat_s") - } - fn visit_i16x8_sub_sat_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.sub_sat_u") - } - fn visit_i16x8_min_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.min_s") - } - fn visit_i16x8_min_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.min_u") - } - fn visit_i16x8_max_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.max_s") - } - fn visit_i16x8_max_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.max_u") - } - fn visit_i16x8_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.mul") - } - - fn visit_i32x4_add(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.add") - } - fn visit_i32x4_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.sub") - } - fn visit_i32x4_min_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.min_s") - } - fn visit_i32x4_min_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.min_u") - } - fn visit_i32x4_max_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.max_s") - } - fn visit_i32x4_max_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.max_u") - } - fn visit_i32x4_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.mul") - } - fn visit_i32x4_dot_i16x8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.dot_i16x8_s") - } - - fn visit_i64x2_add(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.add") - } - fn visit_i64x2_sub(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.sub") - } - fn visit_i64x2_mul(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.mul") - } - - fn visit_i8x16_avgr_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.avgr_u") - } - fn visit_i16x8_avgr_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.avgr_u") - } - fn visit_i8x16_narrow_i16x8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.narrow_i16x8_s") - } - fn visit_i8x16_narrow_i16x8_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.narrow_i16x8_u") - } - fn visit_i16x8_narrow_i32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.narrow_i32x4_s") - } - fn visit_i16x8_narrow_i32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.narrow_i32x4_u") - } - fn visit_i16x8_extmul_low_i8x16_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extmul_low_i8x16_s") - } - fn visit_i16x8_extmul_high_i8x16_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extmul_high_i8x16_s") - } - fn visit_i16x8_extmul_low_i8x16_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extmul_low_i8x16_u") - } - fn visit_i16x8_extmul_high_i8x16_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extmul_high_i8x16_u") - } - fn visit_i32x4_extmul_low_i16x8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extmul_low_i16x8_s") - } - fn visit_i32x4_extmul_high_i16x8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extmul_high_i16x8_s") - } - fn visit_i32x4_extmul_low_i16x8_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extmul_low_i16x8_u") - } - fn visit_i32x4_extmul_high_i16x8_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extmul_high_i16x8_u") - } - fn visit_i64x2_extmul_low_i32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.extmul_low_i32x4_s") - } - fn visit_i64x2_extmul_high_i32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.extmul_high_i32x4_s") - } - fn visit_i64x2_extmul_low_i32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.extmul_low_i32x4_u") - } - fn visit_i64x2_extmul_high_i32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.extmul_high_i32x4_u") - } - fn visit_i16x8_q15mulr_sat_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.q15mulr_sat_s") - } - - fn visit_f32x4_ceil(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.ceil") - } - fn visit_f32x4_floor(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.floor") - } - fn visit_f32x4_trunc(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.trunc") - } - fn visit_f32x4_nearest(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.nearest") - } - - fn visit_f64x2_ceil(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.ceil") - } - fn visit_f64x2_floor(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.floor") - } - fn visit_f64x2_trunc(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.trunc") - } - fn visit_f64x2_nearest(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.nearest") - } - - fn visit_f32x4_abs(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.abs") - } - fn visit_f32x4_neg(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.neg") - } - fn visit_f32x4_sqrt(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.sqrt") - } - fn visit_f64x2_abs(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.abs") - } - fn visit_f64x2_neg(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.neg") - } - fn visit_f64x2_sqrt(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.sqrt") - } - - fn visit_f32x4_demote_f64x2_zero(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.demote_f64x2_zero") - } - fn visit_f64x2_promote_low_f32x4(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.promote_low_f32x4") - } - fn visit_f64x2_convert_low_i32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.convert_low_i32x4_s") - } - fn visit_f64x2_convert_low_i32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.convert_low_i32x4_u") - } - fn visit_i32x4_trunc_sat_f32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.trunc_sat_f32x4_s") - } - fn visit_i32x4_trunc_sat_f32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.trunc_sat_f32x4_u") - } - fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.trunc_sat_f64x2_s_zero") - } - fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.trunc_sat_f64x2_u_zero") - } - fn visit_f32x4_convert_i32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.convert_i32x4_s") - } - fn visit_f32x4_convert_i32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.convert_i32x4_u") - } - fn visit_v128_not(&mut self, _pos: usize) -> Self::Output { - self.instr("v128.not") - } - fn visit_i8x16_abs(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.abs") - } - fn visit_i8x16_neg(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.neg") - } - fn visit_i8x16_popcnt(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.popcnt") - } - fn visit_i16x8_abs(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.abs") - } - fn visit_i16x8_neg(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.neg") - } - fn visit_i32x4_abs(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.abs") - } - fn visit_i32x4_neg(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.neg") - } - fn visit_i64x2_abs(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.abs") - } - fn visit_i64x2_neg(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.neg") - } - fn visit_i16x8_extend_low_i8x16_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extend_low_i8x16_s") - } - fn visit_i16x8_extend_high_i8x16_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extend_high_i8x16_s") - } - fn visit_i16x8_extend_low_i8x16_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extend_low_i8x16_u") - } - fn visit_i16x8_extend_high_i8x16_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extend_high_i8x16_u") - } - fn visit_i32x4_extend_low_i16x8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extend_low_i16x8_s") - } - fn visit_i32x4_extend_high_i16x8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extend_high_i16x8_s") - } - fn visit_i32x4_extend_low_i16x8_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extend_low_i16x8_u") - } - fn visit_i32x4_extend_high_i16x8_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extend_high_i16x8_u") - } - fn visit_i64x2_extend_low_i32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.extend_low_i32x4_s") - } - fn visit_i64x2_extend_high_i32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.extend_high_i32x4_s") - } - fn visit_i64x2_extend_low_i32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.extend_low_i32x4_u") - } - fn visit_i64x2_extend_high_i32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.extend_high_i32x4_u") - } - fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extadd_pairwise_i8x16_s") - } - fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.extadd_pairwise_i8x16_u") - } - fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extadd_pairwise_i16x8_s") - } - fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.extadd_pairwise_i16x8_u") - } - fn visit_i32x4_relaxed_trunc_sat_f32x4_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.relaxed_trunc_f32x4_s") - } - fn visit_i32x4_relaxed_trunc_sat_f32x4_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.relaxed_trunc_f32x4_u") - } - fn visit_i32x4_relaxed_trunc_sat_f64x2_s_zero(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.relaxed_trunc_f64x2_s_zero") - } - fn visit_i32x4_relaxed_trunc_sat_f64x2_u_zero(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.relaxed_trunc_f64x2_u_zero") - } - fn visit_v128_bitselect(&mut self, _pos: usize) -> Self::Output { - self.instr("v128.bitselect") - } - fn visit_f32x4_fma(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.fma") - } - fn visit_f32x4_fms(&mut self, _pos: usize) -> Self::Output { - self.instr("f32x4.fms") - } - fn visit_f64x2_fma(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.fma") - } - fn visit_f64x2_fms(&mut self, _pos: usize) -> Self::Output { - self.instr("f64x2.fms") - } - fn visit_i8x16_laneselect(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.laneselect") - } - fn visit_i16x8_laneselect(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.laneselect") - } - fn visit_i32x4_laneselect(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.laneselect") - } - fn visit_i64x2_laneselect(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.laneselect") - } - fn visit_v128_any_true(&mut self, _pos: usize) -> Self::Output { - self.instr("v128.any_true") - } - fn visit_i8x16_all_true(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.all_true") - } - fn visit_i8x16_bitmask(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.bitmask") - } - fn visit_i16x8_all_true(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.all_true") - } - fn visit_i16x8_bitmask(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.bitmask") - } - fn visit_i32x4_all_true(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.all_true") - } - fn visit_i32x4_bitmask(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.bitmask") - } - fn visit_i64x2_all_true(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.all_true") - } - fn visit_i64x2_bitmask(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.bitmask") - } - fn visit_i8x16_shl(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.shl") - } - fn visit_i8x16_shr_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.shr_s") - } - fn visit_i8x16_shr_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.shr_u") - } - fn visit_i16x8_shl(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.shl") - } - fn visit_i16x8_shr_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.shr_s") - } - fn visit_i16x8_shr_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i16x8.shr_u") - } - fn visit_i32x4_shl(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.shl") - } - fn visit_i32x4_shr_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.shr_s") - } - fn visit_i32x4_shr_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i32x4.shr_u") - } - fn visit_i64x2_shl(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.shl") - } - fn visit_i64x2_shr_s(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.shr_s") - } - fn visit_i64x2_shr_u(&mut self, _pos: usize) -> Self::Output { - self.instr("i64x2.shr_u") - } - - fn visit_i8x16_swizzle(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.swizzle") - } - fn visit_i8x16_relaxed_swizzle(&mut self, _pos: usize) -> Self::Output { - self.instr("i8x16.relaxed_swizzle") - } - fn visit_i8x16_shuffle(&mut self, _pos: usize, lanes: [u8; 16]) -> Self::Output { - self.push_str("i8x16.shuffle"); - for lane in lanes { - write!(self.result(), " {}", lane)?; - } - Ok(OpKind::Normal) - } - fn visit_v128_load8_splat(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load8_splat", &memarg, 1) - } - fn visit_v128_load16_splat(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load16_splat", &memarg, 2) - } - fn visit_v128_load32_splat(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load32_splat", &memarg, 4) - } - fn visit_v128_load32_zero(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load32_zero", &memarg, 4) - } - fn visit_v128_load64_splat(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load64_splat", &memarg, 8) - } - fn visit_v128_load64_zero(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load64_zero", &memarg, 8) - } - fn visit_v128_load8x8_s(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load8x8_s", &memarg, 8) - } - fn visit_v128_load8x8_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load8x8_u", &memarg, 8) - } - fn visit_v128_load16x4_s(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load16x4_s", &memarg, 8) - } - fn visit_v128_load16x4_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load16x4_u", &memarg, 8) - } - fn visit_v128_load32x2_s(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load32x2_s", &memarg, 8) - } - fn visit_v128_load32x2_u(&mut self, _pos: usize, memarg: MemArg) -> Self::Output { - self.mem_instr("v128.load32x2_u", &memarg, 8) - } - fn visit_v128_load8_lane(&mut self, _pos: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.mem_instr("v128.load8_lane", &memarg, 1)?; - write!(self.result(), " {lane}")?; - Ok(OpKind::Normal) - } - fn visit_v128_load16_lane(&mut self, _pos: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.mem_instr("v128.load16_lane", &memarg, 2)?; - write!(self.result(), " {lane}")?; - Ok(OpKind::Normal) - } - fn visit_v128_load32_lane(&mut self, _pos: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.mem_instr("v128.load32_lane", &memarg, 4)?; - write!(self.result(), " {lane}")?; - Ok(OpKind::Normal) - } - fn visit_v128_load64_lane(&mut self, _pos: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.mem_instr("v128.load64_lane", &memarg, 8)?; - write!(self.result(), " {lane}")?; - Ok(OpKind::Normal) - } - fn visit_v128_store8_lane(&mut self, _pos: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.mem_instr("v128.store8_lane", &memarg, 1)?; - write!(self.result(), " {lane}")?; - Ok(OpKind::Normal) - } - fn visit_v128_store16_lane(&mut self, _pos: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.mem_instr("v128.store16_lane", &memarg, 2)?; - write!(self.result(), " {lane}")?; - Ok(OpKind::Normal) - } - fn visit_v128_store32_lane(&mut self, _pos: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.mem_instr("v128.store32_lane", &memarg, 4)?; - write!(self.result(), " {lane}")?; - Ok(OpKind::Normal) - } - fn visit_v128_store64_lane(&mut self, _pos: usize, memarg: MemArg, lane: u8) -> Self::Output { - self.mem_instr("v128.store64_lane", &memarg, 8)?; - write!(self.result(), " {lane}")?; - Ok(OpKind::Normal) - } + wasmparser::for_each_operator!(define_visit); } diff --git a/crates/wasmprinter/tests/all.rs b/crates/wasmprinter/tests/all.rs index 5cb79c7a01..eac15a7f7e 100644 --- a/crates/wasmprinter/tests/all.rs +++ b/crates/wasmprinter/tests/all.rs @@ -169,3 +169,110 @@ fn dont_reserve_the_world() { err ); } + +#[test] +fn label_shadowing_block() { + const MODULE: &str = r#" + (module + (type (;0;) (func)) + (func (;0;) (type 0) + block $a ;; label = @1 + br 0 (;@1;) + end + block $a ;; label = @1 + br 0 (;@1;) + end + ) + ) + "#; + let bytes = wat::parse_str(MODULE).unwrap(); + let result = wasmprinter::print_bytes(&bytes).unwrap(); + assert_eq!( + result.replace(" ", "").trim(), + MODULE.replace(" ", "").trim() + ); +} + +#[test] +fn label_shadowing_block_confusion() { + // Make sure we don’t refer to a shadowed label via a name. + const MODULE: &str = r#" + (module + (type (;0;) (func)) + (func (;0;) (type 0) + block $a ;; label = @1 + block $a ;; label = @2 + br 1 (;@1;) + end + end + ) + ) + "#; + let bytes = wat::parse_str(MODULE).unwrap(); + let result = wasmprinter::print_bytes(&bytes).unwrap(); + assert_eq!( + result.replace(" ", "").trim(), + MODULE.replace(" ", "").trim() + ); +} + +#[test] +fn label_shadowing_locals() { + const MODULE: &str = r#" + (module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $l i32) (result i32) + (local $#local1 (@name "l") i32) (local $#local2 (@name "l") i32) + local.get $l + ) + ) + "#; + let bytes = wat::parse_str(MODULE).unwrap(); + let result = wasmprinter::print_bytes(&bytes).unwrap(); + assert_eq!( + result.replace(" ", "").trim(), + MODULE.replace(" ", "").trim() + ); +} + +#[test] +fn offsets_and_lines_smoke_test() { + const MODULE: &str = r#" + (;@0 ;) (module + (;@b ;) (type (;0;) (func (param i32) (result i32))) + (;@1f ;) (func (;0;) (type 0) (param i32) (result i32) + (;@20 ;) local.get 0 + ) + (;@17 ;) (export "f" (func 0)) + ) + "#; + let bytes = wat::parse_str(MODULE).unwrap(); + + let mut printer = wasmprinter::Printer::new(); + let actual: Vec<_> = printer.offsets_and_lines(&bytes).unwrap().collect(); + + #[rustfmt::skip] + let expected = vec![ + (Some(0), "(module\n"), + (Some(0xb), " (type (;0;) (func (param i32) (result i32)))\n"), + (Some(0x1f), " (func (;0;) (type 0) (param i32) (result i32)\n"), + (Some(0x20), " local.get 0\n"), + (None, " )\n"), + (Some(0x17), " (export \"f\" (func 0))\n"), + (None, ")"), + ]; + + assert_eq!(actual, expected); +} + +#[test] +fn no_panic_non_func_type() { + let bytes = wat::parse_str( + "(module + (type (struct)) + (func (type 0)) + )", + ) + .unwrap(); + wasmprinter::print_bytes(&bytes).unwrap(); +} diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 0c2bb35c26..e722b9faf9 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "wast" -version = "46.0.0" +version = "66.0.2" authors = ["Alex Crichton "] -edition = "2021" +edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" readme = "README.md" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wast" @@ -13,14 +13,14 @@ Customizable Rust parsers for the WebAssembly Text formats WAT and WAST """ [dependencies] -leb128 = "0.2" +leb128 = { workspace = true } unicode-width = "0.1.9" memchr = "2.4.1" -wasm-encoder = { version = "0.16.0", path = "../wasm-encoder" } +wasm-encoder = { workspace = true } [dev-dependencies] -anyhow = "1.0" -rayon = "1.0" +anyhow = { workspace = true } +rayon = { workspace = true } wasmparser = { path = "../wasmparser" } wat = { path = "../wat" } diff --git a/crates/wast/README.md b/crates/wast/README.md index 548a3630e8..e2724f61f8 100644 --- a/crates/wast/README.md +++ b/crates/wast/README.md @@ -17,11 +17,10 @@ ## Usage -Add this to your `Cargo.toml`: +Add `wast` to your `Cargo.toml` -```toml -[dependencies] -wast = "22.0" +```sh +$ cargo add wast ``` The intent of this crate is to provide utilities, combinators, and built-in @@ -30,7 +29,7 @@ types to parse anything that looks like a WebAssembly s-expression. * Need to parse a `*.wat` file? * Need to parse a `*.wast` file? * Need to run test suite assertions from the official wasm test suite? -* Want to write an extension do the WebAssembly text format? +* Want to write an extension to the WebAssembly text format? If you'd like to do any of the above this crate might be right for you! You may also want to check out the `wat` crate which provides a much more stable @@ -45,9 +44,8 @@ crate, however, to parse simply an s-expression wasm-related format (like only include a lexer, the parsing framework, and a few basic token-related parsers. -```toml -[dependencies] -wast = { version = "22.0", default-features = false } +```sh +$ cargo add wast --no-default-features ``` # License diff --git a/crates/wast/src/component/alias.rs b/crates/wast/src/component/alias.rs index d0ec9b23d7..dffcda1445 100644 --- a/crates/wast/src/component/alias.rs +++ b/crates/wast/src/component/alias.rs @@ -4,17 +4,22 @@ use crate::parser::{Parse, Parser, Result}; use crate::token::{Id, Index, NameAnnotation, Span}; /// A inline alias for component exported items. +/// +/// Handles both `core export` and `export` aliases #[derive(Debug)] -pub struct InlineExportAlias<'a> { +pub struct InlineExportAlias<'a, const CORE: bool> { /// The instance to alias the export from. pub instance: Index<'a>, /// The name of the export to alias. pub name: &'a str, } -impl<'a> Parse<'a> for InlineExportAlias<'a> { +impl<'a, const CORE: bool> Parse<'a> for InlineExportAlias<'a, CORE> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; + if CORE { + parser.parse::()?; + } parser.parse::()?; let instance = parser.parse()?; let name = parser.parse()?; @@ -38,7 +43,7 @@ pub struct Alias<'a> { impl<'a> Alias<'a> { /// Parses only an outer type alias. - pub fn parse_outer_type_alias(parser: Parser<'a>, core_prefix_assumed: bool) -> Result { + pub fn parse_outer_core_type_alias(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; parser.parse::()?; let outer = parser.parse()?; @@ -47,14 +52,11 @@ impl<'a> Alias<'a> { let (kind, id, name) = parser.parens(|parser| { let mut kind: ComponentOuterAliasKind = parser.parse()?; match kind { - ComponentOuterAliasKind::CoreType | ComponentOuterAliasKind::Type => { - if core_prefix_assumed { - // Error if the core prefix was present (should not be present in module type aliases). - if kind == ComponentOuterAliasKind::CoreType { - return Err(parser.error("expected type for outer alias")); - } - kind = ComponentOuterAliasKind::CoreType; - } + ComponentOuterAliasKind::CoreType => { + return Err(parser.error("expected type for outer alias")) + } + ComponentOuterAliasKind::Type => { + kind = ComponentOuterAliasKind::CoreType; } _ => return Err(parser.error("expected core type or type for outer alias")), } @@ -77,7 +79,7 @@ impl<'a> Parse<'a> for Alias<'a> { let mut l = parser.lookahead1(); - let (target, id, name) = if l.peek::() { + let (target, id, name) = if l.peek::()? { parser.parse::()?; let outer = parser.parse()?; let index = parser.parse()?; @@ -85,7 +87,7 @@ impl<'a> Parse<'a> for Alias<'a> { parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?; (AliasTarget::Outer { outer, index, kind }, id, name) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; let instance = parser.parse()?; let export_name = parser.parse()?; @@ -101,7 +103,7 @@ impl<'a> Parse<'a> for Alias<'a> { id, name, ) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; parser.parse::()?; let instance = parser.parse()?; @@ -153,28 +155,28 @@ pub enum ComponentExportAliasKind { impl<'a> Parse<'a> for ComponentExportAliasKind { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(Self::CoreModule) } else { Err(l.error()) } - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Func) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Value) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Type) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Component) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Instance) } else { @@ -199,22 +201,22 @@ pub enum ComponentOuterAliasKind { impl<'a> Parse<'a> for ComponentOuterAliasKind { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(Self::CoreModule) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::CoreType) } else { Err(l.error()) } - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Type) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Component) } else { diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index bba6b30d2a..7edb4c2b16 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -1,12 +1,12 @@ use crate::component::*; use crate::core; -use crate::token::{Id, Index, NameAnnotation}; +use crate::token::{Id, Index, NameAnnotation, Span}; use wasm_encoder::{ CanonicalFunctionSection, ComponentAliasSection, ComponentDefinedTypeEncoder, - ComponentExportSection, ComponentImportSection, ComponentInstanceSection, ComponentSection, - ComponentSectionId, ComponentStartSection, ComponentTypeEncoder, ComponentTypeSection, - CoreTypeEncoder, CoreTypeSection, InstanceSection, NestedComponentSection, RawSection, - SectionId, + ComponentExportSection, ComponentImportSection, ComponentInstanceSection, ComponentNameSection, + ComponentSection, ComponentSectionId, ComponentStartSection, ComponentTypeEncoder, + ComponentTypeSection, CoreTypeEncoder, CoreTypeSection, InstanceSection, NameMap, + NestedComponentSection, RawSection, SectionId, }; pub fn encode(component: &Component<'_>) -> Vec { @@ -20,8 +20,8 @@ pub fn encode(component: &Component<'_>) -> Vec { fn encode_fields( // TODO: use the id and name for a future names section - _component_id: &Option>, - _component_name: &Option>, + component_id: &Option>, + component_name: &Option>, fields: &[ComponentField<'_>], ) -> wasm_encoder::Component { let mut e = Encoder::default(); @@ -43,13 +43,12 @@ fn encode_fields( ComponentField::Import(i) => e.encode_import(i), ComponentField::Export(ex) => e.encode_export(ex), ComponentField::Custom(c) => e.encode_custom(c), + ComponentField::Producers(c) => e.encode_producers(c), } } - // FIXME(WebAssembly/component-model#14): once a name section is defined it - // should be encoded here. - e.flush(None); + e.encode_names(component_id, component_name); e.component } @@ -78,11 +77,7 @@ fn encode_type(encoder: ComponentTypeEncoder, ty: &TypeDef) { } TypeDef::Func(f) => { let mut encoder = encoder.function(); - if f.params.len() == 1 && f.params[0].name.is_none() { - encoder.param(&f.params[0].ty); - } else { - encoder.params(f.params.iter().map(|p| (p.name.unwrap_or(""), &p.ty))); - } + encoder.params(f.params.iter().map(|p| (p.name, &p.ty))); if f.results.len() == 1 && f.results[0].name.is_none() { encoder.result(&f.results[0].ty); @@ -96,6 +91,10 @@ fn encode_type(encoder: ComponentTypeEncoder, ty: &TypeDef) { TypeDef::Instance(i) => { encoder.instance(&i.into()); } + TypeDef::Resource(i) => { + let dtor = i.dtor.as_ref().map(|i| i.idx.into()); + encoder.resource(i.rep.into(), dtor); + } } } @@ -126,7 +125,6 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin ComponentDefinedType::Enum(e) => { encoder.enum_type(e.names.iter().copied()); } - ComponentDefinedType::Union(u) => encoder.union(u.types.iter()), ComponentDefinedType::Option(o) => { encoder.option(o.element.as_ref()); } @@ -136,11 +134,13 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin e.err.as_deref().map(Into::into), ); } + ComponentDefinedType::Own(i) => encoder.own((*i).into()), + ComponentDefinedType::Borrow(i) => encoder.borrow((*i).into()), } } #[derive(Default)] -struct Encoder { +struct Encoder<'a> { component: wasm_encoder::Component, current_section_id: Option, @@ -157,19 +157,47 @@ struct Encoder { funcs: CanonicalFunctionSection, imports: ComponentImportSection, exports: ComponentExportSection, + + core_func_names: Vec>, + core_table_names: Vec>, + core_memory_names: Vec>, + core_global_names: Vec>, + core_type_names: Vec>, + core_module_names: Vec>, + core_instance_names: Vec>, + func_names: Vec>, + value_names: Vec>, + type_names: Vec>, + component_names: Vec>, + instance_names: Vec>, } -impl Encoder { +impl<'a> Encoder<'a> { fn encode_custom(&mut self, custom: &Custom) { // Flush any in-progress section before encoding the customs section self.flush(None); self.component.section(custom); } - fn encode_core_module(&mut self, module: &CoreModule) { + fn encode_producers(&mut self, custom: &core::Producers) { + use crate::encode::Encode; + + let mut data = Vec::new(); + custom.encode(&mut data); + self.encode_custom(&Custom { + name: "producers", + span: Span::from_offset(0), + data: vec![&data], + }) + } + + fn encode_core_module(&mut self, module: &CoreModule<'a>) { // Flush any in-progress section before encoding the module self.flush(None); + self.core_module_names + .push(get_name(&module.id, &module.name)); + match &module.kind { CoreModuleKind::Import { .. } => unreachable!("should be expanded already"), CoreModuleKind::Inline { fields } => { @@ -183,7 +211,9 @@ impl Encoder { } } - fn encode_core_instance(&mut self, instance: &CoreInstance) { + fn encode_core_instance(&mut self, instance: &CoreInstance<'a>) { + self.core_instance_names + .push(get_name(&instance.id, &instance.name)); match &instance.kind { CoreInstanceKind::Instantiate { module, args } => { self.core_instances.instantiate( @@ -202,12 +232,15 @@ impl Encoder { self.flush(Some(self.core_instances.id())); } - fn encode_core_type(&mut self, ty: &CoreType) { + fn encode_core_type(&mut self, ty: &CoreType<'a>) { + self.core_type_names.push(get_name(&ty.id, &ty.name)); encode_core_type(self.core_types.ty(), &ty.def); self.flush(Some(self.core_types.id())); } - fn encode_component(&mut self, component: &NestedComponent) { + fn encode_component(&mut self, component: &NestedComponent<'a>) { + self.component_names + .push(get_name(&component.id, &component.name)); // Flush any in-progress section before encoding the component self.flush(None); @@ -224,7 +257,9 @@ impl Encoder { } } - fn encode_instance(&mut self, instance: &Instance) { + fn encode_instance(&mut self, instance: &Instance<'a>) { + self.instance_names + .push(get_name(&instance.id, &instance.name)); match &instance.kind { InstanceKind::Import { .. } => unreachable!("should be expanded already"), InstanceKind::Instantiate { component, args } => { @@ -239,7 +274,7 @@ impl Encoder { InstanceKind::BundleOfExports(exports) => { self.instances.export_items(exports.iter().map(|e| { let (kind, index) = (&e.kind).into(); - (e.name, kind, index) + (e.name.into(), kind, index) })); } } @@ -247,27 +282,18 @@ impl Encoder { self.flush(Some(self.instances.id())); } - fn encode_alias(&mut self, alias: &Alias) { + fn encode_alias(&mut self, alias: &Alias<'a>) { + let name = get_name(&alias.id, &alias.name); + self.aliases.alias((&alias.target).into()); match &alias.target { - AliasTarget::Export { - instance, - name, - kind, - } => { - self.aliases - .instance_export((*instance).into(), (*kind).into(), name); + AliasTarget::Export { kind, .. } => { + self.names_for_component_export_alias(*kind).push(name); } - AliasTarget::CoreExport { - instance, - name, - kind, - } => { - self.aliases - .core_instance_export((*instance).into(), (*kind).into(), name); + AliasTarget::CoreExport { kind, .. } => { + self.names_for_core_export_alias(*kind).push(name); } - AliasTarget::Outer { outer, index, kind } => { - self.aliases - .outer((*outer).into(), (*kind).into(), (*index).into()); + AliasTarget::Outer { kind, .. } => { + self.names_for_component_outer_alias(*kind).push(name); } } @@ -285,14 +311,17 @@ impl Encoder { }); } - fn encode_type(&mut self, ty: &Type) { + fn encode_type(&mut self, ty: &Type<'a>) { + self.type_names.push(get_name(&ty.id, &ty.name)); encode_type(self.types.ty(), &ty.def); self.flush(Some(self.types.id())); } - fn encode_canonical_func(&mut self, func: &CanonicalFunc) { + fn encode_canonical_func(&mut self, func: &CanonicalFunc<'a>) { + let name = get_name(&func.id, &func.name); match &func.kind { CanonicalFuncKind::Lift { ty, info } => { + self.func_names.push(name); self.funcs.lift( info.func.idx.into(), ty.into(), @@ -300,22 +329,54 @@ impl Encoder { ); } CanonicalFuncKind::Lower(info) => { + self.core_func_names.push(name); self.funcs .lower(info.func.idx.into(), info.opts.iter().map(Into::into)); } + CanonicalFuncKind::ResourceNew(info) => { + self.core_func_names.push(name); + self.funcs.resource_new(info.ty.into()); + } + CanonicalFuncKind::ResourceDrop(info) => { + self.core_func_names.push(name); + self.funcs.resource_drop(info.ty.into()); + } + CanonicalFuncKind::ResourceRep(info) => { + self.core_func_names.push(name); + self.funcs.resource_rep(info.ty.into()); + } } self.flush(Some(self.funcs.id())); } - fn encode_import(&mut self, import: &ComponentImport) { - self.imports.import(import.name, (&import.item.kind).into()); + fn encode_import(&mut self, import: &ComponentImport<'a>) { + let name = get_name(&import.item.id, &import.item.name); + self.names_for_item_kind(&import.item.kind).push(name); + self.imports.import( + wasm_encoder::ComponentExternName::from(import.name), + (&import.item.kind).into(), + ); self.flush(Some(self.imports.id())); } - fn encode_export(&mut self, export: &ComponentExport) { + fn encode_export(&mut self, export: &ComponentExport<'a>) { + let name = get_name(&export.id, &export.debug_name); let (kind, index) = (&export.kind).into(); - self.exports.export(export.name, kind, index); + self.exports.export( + wasm_encoder::ComponentExternName::from(export.name), + kind, + index, + export.ty.as_ref().map(|ty| (&ty.0.kind).into()), + ); + match &export.kind { + ComponentExportKind::CoreModule(_) => self.core_module_names.push(name), + ComponentExportKind::Func(_) => self.func_names.push(name), + ComponentExportKind::Instance(_) => self.instance_names.push(name), + ComponentExportKind::Value(_) => self.value_names.push(name), + ComponentExportKind::Component(_) => self.component_names.push(name), + ComponentExportKind::Type(_) => self.type_names.push(name), + } self.flush(Some(self.exports.id())); } @@ -376,6 +437,108 @@ impl Encoder { self.current_section_id = section_id } + + fn encode_names( + &mut self, + component_id: &Option>, + component_name: &Option>, + ) { + let mut names = ComponentNameSection::new(); + if let Some(name) = get_name(component_id, component_name) { + names.component(name); + } + + let mut funcs = |list: &[Option<&str>], append: fn(&mut ComponentNameSection, &NameMap)| { + let mut map = NameMap::new(); + for (i, entry) in list.iter().enumerate() { + if let Some(name) = entry { + map.append(i as u32, name); + } + } + if !map.is_empty() { + append(&mut names, &map); + } + }; + + funcs(&self.core_func_names, ComponentNameSection::core_funcs); + funcs(&self.core_table_names, ComponentNameSection::core_tables); + funcs(&self.core_memory_names, ComponentNameSection::core_memories); + funcs(&self.core_global_names, ComponentNameSection::core_globals); + funcs(&self.core_type_names, ComponentNameSection::core_types); + funcs(&self.core_module_names, ComponentNameSection::core_modules); + funcs( + &self.core_instance_names, + ComponentNameSection::core_instances, + ); + funcs(&self.func_names, ComponentNameSection::funcs); + funcs(&self.value_names, ComponentNameSection::values); + funcs(&self.type_names, ComponentNameSection::types); + funcs(&self.component_names, ComponentNameSection::components); + funcs(&self.instance_names, ComponentNameSection::instances); + + if !names.is_empty() { + self.component.section(&names); + } + } + + fn names_for_component_export_alias( + &mut self, + kind: ComponentExportAliasKind, + ) -> &mut Vec> { + match kind { + ComponentExportAliasKind::Func => &mut self.func_names, + ComponentExportAliasKind::CoreModule => &mut self.core_module_names, + ComponentExportAliasKind::Value => &mut self.value_names, + ComponentExportAliasKind::Type => &mut self.type_names, + ComponentExportAliasKind::Component => &mut self.component_names, + ComponentExportAliasKind::Instance => &mut self.instance_names, + } + } + + fn names_for_component_outer_alias( + &mut self, + kind: ComponentOuterAliasKind, + ) -> &mut Vec> { + match kind { + ComponentOuterAliasKind::CoreModule => &mut self.core_module_names, + ComponentOuterAliasKind::CoreType => &mut self.core_type_names, + ComponentOuterAliasKind::Component => &mut self.component_names, + ComponentOuterAliasKind::Type => &mut self.type_names, + } + } + + fn names_for_core_export_alias(&mut self, kind: core::ExportKind) -> &mut Vec> { + match kind { + core::ExportKind::Func => &mut self.core_func_names, + core::ExportKind::Global => &mut self.core_global_names, + core::ExportKind::Table => &mut self.core_table_names, + core::ExportKind::Memory => &mut self.core_memory_names, + core::ExportKind::Tag => unimplemented!(), + } + } + + fn names_for_item_kind(&mut self, kind: &ItemSigKind) -> &mut Vec> { + match kind { + ItemSigKind::CoreModule(_) => &mut self.core_module_names, + ItemSigKind::Func(_) => &mut self.func_names, + ItemSigKind::Component(_) => &mut self.component_names, + ItemSigKind::Instance(_) => &mut self.instance_names, + ItemSigKind::Value(_) => &mut self.value_names, + ItemSigKind::Type(_) => &mut self.type_names, + } + } +} + +fn get_name<'a>(id: &Option>, name: &Option>) -> Option<&'a str> { + name.as_ref().map(|n| n.name).or_else(|| { + id.and_then(|id| { + if id.is_gensym() { + None + } else { + Some(id.name()) + } + }) + }) } // This implementation is much like `wasm_encoder::CustomSection`, except @@ -417,17 +580,38 @@ impl From> for wasm_encoder::ValType { core::ValType::F32 => Self::F32, core::ValType::F64 => Self::F64, core::ValType::V128 => Self::V128, - core::ValType::Ref(r) => r.into(), + core::ValType::Ref(r) => Self::Ref(r.into()), } } } -impl From> for wasm_encoder::ValType { +impl From> for wasm_encoder::RefType { fn from(r: core::RefType<'_>) -> Self { - match r.heap { - core::HeapType::Func => Self::FuncRef, - core::HeapType::Extern => Self::ExternRef, - _ => { + wasm_encoder::RefType { + nullable: r.nullable, + heap_type: r.heap.into(), + } + } +} + +impl From> for wasm_encoder::HeapType { + fn from(r: core::HeapType<'_>) -> Self { + match r { + core::HeapType::Func => Self::Func, + core::HeapType::Extern => Self::Extern, + core::HeapType::Exn => { + todo!("encoding of exceptions proposal types not yet implemented") + } + core::HeapType::Index(Index::Num(i, _)) => Self::Indexed(i), + core::HeapType::Index(_) => panic!("unresolved index"), + core::HeapType::Any + | core::HeapType::Eq + | core::HeapType::Struct + | core::HeapType::Array + | core::HeapType::NoFunc + | core::HeapType::NoExtern + | core::HeapType::None + | core::HeapType::I31 => { todo!("encoding of GC proposal types not yet implemented") } } @@ -624,7 +808,10 @@ impl From<&ItemSigKind<'_>> for wasm_encoder::ComponentTypeRef { ItemSigKind::Value(v) => Self::Value((&v.0).into()), ItemSigKind::Func(f) => Self::Func(f.into()), ItemSigKind::Type(TypeBounds::Eq(t)) => { - Self::Type(wasm_encoder::TypeBounds::Eq, (*t).into()) + Self::Type(wasm_encoder::TypeBounds::Eq((*t).into())) + } + ItemSigKind::Type(TypeBounds::SubResource) => { + Self::Type(wasm_encoder::TypeBounds::SubResource) } } } @@ -642,28 +829,20 @@ impl From<&ComponentType<'_>> for wasm_encoder::ComponentType { ComponentTypeDecl::Type(t) => { encode_type(encoded.ty(), &t.def); } - ComponentTypeDecl::Alias(a) => match &a.target { - AliasTarget::Outer { - outer, - index, - kind: ComponentOuterAliasKind::CoreType, - } => { - encoded.alias_outer_core_type(u32::from(*outer), u32::from(*index)); - } - AliasTarget::Outer { - outer, - index, - kind: ComponentOuterAliasKind::Type, - } => { - encoded.alias_outer_type(u32::from(*outer), u32::from(*index)); - } - _ => unreachable!("only outer type aliases are supported"), - }, + ComponentTypeDecl::Alias(a) => { + encoded.alias((&a.target).into()); + } ComponentTypeDecl::Import(i) => { - encoded.import(i.name, (&i.item.kind).into()); + encoded.import( + wasm_encoder::ComponentExternName::from(i.name), + (&i.item.kind).into(), + ); } ComponentTypeDecl::Export(e) => { - encoded.export(e.name, (&e.item.kind).into()); + encoded.export( + wasm_encoder::ComponentExternName::from(e.name), + (&e.item.kind).into(), + ); } } } @@ -684,25 +863,14 @@ impl From<&InstanceType<'_>> for wasm_encoder::InstanceType { InstanceTypeDecl::Type(t) => { encode_type(encoded.ty(), &t.def); } - InstanceTypeDecl::Alias(a) => match &a.target { - AliasTarget::Outer { - outer, - index, - kind: ComponentOuterAliasKind::CoreType, - } => { - encoded.alias_outer_core_type(u32::from(*outer), u32::from(*index)); - } - AliasTarget::Outer { - outer, - index, - kind: ComponentOuterAliasKind::Type, - } => { - encoded.alias_outer_type(u32::from(*outer), u32::from(*index)); - } - _ => unreachable!("only outer type aliases are supported"), - }, + InstanceTypeDecl::Alias(a) => { + encoded.alias((&a.target).into()); + } InstanceTypeDecl::Export(e) => { - encoded.export(e.name, (&e.item.kind).into()); + encoded.export( + wasm_encoder::ComponentExternName::from(e.name), + (&e.item.kind).into(), + ); } } } @@ -815,3 +983,42 @@ impl From<&CanonOpt<'_>> for wasm_encoder::CanonicalOption { } } } + +impl<'a> From<&AliasTarget<'a>> for wasm_encoder::Alias<'a> { + fn from(target: &AliasTarget<'a>) -> Self { + match target { + AliasTarget::Export { + instance, + name, + kind, + } => wasm_encoder::Alias::InstanceExport { + instance: (*instance).into(), + kind: (*kind).into(), + name, + }, + AliasTarget::CoreExport { + instance, + name, + kind, + } => wasm_encoder::Alias::CoreInstanceExport { + instance: (*instance).into(), + kind: (*kind).into(), + name, + }, + AliasTarget::Outer { outer, index, kind } => wasm_encoder::Alias::Outer { + count: (*outer).into(), + kind: (*kind).into(), + index: (*index).into(), + }, + } + } +} + +impl<'a> From> for wasm_encoder::ComponentExternName<'a> { + fn from(name: ComponentExternName<'a>) -> Self { + match name { + ComponentExternName::Kebab(name) => Self::Kebab(name), + ComponentExternName::Interface(name) => Self::Interface(name), + } + } +} diff --git a/crates/wast/src/component/component.rs b/crates/wast/src/component/component.rs index ebb5a3f53f..f954935d87 100644 --- a/crates/wast/src/component/component.rs +++ b/crates/wast/src/component/component.rs @@ -1,6 +1,6 @@ use crate::annotation; use crate::component::*; -use crate::core; +use crate::core::Producers; use crate::kw; use crate::parser::{Parse, Parser, Result}; use crate::token::Index; @@ -109,12 +109,14 @@ impl<'a> Component<'a> { impl<'a> Parse<'a> for Component<'a> { fn parse(parser: Parser<'a>) -> Result { let _r = parser.register_annotation("custom"); + let _r = parser.register_annotation("producers"); + let _r = parser.register_annotation("name"); let span = parser.parse::()?.0; let id = parser.parse()?; let name = parser.parse()?; - let kind = if parser.peek::() { + let kind = if parser.peek::()? { parser.parse::()?; let mut data = Vec::new(); while !parser.is_empty() { @@ -151,6 +153,7 @@ pub enum ComponentField<'a> { Import(ComponentImport<'a>), Export(ComponentExport<'a>), Custom(Custom<'a>), + Producers(Producers<'a>), } impl<'a> ComponentField<'a> { @@ -165,47 +168,50 @@ impl<'a> ComponentField<'a> { impl<'a> Parse<'a> for ComponentField<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { - if parser.peek2::() { + if parser.peek::()? { + if parser.peek2::()? { return Ok(Self::CoreModule(parser.parse()?)); } - if parser.peek2::() { + if parser.peek2::()? { return Ok(Self::CoreInstance(parser.parse()?)); } - if parser.peek2::() { + if parser.peek2::()? { return Ok(Self::CoreType(parser.parse()?)); } - if parser.peek2::() { + if parser.peek2::()? { return Ok(Self::CoreFunc(parser.parse()?)); } } else { - if parser.peek::() { + if parser.peek::()? { return Ok(Self::Component(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(Self::Instance(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(Self::Alias(parser.parse()?)); } - if parser.peek::() { - return Ok(Self::Type(parser.parse()?)); + if parser.peek::()? { + return Ok(Self::Type(Type::parse_maybe_with_inline_exports(parser)?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(Self::Import(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(Self::Func(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(Self::Export(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(Self::Start(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(Self::Custom(parser.parse()?)); } + if parser.peek::()? { + return Ok(Self::Producers(parser.parse()?)); + } } Err(parser.error("expected valid component field")) } @@ -227,12 +233,12 @@ impl<'a> Parse<'a> for Start<'a> { parser.parse::()?; let func = parser.parse()?; let mut args = Vec::new(); - while !parser.is_empty() && !parser.peek2::() { + while !parser.is_empty() && !parser.peek2::()? { args.push(parser.parens(|parser| parser.parse())?); } let mut results = Vec::new(); - while !parser.is_empty() && parser.peek2::() { + while !parser.is_empty() && parser.peek2::()? { results.push(parser.parens(|parser| { parser.parse::()?; parser.parens(|parser| { @@ -261,7 +267,7 @@ pub struct NestedComponent<'a> { pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: core::InlineExport<'a>, + pub exports: InlineExport<'a>, /// What kind of component this was parsed as. pub kind: NestedComponentKind<'a>, } diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs index 506a850581..10523eacc8 100644 --- a/crates/wast/src/component/expand.rs +++ b/crates/wast/src/component/expand.rs @@ -11,7 +11,7 @@ use std::mem; /// /// This expansion is intended to desugar the AST from various parsed constructs /// to bits and bobs amenable for name resolution as well as binary encoding. -/// For example `(import "" (func))` is split into a type definition followed by +/// For example `(import "i" (func))` is split into a type definition followed by /// the import referencing that type definition. /// /// Most forms of AST expansion happen in this file and afterwards the AST will @@ -121,10 +121,16 @@ impl<'a> Expander<'a> { self.expand_item_sig(&mut i.item); None } + ComponentField::Export(e) => { + if let Some(sig) = &mut e.ty { + self.expand_item_sig(&mut sig.0); + } + None + } ComponentField::Start(_) | ComponentField::Alias(_) - | ComponentField::Export(_) - | ComponentField::Custom(_) => None, + | ComponentField::Custom(_) + | ComponentField::Producers(_) => None, }; if let Some(expanded) = expanded { @@ -138,8 +144,11 @@ impl<'a> Expander<'a> { self.component_fields_to_append .push(ComponentField::Export(ComponentExport { span: module.span, + id: None, + debug_name: None, name, kind: ComponentExportKind::module(module.span, id), + ty: None, })); } match &mut module.kind { @@ -181,8 +190,11 @@ impl<'a> Expander<'a> { self.component_fields_to_append .push(ComponentField::Export(ComponentExport { span: component.span, + id: None, + debug_name: None, name, kind: ComponentExportKind::component(component.span, id), + ty: None, })); } match &mut component.kind { @@ -212,8 +224,11 @@ impl<'a> Expander<'a> { self.component_fields_to_append .push(ComponentField::Export(ComponentExport { span: instance.span, + id: None, + debug_name: None, name, kind: ComponentExportKind::instance(instance.span, id), + ty: None, })); } match &mut instance.kind { @@ -245,7 +260,10 @@ impl<'a> Expander<'a> { CanonicalFuncKind::Lift { ty, .. } => { self.expand_component_type_use(ty); } - CanonicalFuncKind::Lower(_) => {} + CanonicalFuncKind::Lower(_) + | CanonicalFuncKind::ResourceNew(_) + | CanonicalFuncKind::ResourceRep(_) + | CanonicalFuncKind::ResourceDrop(_) => {} } } @@ -267,6 +285,26 @@ impl<'a> Expander<'a> { name: func.name, kind: CanonicalFuncKind::Lower(mem::take(info)), })), + CoreFuncKind::ResourceNew(info) => Some(ComponentField::CanonicalFunc(CanonicalFunc { + span: func.span, + id: func.id, + name: func.name, + kind: CanonicalFuncKind::ResourceNew(mem::take(info)), + })), + CoreFuncKind::ResourceDrop(info) => { + Some(ComponentField::CanonicalFunc(CanonicalFunc { + span: func.span, + id: func.id, + name: func.name, + kind: CanonicalFuncKind::ResourceDrop(mem::take(info)), + })) + } + CoreFuncKind::ResourceRep(info) => Some(ComponentField::CanonicalFunc(CanonicalFunc { + span: func.span, + id: func.id, + name: func.name, + kind: CanonicalFuncKind::ResourceRep(mem::take(info)), + })), } } @@ -276,8 +314,11 @@ impl<'a> Expander<'a> { self.component_fields_to_append .push(ComponentField::Export(ComponentExport { span: func.span, + id: None, + debug_name: None, name, kind: ComponentExportKind::func(func.span, id), + ty: None, })); } match &mut func.kind { @@ -339,6 +380,7 @@ impl<'a> Expander<'a> { TypeDef::Func(f) => self.expand_func_ty(f), TypeDef::Component(c) => self.expand_component_ty(c), TypeDef::Instance(i) => self.expand_instance_ty(i), + TypeDef::Resource(_) => {} } let id = gensym::fill(field.span, &mut field.id); @@ -348,6 +390,18 @@ impl<'a> Expander<'a> { TypeDef::Func(t) => t.key().insert(self, index), TypeDef::Component(t) => t.key().insert(self, index), TypeDef::Instance(t) => t.key().insert(self, index), + TypeDef::Resource(_) => {} + } + for name in field.exports.names.drain(..) { + self.component_fields_to_append + .push(ComponentField::Export(ComponentExport { + span: field.span, + id: None, + debug_name: None, + name, + kind: ComponentExportKind::ty(field.span, id), + ty: None, + })); } } @@ -424,6 +478,7 @@ impl<'a> Expander<'a> { name: None, def: key.to_def(item.span), parent: None, + final_type: None, })); let idx = Index::Id(id); t.index = Some(idx); @@ -500,11 +555,6 @@ impl<'a> Expander<'a> { self.expand_component_val_ty(field); } } - ComponentDefinedType::Union(u) => { - for ty in u.types.iter_mut() { - self.expand_component_val_ty(ty); - } - } ComponentDefinedType::Option(t) => { self.expand_component_val_ty(&mut t.element); } @@ -517,6 +567,7 @@ impl<'a> Expander<'a> { self.expand_component_val_ty(ty); } } + ComponentDefinedType::Own(_) | ComponentDefinedType::Borrow(_) => {} } } diff --git a/crates/wast/src/component/export.rs b/crates/wast/src/component/export.rs index a3b2bd7c0e..d9e2ae4b4c 100644 --- a/crates/wast/src/component/export.rs +++ b/crates/wast/src/component/export.rs @@ -1,25 +1,45 @@ -use super::ItemRef; +use super::{ComponentExternName, ItemRef, ItemSigNoName}; use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; -use crate::token::{Id, Index, Span}; +use crate::token::{Id, Index, NameAnnotation, Span}; /// An entry in a WebAssembly component's export section. #[derive(Debug)] pub struct ComponentExport<'a> { /// Where this export was defined. pub span: Span, + /// Optional identifier bound to this export. + pub id: Option>, + /// An optional name for this instance stored in the custom `name` section. + pub debug_name: Option>, /// The name of this export from the component. - pub name: &'a str, + pub name: ComponentExternName<'a>, /// The kind of export. pub kind: ComponentExportKind<'a>, + /// The kind of export. + pub ty: Option>, } impl<'a> Parse<'a> for ComponentExport<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; + let id = parser.parse()?; + let debug_name = parser.parse()?; let name = parser.parse()?; let kind = parser.parse()?; - Ok(ComponentExport { span, name, kind }) + let ty = if !parser.is_empty() { + Some(parser.parens(|p| p.parse())?) + } else { + None + }; + Ok(ComponentExport { + span, + id, + debug_name, + name, + kind, + ty, + }) } } @@ -85,25 +105,33 @@ impl<'a> ComponentExportKind<'a> { export_names: Default::default(), }) } + + pub(crate) fn ty(span: Span, id: Id<'a>) -> Self { + Self::Type(ItemRef { + kind: kw::r#type(span), + idx: Index::Id(id), + export_names: Default::default(), + }) + } } impl<'a> Parse<'a> for ComponentExportKind<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parens(|parser| { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { // Remove core prefix parser.parse::()?; Ok(Self::CoreModule(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Func(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Value(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Type(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Component(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Instance(parser.parse()?)) } else { Err(l.error()) @@ -113,23 +141,23 @@ impl<'a> Parse<'a> for ComponentExportKind<'a> { } impl Peek for ComponentExportKind<'_> { - fn peek(cursor: Cursor) -> bool { - let cursor = match cursor.lparen() { + fn peek(cursor: Cursor) -> Result { + let cursor = match cursor.lparen()? { Some(c) => c, - None => return false, + None => return Ok(false), }; - let cursor = match cursor.keyword() { - Some(("core", c)) => match c.keyword() { + let cursor = match cursor.keyword()? { + Some(("core", c)) => match c.keyword()? { Some(("module", c)) => c, - _ => return false, + _ => return Ok(false), }, Some(("func", c)) | Some(("value", c)) | Some(("type", c)) | Some(("component", c)) | Some(("instance", c)) => c, - _ => return false, + _ => return Ok(false), }; Index::peek(cursor) @@ -139,3 +167,65 @@ impl Peek for ComponentExportKind<'_> { "component export" } } + +/// A listing of inline `(export "foo" )` statements on a WebAssembly +/// component item in its textual format. +#[derive(Debug, Default)] +pub struct InlineExport<'a> { + /// The extra names to export an item as, if any. + pub names: Vec>, +} + +impl<'a> Parse<'a> for InlineExport<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut names = Vec::new(); + while parser.peek::()? { + names.push(parser.parens(|p| { + p.parse::()?; + p.parse() + })?); + } + Ok(InlineExport { names }) + } +} + +impl Peek for InlineExport<'_> { + fn peek(cursor: Cursor<'_>) -> Result { + let cursor = match cursor.lparen()? { + Some(cursor) => cursor, + None => return Ok(false), + }; + let cursor = match cursor.keyword()? { + Some(("export", cursor)) => cursor, + _ => return Ok(false), + }; + + // (export "foo") + if let Some((_, cursor)) = cursor.string()? { + return Ok(cursor.rparen()?.is_some()); + } + + // (export (interface "foo")) + let cursor = match cursor.lparen()? { + Some(cursor) => cursor, + None => return Ok(false), + }; + let cursor = match cursor.keyword()? { + Some(("interface", cursor)) => cursor, + _ => return Ok(false), + }; + let cursor = match cursor.string()? { + Some((_, cursor)) => cursor, + _ => return Ok(false), + }; + let cursor = match cursor.rparen()? { + Some(cursor) => cursor, + _ => return Ok(false), + }; + Ok(cursor.rparen()?.is_some()) + } + + fn display() -> &'static str { + "inline export" + } +} diff --git a/crates/wast/src/component/func.rs b/crates/wast/src/component/func.rs index c265b3cbb4..24cbb3eb67 100644 --- a/crates/wast/src/component/func.rs +++ b/crates/wast/src/component/func.rs @@ -1,5 +1,4 @@ use crate::component::*; -use crate::core; use crate::kw; use crate::parser::{Parse, Parser, Result}; use crate::token::{Id, Index, LParen, NameAnnotation, Span}; @@ -39,6 +38,7 @@ impl<'a> Parse<'a> for CoreFunc<'a> { /// Represents the kind of core functions. #[derive(Debug)] +#[allow(missing_docs)] pub enum CoreFuncKind<'a> { /// The core function is defined in terms of lowering a component function. /// @@ -47,18 +47,32 @@ pub enum CoreFuncKind<'a> { /// The core function is defined in terms of aliasing a module instance export. /// /// The core function is actually a member of the core alias section. - Alias(InlineExportAlias<'a>), + Alias(InlineExportAlias<'a, true>), + ResourceNew(CanonResourceNew<'a>), + ResourceDrop(CanonResourceDrop<'a>), + ResourceRep(CanonResourceRep<'a>), } impl<'a> Parse<'a> for CoreFuncKind<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parens(|parser| { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; - Ok(Self::Lower(parser.parse()?)) - } else if l.peek::() { - Ok(Self::Alias(parser.parse()?)) + } else if l.peek::()? { + return Ok(Self::Alias(parser.parse()?)); + } else { + return Err(l.error()); + } + let mut l = parser.lookahead1(); + if l.peek::()? { + Ok(CoreFuncKind::Lower(parser.parse()?)) + } else if l.peek::()? { + Ok(CoreFuncKind::ResourceNew(parser.parse()?)) + } else if l.peek::()? { + Ok(CoreFuncKind::ResourceDrop(parser.parse()?)) + } else if l.peek::()? { + Ok(CoreFuncKind::ResourceRep(parser.parse()?)) } else { Err(l.error()) } @@ -80,7 +94,7 @@ pub struct Func<'a> { pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: core::InlineExport<'a>, + pub exports: InlineExport<'a>, /// The kind of function. pub kind: FuncKind<'a>, } @@ -129,7 +143,7 @@ pub enum FuncKind<'a> { /// The function is defined in terms of aliasing a component instance export. /// /// The function is actually a member of the alias section. - Alias(InlineExportAlias<'a>), + Alias(InlineExportAlias<'a, false>), } impl<'a> Parse<'a> for FuncKind<'a> { @@ -139,7 +153,7 @@ impl<'a> Parse<'a> for FuncKind<'a> { import, ty: parser.parse()?, }) - } else if parser.peek::() && parser.peek2::() { + } else if parser.peek::()? && parser.peek2::()? { parser.parens(|parser| Ok(Self::Alias(parser.parse()?))) } else { Ok(Self::Lift { @@ -173,7 +187,7 @@ impl<'a> Parse<'a> for CanonicalFunc<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; - if parser.peek::() { + if parser.peek::()? { let info = parser.parse()?; let (id, name, ty) = parser.parens(|parser| { parser.parse::()?; @@ -189,30 +203,50 @@ impl<'a> Parse<'a> for CanonicalFunc<'a> { name, kind: CanonicalFuncKind::Lift { info, ty }, }) - } else if parser.peek::() { - let info = parser.parse()?; - let (id, name) = parser.parens(|parser| { - parser.parse::()?; - parser.parse::()?; - let id = parser.parse()?; - let name = parser.parse()?; - Ok((id, name)) - })?; - - Ok(Self { - span, - id, - name, - kind: CanonicalFuncKind::Lower(info), - }) + } else if parser.peek::()? { + Self::parse_core_func(span, parser, CanonicalFuncKind::Lower) + } else if parser.peek::()? { + Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceNew) + } else if parser.peek::()? { + Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceDrop) + } else if parser.peek::()? { + Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceRep) } else { Err(parser.error("expected `canon lift` or `canon lower`")) } } } +impl<'a> CanonicalFunc<'a> { + fn parse_core_func( + span: Span, + parser: Parser<'a>, + variant: fn(T) -> CanonicalFuncKind<'a>, + ) -> Result + where + T: Parse<'a>, + { + let info = parser.parse()?; + let (id, name) = parser.parens(|parser| { + parser.parse::()?; + parser.parse::()?; + let id = parser.parse()?; + let name = parser.parse()?; + Ok((id, name)) + })?; + + Ok(Self { + span, + id, + name, + kind: variant(info), + }) + } +} + /// Possible ways to define a canonical function in the text format. #[derive(Debug)] +#[allow(missing_docs)] pub enum CanonicalFuncKind<'a> { /// A canonical function that is defined in terms of lifting a core function. Lift { @@ -223,6 +257,10 @@ pub enum CanonicalFuncKind<'a> { }, /// A canonical function that is defined in terms of lowering a component function. Lower(CanonLower<'a>), + + ResourceNew(CanonResourceNew<'a>), + ResourceDrop(CanonResourceDrop<'a>), + ResourceRep(CanonResourceRep<'a>), } /// Information relating to lifting a core function. @@ -296,6 +334,81 @@ impl Default for CanonLower<'_> { } } +/// Information relating to the `resource.new` intrinsic. +#[derive(Debug)] +pub struct CanonResourceNew<'a> { + /// The resource type that this intrinsic creates an owned reference to. + pub ty: Index<'a>, +} + +impl<'a> Parse<'a> for CanonResourceNew<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + + Ok(Self { + ty: parser.parse()?, + }) + } +} + +impl Default for CanonResourceNew<'_> { + fn default() -> Self { + CanonResourceNew { + ty: Index::Num(0, Span::from_offset(0)), + } + } +} + +/// Information relating to the `resource.drop` intrinsic. +#[derive(Debug)] +pub struct CanonResourceDrop<'a> { + /// The resource type that this intrinsic is dropping. + pub ty: Index<'a>, +} + +impl<'a> Parse<'a> for CanonResourceDrop<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + + Ok(Self { + ty: parser.parse()?, + }) + } +} + +impl Default for CanonResourceDrop<'_> { + fn default() -> Self { + CanonResourceDrop { + ty: Index::Num(0, Span::from_offset(0)), + } + } +} + +/// Information relating to the `resource.rep` intrinsic. +#[derive(Debug)] +pub struct CanonResourceRep<'a> { + /// The resource type that this intrinsic is accessing. + pub ty: Index<'a>, +} + +impl<'a> Parse<'a> for CanonResourceRep<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + + Ok(Self { + ty: parser.parse()?, + }) + } +} + +impl Default for CanonResourceRep<'_> { + fn default() -> Self { + CanonResourceRep { + ty: Index::Num(0, Span::from_offset(0)), + } + } +} + #[derive(Debug)] /// Canonical ABI options. pub enum CanonOpt<'a> { @@ -316,30 +429,30 @@ pub enum CanonOpt<'a> { impl<'a> Parse<'a> for CanonOpt<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(Self::StringUtf8) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::StringUtf16) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::StringLatin1Utf16) - } else if l.peek::() { + } else if l.peek::()? { parser.parens(|parser| { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { let span = parser.parse::()?.0; Ok(CanonOpt::Memory(parse_trailing_item_ref( kw::memory(span), parser, )?)) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(CanonOpt::Realloc( parser.parse::>()?.0, )) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(CanonOpt::PostReturn( parser.parse::>()?.0, diff --git a/crates/wast/src/component/import.rs b/crates/wast/src/component/import.rs index 18b92dfd17..0b83f0ff62 100644 --- a/crates/wast/src/component/import.rs +++ b/crates/wast/src/component/import.rs @@ -1,16 +1,15 @@ use crate::component::*; use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; -use crate::token::Index; -use crate::token::{Id, NameAnnotation, Span}; +use crate::token::{Id, Index, LParen, NameAnnotation, Span}; /// An `import` statement and entry in a WebAssembly component. #[derive(Debug)] pub struct ComponentImport<'a> { /// Where this `import` was defined pub span: Span, - /// The name of the item to import. - pub name: &'a str, + /// The name of the item being imported. + pub name: ComponentExternName<'a>, /// The item that's being imported. pub item: ItemSig<'a>, } @@ -24,6 +23,28 @@ impl<'a> Parse<'a> for ComponentImport<'a> { } } +/// The different ways an import can be named. +#[derive(Debug, Copy, Clone)] +pub enum ComponentExternName<'a> { + /// This is a kebab-named import where a top-level name is assigned. + Kebab(&'a str), + /// This is an interface import where the string is an ID. + Interface(&'a str), +} + +impl<'a> Parse<'a> for ComponentExternName<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::()? { + Ok(ComponentExternName::Interface(parser.parens(|p| { + p.parse::()?; + p.parse() + })?)) + } else { + Ok(ComponentExternName::Kebab(parser.parse()?)) + } + } +} + /// An item signature for imported items. #[derive(Debug)] pub struct ItemSig<'a> { @@ -41,41 +62,54 @@ pub struct ItemSig<'a> { impl<'a> Parse<'a> for ItemSig<'a> { fn parse(parser: Parser<'a>) -> Result { - let mut l = parser.lookahead1(); - let (span, parse_kind): (_, fn(Parser<'a>) -> Result) = if l.peek::() - { - let span = parser.parse::()?.0; - parser.parse::()?; - (span, |parser| Ok(ItemSigKind::CoreModule(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemSigKind::Func(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemSigKind::Component(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemSigKind::Instance(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemSigKind::Value(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| { - Ok(ItemSigKind::Type(parser.parens(|parser| parser.parse())?)) - }) - } else { - return Err(l.error()); - }; - Ok(Self { - span, - id: parser.parse()?, - name: parser.parse()?, - kind: parse_kind(parser)?, - }) + parse_item_sig(parser, true) } } +/// An item signature for imported items. +#[derive(Debug)] +pub struct ItemSigNoName<'a>(pub ItemSig<'a>); + +impl<'a> Parse<'a> for ItemSigNoName<'a> { + fn parse(parser: Parser<'a>) -> Result { + Ok(ItemSigNoName(parse_item_sig(parser, false)?)) + } +} + +fn parse_item_sig<'a>(parser: Parser<'a>, name: bool) -> Result> { + let mut l = parser.lookahead1(); + let (span, parse_kind): (_, fn(Parser<'a>) -> Result) = if l.peek::()? { + let span = parser.parse::()?.0; + parser.parse::()?; + (span, |parser| Ok(ItemSigKind::CoreModule(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Func(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Component(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Instance(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Value(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| { + Ok(ItemSigKind::Type(parser.parens(|parser| parser.parse())?)) + }) + } else { + return Err(l.error()); + }; + Ok(ItemSig { + span, + id: if name { parser.parse()? } else { None }, + name: if name { parser.parse()? } else { None }, + kind: parse_kind(parser)?, + }) +} + /// The kind of signatures for imported items. #[derive(Debug)] pub enum ItemSigKind<'a> { @@ -98,13 +132,23 @@ pub enum ItemSigKind<'a> { pub enum TypeBounds<'a> { /// The equality type bounds. Eq(Index<'a>), + /// A resource type is imported/exported, + SubResource, } impl<'a> Parse<'a> for TypeBounds<'a> { fn parse(parser: Parser<'a>) -> Result { - // Currently this is the only supported type bounds. - parser.parse::()?; - Ok(Self::Eq(parser.parse()?)) + let mut l = parser.lookahead1(); + if l.peek::()? { + parser.parse::()?; + Ok(Self::Eq(parser.parse()?)) + } else if l.peek::()? { + parser.parse::()?; + parser.parse::()?; + Ok(Self::SubResource) + } else { + Err(l.error()) + } } } @@ -112,10 +156,10 @@ impl<'a> Parse<'a> for TypeBounds<'a> { /// /// This is the same as `core::InlineImport` except only one string import is /// required. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub struct InlineImport<'a> { /// The name of the item being imported. - pub name: &'a str, + pub name: ComponentExternName<'a>, } impl<'a> Parse<'a> for InlineImport<'a> { @@ -128,20 +172,39 @@ impl<'a> Parse<'a> for InlineImport<'a> { } impl Peek for InlineImport<'_> { - fn peek(cursor: Cursor<'_>) -> bool { - let cursor = match cursor.lparen() { + fn peek(cursor: Cursor<'_>) -> Result { + let cursor = match cursor.lparen()? { Some(cursor) => cursor, - None => return false, + None => return Ok(false), }; - let cursor = match cursor.keyword() { + let cursor = match cursor.keyword()? { Some(("import", cursor)) => cursor, - _ => return false, + _ => return Ok(false), + }; + + // (import "foo") + if let Some((_, cursor)) = cursor.string()? { + return Ok(cursor.rparen()?.is_some()); + } + + // (import (interface "foo")) + let cursor = match cursor.lparen()? { + Some(cursor) => cursor, + None => return Ok(false), + }; + let cursor = match cursor.keyword()? { + Some(("interface", cursor)) => cursor, + _ => return Ok(false), }; - let cursor = match cursor.string() { + let cursor = match cursor.string()? { Some((_, cursor)) => cursor, - None => return false, + _ => return Ok(false), + }; + let cursor = match cursor.rparen()? { + Some(cursor) => cursor, + _ => return Ok(false), }; - cursor.rparen().is_some() + Ok(cursor.rparen()?.is_some()) } fn display() -> &'static str { diff --git a/crates/wast/src/component/instance.rs b/crates/wast/src/component/instance.rs index 8c8c1edb35..dc7b3faf44 100644 --- a/crates/wast/src/component/instance.rs +++ b/crates/wast/src/component/instance.rs @@ -51,7 +51,7 @@ pub enum CoreInstanceKind<'a> { impl<'a> Parse<'a> for CoreInstanceKind<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() && parser.peek2::() { + if parser.peek::()? && parser.peek2::()? { parser.parens(|parser| { parser.parse::()?; Ok(Self::Instantiate { @@ -168,7 +168,7 @@ pub struct Instance<'a> { pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: core::InlineExport<'a>, + pub exports: InlineExport<'a>, /// What kind of instance this is. pub kind: InstanceKind<'a>, } @@ -221,7 +221,7 @@ impl<'a> Parse<'a> for InstanceKind<'a> { }); } - if parser.peek::() && parser.peek2::() { + if parser.peek::()? && parser.peek2::()? { parser.parens(|parser| { parser.parse::()?; Ok(Self::Instantiate { diff --git a/crates/wast/src/component/item_ref.rs b/crates/wast/src/component/item_ref.rs index c3bbf2f9f4..cc8edc9b5b 100644 --- a/crates/wast/src/component/item_ref.rs +++ b/crates/wast/src/component/item_ref.rs @@ -1,7 +1,7 @@ use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use crate::token::Index; -fn peek(cursor: Cursor) -> bool { +fn peek(cursor: Cursor) -> Result { // This is a little fancy because when parsing something like: // // (type (component (type $foo))) @@ -16,25 +16,25 @@ fn peek(cursor: Cursor) -> bool { // strings. // Peek for the given keyword type - if !K::peek(cursor) { - return false; + if !K::peek(cursor)? { + return Ok(false); } // Move past the given keyword - let cursor = match cursor.keyword() { + let cursor = match cursor.keyword()? { Some((_, c)) => c, - _ => return false, + _ => return Ok(false), }; // Peek an id or integer index, followed by `)` or string to disambiguate - match cursor - .id() - .map(|p| p.1) - .or_else(|| cursor.integer().map(|p| p.1)) - { - Some(cursor) => cursor.rparen().is_some() || cursor.string().is_some(), + let cursor = match cursor.id()? { + Some((_, cursor)) => Some(cursor), + None => cursor.integer()?.map(|p| p.1), + }; + Ok(match cursor { + Some(cursor) => cursor.rparen()?.is_some() || cursor.string()?.is_some(), None => false, - } + }) } /// Parses core item references. @@ -65,7 +65,7 @@ impl<'a, K: Parse<'a>> Parse<'a> for CoreItemRef<'a, K> { } impl<'a, K: Peek> Peek for CoreItemRef<'a, K> { - fn peek(cursor: Cursor<'_>) -> bool { + fn peek(cursor: Cursor<'_>) -> Result { peek::(cursor) } @@ -102,7 +102,7 @@ impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { } impl<'a, K: Peek> Peek for ItemRef<'a, K> { - fn peek(cursor: Cursor<'_>) -> bool { + fn peek(cursor: Cursor<'_>) -> Result { peek::(cursor) } @@ -120,7 +120,7 @@ where K: Parse<'a> + Default, { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { + if parser.peek::>()? { Ok(IndexOrRef(ItemRef { kind: K::default(), idx: parser.parse()?, @@ -141,7 +141,7 @@ where K: Parse<'a> + Default, { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { + if parser.peek::>()? { Ok(IndexOrCoreRef(CoreItemRef { kind: K::default(), idx: parser.parse()?, diff --git a/crates/wast/src/component/module.rs b/crates/wast/src/component/module.rs index a8c606136c..6871af8d4c 100644 --- a/crates/wast/src/component/module.rs +++ b/crates/wast/src/component/module.rs @@ -18,7 +18,7 @@ pub struct CoreModule<'a> { pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: core::InlineExport<'a>, + pub exports: InlineExport<'a>, /// What kind of module this is, be it an inline-defined or imported one. pub kind: CoreModuleKind<'a>, } diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index 1478fe3bf9..3e3169aa6d 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -1,5 +1,5 @@ use crate::component::*; -use crate::core; +use crate::core::{self, ValType}; use crate::kw; use crate::names::Namespace; use crate::token::Span; @@ -83,6 +83,17 @@ impl<'a> ComponentState<'a> { ..ComponentState::default() } } + + fn register_item_sig(&mut self, sig: &ItemSig<'a>) -> Result { + match &sig.kind { + ItemSigKind::CoreModule(_) => self.core_modules.register(sig.id, "core module"), + ItemSigKind::Func(_) => self.funcs.register(sig.id, "func"), + ItemSigKind::Component(_) => self.components.register(sig.id, "component"), + ItemSigKind::Instance(_) => self.instances.register(sig.id, "instance"), + ItemSigKind::Value(_) => self.values.register(sig.id, "value"), + ItemSigKind::Type(_) => self.types.register(sig.id, "type"), + } + } } impl<'a> Resolver<'a> { @@ -153,8 +164,13 @@ impl<'a> Resolver<'a> { ComponentField::Func(_) => unreachable!("should be expanded already"), ComponentField::Start(s) => self.start(s), ComponentField::Import(i) => self.item_sig(&mut i.item), - ComponentField::Export(e) => self.export(&mut e.kind), - ComponentField::Custom(_) => Ok(()), + ComponentField::Export(e) => { + if let Some(ty) = &mut e.ty { + self.item_sig(&mut ty.0)?; + } + self.export(&mut e.kind) + } + ComponentField::Custom(_) | ComponentField::Producers(_) => Ok(()), } } @@ -241,6 +257,7 @@ impl<'a> Resolver<'a> { ItemSigKind::Value(t) => self.component_val_type(&mut t.0), ItemSigKind::Type(b) => match b { TypeBounds::Eq(i) => self.resolve_ns(i, Ns::Type), + TypeBounds::SubResource => Ok(()), }, } } @@ -356,6 +373,11 @@ impl<'a> Resolver<'a> { self.component_item_ref(&mut info.func)?; &mut info.opts } + CanonicalFuncKind::ResourceNew(info) => return self.resolve_ns(&mut info.ty, Ns::Type), + CanonicalFuncKind::ResourceRep(info) => return self.resolve_ns(&mut info.ty, Ns::Type), + CanonicalFuncKind::ResourceDrop(info) => { + return self.resolve_ns(&mut info.ty, Ns::Type) + } }; for opt in opts { @@ -425,20 +447,15 @@ impl<'a> Resolver<'a> { } } ComponentDefinedType::List(l) => { - self.component_val_type(&mut *l.element)?; + self.component_val_type(&mut l.element)?; } ComponentDefinedType::Tuple(t) => { for field in t.fields.iter_mut() { self.component_val_type(field)?; } } - ComponentDefinedType::Union(t) => { - for ty in t.types.iter_mut() { - self.component_val_type(ty)?; - } - } ComponentDefinedType::Option(o) => { - self.component_val_type(&mut *o.element)?; + self.component_val_type(&mut o.element)?; } ComponentDefinedType::Result(r) => { if let Some(ty) = &mut r.ok { @@ -449,6 +466,9 @@ impl<'a> Resolver<'a> { self.component_val_type(ty)?; } } + ComponentDefinedType::Own(t) | ComponentDefinedType::Borrow(t) => { + self.resolve_ns(t, Ns::Type)?; + } } Ok(()) } @@ -497,6 +517,30 @@ impl<'a> Resolver<'a> { self.instance_type(i)?; self.stack.pop(); } + TypeDef::Resource(r) => { + match &mut r.rep { + ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {} + ValType::Ref(r) => match &mut r.heap { + core::HeapType::Func + | core::HeapType::Extern + | core::HeapType::Exn + | core::HeapType::Any + | core::HeapType::Eq + | core::HeapType::Array + | core::HeapType::I31 + | core::HeapType::Struct + | core::HeapType::None + | core::HeapType::NoFunc + | core::HeapType::NoExtern => {} + core::HeapType::Index(id) => { + self.resolve_ns(id, Ns::Type)?; + } + }, + } + if let Some(dtor) = &mut r.dtor { + self.core_item_ref(dtor)?; + } + } } Ok(()) } @@ -522,9 +566,12 @@ impl<'a> Resolver<'a> { ComponentTypeDecl::Type(ty) => { state.types.register(ty.id, "type")?; } - // Only the type namespace is populated within the component type - // namespace so these are ignored here. - ComponentTypeDecl::Import(_) | ComponentTypeDecl::Export(_) => {} + ComponentTypeDecl::Export(e) => { + state.register_item_sig(&e.item)?; + } + ComponentTypeDecl::Import(i) => { + state.register_item_sig(&i.item)?; + } } Ok(()) }, @@ -551,7 +598,9 @@ impl<'a> Resolver<'a> { InstanceTypeDecl::Type(ty) => { state.types.register(ty.id, "type")?; } - InstanceTypeDecl::Export(_export) => {} + InstanceTypeDecl::Export(export) => { + state.register_item_sig(&export.item)?; + } } Ok(()) }, @@ -767,7 +816,12 @@ impl<'a> ComponentState<'a> { ComponentField::Type(t) => self.types.register(t.id, "type")?, ComponentField::CanonicalFunc(f) => match &f.kind { CanonicalFuncKind::Lift { .. } => self.funcs.register(f.id, "func")?, - CanonicalFuncKind::Lower(_) => self.core_funcs.register(f.id, "core func")?, + CanonicalFuncKind::Lower(_) + | CanonicalFuncKind::ResourceNew(_) + | CanonicalFuncKind::ResourceRep(_) + | CanonicalFuncKind::ResourceDrop(_) => { + self.core_funcs.register(f.id, "core func")? + } }, ComponentField::CoreFunc(_) | ComponentField::Func(_) => { unreachable!("should be expanded already") @@ -778,20 +832,18 @@ impl<'a> ComponentState<'a> { } return Ok(()); } - ComponentField::Import(i) => match &i.item.kind { - ItemSigKind::CoreModule(_) => { - self.core_modules.register(i.item.id, "core module")? + ComponentField::Import(i) => self.register_item_sig(&i.item)?, + ComponentField::Export(e) => match &e.kind { + ComponentExportKind::CoreModule(_) => { + self.core_modules.register(e.id, "core module")? } - ItemSigKind::Func(_) => self.funcs.register(i.item.id, "func")?, - ItemSigKind::Component(_) => self.components.register(i.item.id, "component")?, - ItemSigKind::Instance(_) => self.instances.register(i.item.id, "instance")?, - ItemSigKind::Value(_) => self.values.register(i.item.id, "value")?, - ItemSigKind::Type(_) => self.types.register(i.item.id, "type")?, + ComponentExportKind::Func(_) => self.funcs.register(e.id, "func")?, + ComponentExportKind::Instance(_) => self.instances.register(e.id, "instance")?, + ComponentExportKind::Value(_) => self.values.register(e.id, "value")?, + ComponentExportKind::Component(_) => self.components.register(e.id, "component")?, + ComponentExportKind::Type(_) => self.types.register(e.id, "type")?, }, - ComponentField::Export(_) | ComponentField::Custom(_) => { - // Exports and custom sections don't define any items - return Ok(()); - } + ComponentField::Custom(_) | ComponentField::Producers(_) => return Ok(()), }; Ok(()) diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index 6c4e99516a..72eced02a8 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -53,7 +53,7 @@ pub enum CoreTypeDef<'a> { impl<'a> Parse<'a> for CoreTypeDef<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; Ok(Self::Module(parser.parse()?)) } else { @@ -94,13 +94,13 @@ pub enum ModuleTypeDecl<'a> { impl<'a> Parse<'a> for ModuleTypeDecl<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { Ok(Self::Type(parser.parse()?)) - } else if l.peek::() { - Ok(Self::Alias(Alias::parse_outer_type_alias(parser, true)?)) - } else if l.peek::() { + } else if l.peek::()? { + Ok(Self::Alias(Alias::parse_outer_core_type_alias(parser)?)) + } else if l.peek::()? { Ok(Self::Import(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; let name = parser.parse()?; let et = parser.parens(|parser| parser.parse())?; @@ -133,17 +133,31 @@ pub struct Type<'a> { pub name: Option>, /// If present, inline export annotations which indicate names this /// definition should be exported under. - pub exports: core::InlineExport<'a>, + pub exports: InlineExport<'a>, /// The type definition. pub def: TypeDef<'a>, } -impl<'a> Parse<'a> for Type<'a> { - fn parse(parser: Parser<'a>) -> Result { +impl<'a> Type<'a> { + /// Parses a `Type` while allowing inline `(export "...")` names to be + /// defined. + pub fn parse_maybe_with_inline_exports(parser: Parser<'a>) -> Result { + Type::parse(parser, true) + } + + fn parse_no_inline_exports(parser: Parser<'a>) -> Result { + Type::parse(parser, false) + } + + fn parse(parser: Parser<'a>, allow_inline_exports: bool) -> Result { let span = parser.parse::()?.0; let id = parser.parse()?; let name = parser.parse()?; - let exports = parser.parse()?; + let exports = if allow_inline_exports { + parser.parse()? + } else { + Default::default() + }; let def = parser.parse()?; Ok(Self { @@ -167,22 +181,27 @@ pub enum TypeDef<'a> { Component(ComponentType<'a>), /// An instance type. Instance(InstanceType<'a>), + /// A resource type. + Resource(ResourceType<'a>), } impl<'a> Parse<'a> for TypeDef<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { + if parser.peek::()? { parser.parens(|parser| { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(Self::Func(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Component(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Instance(parser.parse()?)) + } else if l.peek::()? { + parser.parse::()?; + Ok(Self::Resource(parser.parse()?)) } else { Ok(Self::Defined(ComponentDefinedType::parse_non_primitive( parser, l, @@ -220,43 +239,43 @@ pub enum PrimitiveValType { impl<'a> Parse<'a> for PrimitiveValType { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(Self::Bool) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::S8) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::U8) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::S16) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::U16) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::S32) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::U32) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::S64) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::U64) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Float32) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Float64) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::Char) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(Self::String) } else { @@ -266,9 +285,9 @@ impl<'a> Parse<'a> for PrimitiveValType { } impl Peek for PrimitiveValType { - fn peek(cursor: crate::parser::Cursor<'_>) -> bool { - matches!( - cursor.keyword(), + fn peek(cursor: crate::parser::Cursor<'_>) -> Result { + Ok(matches!( + cursor.keyword()?, Some(("bool", _)) | Some(("s8", _)) | Some(("u8", _)) @@ -282,7 +301,7 @@ impl Peek for PrimitiveValType { | Some(("float64", _)) | Some(("char", _)) | Some(("string", _)) - ) + )) } fn display() -> &'static str { @@ -302,7 +321,7 @@ pub enum ComponentValType<'a> { impl<'a> Parse<'a> for ComponentValType<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { + if parser.peek::>()? { Ok(Self::Ref(parser.parse()?)) } else { Ok(Self::Inline(InlineComponentValType::parse(parser)?.0)) @@ -311,8 +330,8 @@ impl<'a> Parse<'a> for ComponentValType<'a> { } impl Peek for ComponentValType<'_> { - fn peek(cursor: crate::parser::Cursor<'_>) -> bool { - Index::peek(cursor) || ComponentDefinedType::peek(cursor) + fn peek(cursor: crate::parser::Cursor<'_>) -> Result { + Ok(Index::peek(cursor)? || ComponentDefinedType::peek(cursor)?) } fn display() -> &'static str { @@ -329,7 +348,7 @@ pub struct InlineComponentValType<'a>(ComponentDefinedType<'a>); impl<'a> Parse<'a> for InlineComponentValType<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { + if parser.peek::()? { parser.parens(|parser| { Ok(Self(ComponentDefinedType::parse_non_primitive( parser, @@ -353,32 +372,37 @@ pub enum ComponentDefinedType<'a> { Tuple(Tuple<'a>), Flags(Flags<'a>), Enum(Enum<'a>), - Union(Union<'a>), Option(OptionType<'a>), Result(ResultType<'a>), + Own(Index<'a>), + Borrow(Index<'a>), } impl<'a> ComponentDefinedType<'a> { fn parse_non_primitive(parser: Parser<'a>, mut l: Lookahead1<'a>) -> Result { parser.depth_check()?; - if l.peek::() { + if l.peek::()? { Ok(Self::Record(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Variant(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::List(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Tuple(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Flags(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Enum(parser.parse()?)) - } else if l.peek::() { - Ok(Self::Union(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Option(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Result(parser.parse()?)) + } else if l.peek::()? { + parser.parse::()?; + Ok(Self::Own(parser.parse()?)) + } else if l.peek::()? { + parser.parse::()?; + Ok(Self::Borrow(parser.parse()?)) } else { Err(l.error()) } @@ -392,26 +416,27 @@ impl Default for ComponentDefinedType<'_> { } impl Peek for ComponentDefinedType<'_> { - fn peek(cursor: crate::parser::Cursor<'_>) -> bool { - if PrimitiveValType::peek(cursor) { - return true; + fn peek(cursor: crate::parser::Cursor<'_>) -> Result { + if PrimitiveValType::peek(cursor)? { + return Ok(true); } - match cursor.lparen() { + Ok(match cursor.lparen()? { Some(cursor) => matches!( - cursor.keyword(), + cursor.keyword()?, Some(("record", _)) | Some(("variant", _)) | Some(("list", _)) | Some(("tuple", _)) | Some(("flags", _)) | Some(("enum", _)) - | Some(("union", _)) | Some(("option", _)) | Some(("result", _)) + | Some(("own", _)) + | Some(("borrow", _)) ), None => false, - } + }) } fn display() -> &'static str { @@ -601,24 +626,6 @@ impl<'a> Parse<'a> for Enum<'a> { } } -/// A union type. -#[derive(Debug)] -pub struct Union<'a> { - /// The types of the union. - pub types: Vec>, -} - -impl<'a> Parse<'a> for Union<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut types = Vec::new(); - while !parser.is_empty() { - types.push(parser.parse()?); - } - Ok(Self { types }) - } -} - /// An optional type. #[derive(Debug)] pub struct OptionType<'a> { @@ -649,7 +656,7 @@ impl<'a> Parse<'a> for ResultType<'a> { parser.parse::()?; let ok: Option = parser.parse()?; - let err: Option = if parser.peek::() { + let err: Option = if parser.peek::()? { Some(parser.parens(|parser| { parser.parse::()?; parser.parse() @@ -679,12 +686,12 @@ pub struct ComponentFunctionType<'a> { impl<'a> Parse<'a> for ComponentFunctionType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut params: Vec = Vec::new(); - while parser.peek2::() { + while parser.peek2::()? { params.push(parser.parens(|p| p.parse())?); } let mut results: Vec = Vec::new(); - while parser.peek2::() { + while parser.peek2::()? { results.push(parser.parens(|p| p.parse())?); } @@ -698,8 +705,8 @@ impl<'a> Parse<'a> for ComponentFunctionType<'a> { /// A parameter of a [`ComponentFunctionType`]. #[derive(Debug)] pub struct ComponentFunctionParam<'a> { - /// An optionally-specified name of this parameter - pub name: Option<&'a str>, + /// The name of the parameter + pub name: &'a str, /// The type of the parameter. pub ty: ComponentValType<'a>, } @@ -739,7 +746,7 @@ pub struct ComponentExportType<'a> { /// Where this export was defined. pub span: Span, /// The name of this export. - pub name: &'a str, + pub name: ComponentExternName<'a>, /// The signature of the item. pub item: ItemSig<'a>, } @@ -747,8 +754,15 @@ pub struct ComponentExportType<'a> { impl<'a> Parse<'a> for ComponentExportType<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; + let id = parser.parse()?; + let debug_name = parser.parse()?; let name = parser.parse()?; - let item = parser.parens(|p| p.parse())?; + let item = parser.parens(|p| { + let mut item = p.parse::>()?.0; + item.id = id; + item.name = debug_name; + Ok(item) + })?; Ok(Self { span, name, item }) } } @@ -787,15 +801,15 @@ pub enum ComponentTypeDecl<'a> { impl<'a> Parse<'a> for ComponentTypeDecl<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { Ok(Self::CoreType(parser.parse()?)) - } else if l.peek::() { - Ok(Self::Type(parser.parse()?)) - } else if l.peek::() { - Ok(Self::Alias(Alias::parse_outer_type_alias(parser, false)?)) - } else if l.peek::() { + } else if l.peek::()? { + Ok(Self::Type(Type::parse_no_inline_exports(parser)?)) + } else if l.peek::()? { + Ok(Self::Alias(parser.parse()?)) + } else if l.peek::()? { Ok(Self::Import(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { Ok(Self::Export(parser.parse()?)) } else { Err(l.error()) @@ -845,13 +859,13 @@ pub enum InstanceTypeDecl<'a> { impl<'a> Parse<'a> for InstanceTypeDecl<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { Ok(Self::CoreType(parser.parse()?)) - } else if l.peek::() { - Ok(Self::Type(parser.parse()?)) - } else if l.peek::() { - Ok(Self::Alias(Alias::parse_outer_type_alias(parser, false)?)) - } else if l.peek::() { + } else if l.peek::()? { + Ok(Self::Type(Type::parse_no_inline_exports(parser)?)) + } else if l.peek::()? { + Ok(Self::Alias(parser.parse()?)) + } else if l.peek::()? { Ok(Self::Export(parser.parse()?)) } else { Err(l.error()) @@ -869,6 +883,33 @@ impl<'a> Parse<'a> for Vec> { } } +/// A type definition for an instance type. +#[derive(Debug)] +pub struct ResourceType<'a> { + /// Representation, in core WebAssembly, of this resource. + pub rep: core::ValType<'a>, + /// The declarations of the instance type. + pub dtor: Option>, +} + +impl<'a> Parse<'a> for ResourceType<'a> { + fn parse(parser: Parser<'a>) -> Result { + let rep = parser.parens(|p| { + p.parse::()?; + p.parse() + })?; + let dtor = if parser.is_empty() { + None + } else { + Some(parser.parens(|p| { + p.parse::()?; + p.parens(|p| p.parse()) + })?) + }; + Ok(Self { rep, dtor }) + } +} + /// A value type declaration used for values in import signatures. #[derive(Debug)] pub struct ComponentValTypeUse<'a>(pub ComponentValType<'a>); @@ -897,7 +938,7 @@ pub enum CoreTypeUse<'a, T> { impl<'a, T: Parse<'a>> Parse<'a> for CoreTypeUse<'a, T> { fn parse(parser: Parser<'a>) -> Result { // Here the core context is assumed, so no core prefix is expected - if parser.peek::() && parser.peek2::>() { + if parser.peek::()? && parser.peek2::>()? { Ok(Self::Ref(parser.parens(|parser| parser.parse())?)) } else { Ok(Self::Inline(parser.parse()?)) @@ -930,7 +971,7 @@ pub enum ComponentTypeUse<'a, T> { impl<'a, T: Parse<'a>> Parse<'a> for ComponentTypeUse<'a, T> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() && parser.peek2::>() { + if parser.peek::()? && parser.peek2::>()? { Ok(Self::Ref(parser.parens(|parser| parser.parse())?)) } else { Ok(Self::Inline(parser.parse()?)) diff --git a/crates/wast/src/component/wast.rs b/crates/wast/src/component/wast.rs index 8409a6c969..72d8bf15bc 100644 --- a/crates/wast/src/component/wast.rs +++ b/crates/wast/src/component/wast.rs @@ -25,7 +25,6 @@ pub enum WastVal<'a> { Tuple(Vec>), Variant(&'a str, Option>>), Enum(&'a str), - Union(u32, Box>), Option(Option>>), Result(Result>>, Option>>>), Flags(Vec<&'a str>), @@ -36,10 +35,10 @@ static CASES: &[(&str, fn(Parser<'_>) -> Result>)] = { &[ ("bool.const", |p| { let mut l = p.lookahead1(); - if l.peek::() { + if l.peek::()? { p.parse::()?; Ok(Bool(true)) - } else if l.peek::() { + } else if l.peek::()? { p.parse::()?; Ok(Bool(false)) } else { @@ -103,11 +102,6 @@ static CASES: &[(&str, fn(Parser<'_>) -> Result>)] = { Ok(Variant(name, payload)) }), ("enum.const", |p| Ok(Enum(p.parse()?))), - ("union.const", |p| { - let num = p.parse()?; - let payload = Box::new(p.parens(|p| p.parse())?); - Ok(Union(num, payload)) - }), ("option.none", |_| Ok(Option(None))), ("option.some", |p| { Ok(Option(Some(Box::new(p.parens(|p| p.parse())?)))) @@ -140,7 +134,7 @@ impl<'a> Parse<'a> for WastVal<'a> { fn parse(parser: Parser<'a>) -> Result { parser.depth_check()?; let parse = parser.step(|c| { - if let Some((kw, rest)) = c.keyword() { + if let Some((kw, rest)) = c.keyword()? { if let Some(i) = CASES.iter().position(|(name, _)| *name == kw) { return Ok((CASES[i].1, rest)); } @@ -152,12 +146,12 @@ impl<'a> Parse<'a> for WastVal<'a> { } impl Peek for WastVal<'_> { - fn peek(cursor: Cursor<'_>) -> bool { - let kw = match cursor.keyword() { + fn peek(cursor: Cursor<'_>) -> Result { + let kw = match cursor.keyword()? { Some((kw, _)) => kw, - None => return false, + None => return Ok(false), }; - CASES.iter().any(|(name, _)| *name == kw) + Ok(CASES.iter().any(|(name, _)| *name == kw)) } fn display() -> &'static str { diff --git a/crates/wast/src/core/binary.rs b/crates/wast/src/core/binary.rs index 917dcb9e7a..3cfe18a356 100644 --- a/crates/wast/src/core/binary.rs +++ b/crates/wast/src/core/binary.rs @@ -108,8 +108,8 @@ impl Encoder<'_> { fn custom_sections(&mut self, place: CustomPlace) { for entry in self.customs.iter() { - if entry.place == place { - self.section(0, &(entry.name, entry)); + if entry.place() == place { + self.section(0, &(entry.name(), entry)); } } } @@ -173,10 +173,25 @@ impl Encode for RecOrType<'_> { impl Encode for Type<'_> { fn encode(&self, e: &mut Vec) { - if let Some(parent) = &self.parent { - e.push(0x50); - (1 as usize).encode(e); - parent.encode(e); + match (&self.parent, self.final_type) { + (Some(parent), Some(true)) => { + // Type is final with a supertype + e.push(0x4f); + e.push(0x01); + parent.encode(e); + } + (Some(parent), Some(false) | None) => { + // Type is not final and has a declared supertype + e.push(0x50); + e.push(0x01); + parent.encode(e); + } + (None, Some(false)) => { + // Sub was used without any declared supertype + e.push(0x50); + e.push(0x00); + } + (None, _) => {} // No supertype, sub wasn't used } match &self.def { TypeDef::Func(func) => { @@ -197,12 +212,7 @@ impl Encode for Type<'_> { impl Encode for Rec<'_> { fn encode(&self, e: &mut Vec) { - if self.types.len() == 1 { - self.types[0].encode(e); - return; - } - - e.push(0x45); + e.push(0x4e); self.types.len().encode(e); for ty in &self.types { ty.encode(e); @@ -236,13 +246,20 @@ impl<'a> Encode for HeapType<'a> { match self { HeapType::Func => e.push(0x70), HeapType::Extern => e.push(0x6f), + HeapType::Exn => e.push(0x69), HeapType::Any => e.push(0x6e), HeapType::Eq => e.push(0x6d), - HeapType::Data => e.push(0x67), - HeapType::Array => e.push(0x66), - HeapType::I31 => e.push(0x6a), - HeapType::Index(index) => { - index.encode(e); + HeapType::Struct => e.push(0x6b), + HeapType::Array => e.push(0x6a), + HeapType::I31 => e.push(0x6c), + HeapType::NoFunc => e.push(0x73), + HeapType::NoExtern => e.push(0x72), + HeapType::None => e.push(0x71), + // Note that this is encoded as a signed leb128 so be sure to cast + // to an i64 first + HeapType::Index(Index::Num(n, _)) => i64::from(*n).encode(e), + HeapType::Index(Index::Id(n)) => { + panic!("unresolved index in emission: {:?}", n) } } } @@ -261,28 +278,48 @@ impl<'a> Encode for RefType<'a> { nullable: true, heap: HeapType::Extern, } => e.push(0x6f), + // The 'exnref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::Exn, + } => e.push(0x69), // The 'eqref' binary abbreviation RefType { nullable: true, heap: HeapType::Eq, } => e.push(0x6d), - // The 'dataref' binary abbreviation + // The 'structref' binary abbreviation RefType { nullable: true, - heap: HeapType::Data, - } => e.push(0x67), + heap: HeapType::Struct, + } => e.push(0x6b), // The 'i31ref' binary abbreviation RefType { nullable: true, heap: HeapType::I31, - } => e.push(0x6a), + } => e.push(0x6c), + // The 'nullfuncref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::NoFunc, + } => e.push(0x73), + // The 'nullexternref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::NoExtern, + } => e.push(0x72), + // The 'nullref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::None, + } => e.push(0x71), - // Generic 'ref opt ' encoding + // Generic 'ref null ' encoding RefType { nullable: true, heap, } => { - e.push(0x6c); + e.push(0x63); heap.encode(e); } // Generic 'ref ' encoding @@ -290,7 +327,7 @@ impl<'a> Encode for RefType<'a> { nullable: false, heap, } => { - e.push(0x6b); + e.push(0x64); heap.encode(e); } } @@ -300,8 +337,8 @@ impl<'a> Encode for RefType<'a> { impl<'a> Encode for StorageType<'a> { fn encode(&self, e: &mut Vec) { match self { - StorageType::I8 => e.push(0x7a), - StorageType::I16 => e.push(0x79), + StorageType::I8 => e.push(0x78), + StorageType::I16 => e.push(0x77), StorageType::Val(ty) => { ty.encode(e); } @@ -427,7 +464,19 @@ impl Encode for Table<'_> { fn encode(&self, e: &mut Vec) { assert!(self.exports.names.is_empty()); match &self.kind { - TableKind::Normal(t) => t.encode(e), + TableKind::Normal { + ty, + init_expr: None, + } => ty.encode(e), + TableKind::Normal { + ty, + init_expr: Some(init_expr), + } => { + e.push(0x40); + e.push(0x00); + ty.encode(e); + init_expr.encode(e); + } _ => panic!("TableKind should be normal during encoding"), } } @@ -497,6 +546,10 @@ impl Encode for Elem<'_> { offset.encode(e); e.push(0x00); // extern_kind } + (ElemKind::Declared, ElemPayload::Indices(_)) => { + e.push(0x03); // flags + e.push(0x00); // extern_kind + } ( ElemKind::Active { table: Index::Num(0, _), @@ -524,10 +577,6 @@ impl Encode for Elem<'_> { offset.encode(e); ty.encode(e); } - (ElemKind::Declared, ElemPayload::Indices(_)) => { - e.push(0x03); // flags - e.push(0x00); // extern_kind - } (ElemKind::Declared, ElemPayload::Exprs { ty, .. }) => { e.push(0x07); // flags ty.encode(e); @@ -593,10 +642,10 @@ impl Encode for Func<'_> { } } -impl Encode for Vec> { +impl Encode for Box<[Local<'_>]> { fn encode(&self, e: &mut Vec) { let mut locals_compressed = Vec::<(u32, ValType)>::new(); - for local in self { + for local in self.iter() { if let Some((cnt, prev)) = locals_compressed.last_mut() { if *prev == local.ty { *cnt += 1; @@ -871,7 +920,7 @@ fn find_names<'a>( locals, expression, .. } = &f.kind { - for local in locals { + for local in locals.iter() { if let Some(name) = get_name(&local.id, &local.name) { local_names.push((local_idx, name)); } @@ -985,6 +1034,47 @@ impl Encode for Id<'_> { } } +impl<'a> Encode for TryTable<'a> { + fn encode(&self, dst: &mut Vec) { + self.block.encode(dst); + self.catches.encode(dst); + + let catch_all_flag_byte: u8 = match self.catch_all { + None => 0, + Some(TryTableCatchAll { + kind: TryTableCatchKind::Drop, + .. + }) => 1, + Some(TryTableCatchAll { + kind: TryTableCatchKind::Ref, + .. + }) => 2, + }; + catch_all_flag_byte.encode(dst); + if let Some(catch_all) = &self.catch_all { + catch_all.encode(dst); + } + } +} + +impl<'a> Encode for TryTableCatch<'a> { + fn encode(&self, dst: &mut Vec) { + let catch_flag_byte: u8 = match self.kind { + TryTableCatchKind::Drop => 0, + TryTableCatchKind::Ref => 1, + }; + catch_flag_byte.encode(dst); + self.tag.encode(dst); + self.label.encode(dst); + } +} + +impl<'a> Encode for TryTableCatchAll<'a> { + fn encode(&self, dst: &mut Vec) { + self.label.encode(dst); + } +} + impl Encode for V128Const { fn encode(&self, dst: &mut Vec) { dst.extend_from_slice(&self.to_le_bytes()); @@ -1010,6 +1100,16 @@ impl<'a> Encode for SelectTypes<'a> { } impl Encode for Custom<'_> { + fn encode(&self, e: &mut Vec) { + match self { + Custom::Raw(r) => r.encode(e), + Custom::Producers(p) => p.encode(e), + Custom::Dylink0(p) => p.encode(e), + } + } +} + +impl Encode for RawCustomSection<'_> { fn encode(&self, e: &mut Vec) { for list in self.data.iter() { e.extend_from_slice(list); @@ -1017,6 +1117,44 @@ impl Encode for Custom<'_> { } } +impl Encode for Producers<'_> { + fn encode(&self, e: &mut Vec) { + self.fields.encode(e); + } +} + +impl Encode for Dylink0<'_> { + fn encode(&self, e: &mut Vec) { + for section in self.subsections.iter() { + e.push(section.id()); + let mut tmp = Vec::new(); + section.encode(&mut tmp); + tmp.encode(e); + } + } +} + +impl Encode for Dylink0Subsection<'_> { + fn encode(&self, e: &mut Vec) { + match self { + Dylink0Subsection::MemInfo { + memory_size, + memory_align, + table_size, + table_align, + } => { + memory_size.encode(e); + memory_align.encode(e); + table_size.encode(e); + table_align.encode(e); + } + Dylink0Subsection::Needed(libs) => libs.encode(e), + Dylink0Subsection::ExportInfo(list) => list.encode(e), + Dylink0Subsection::ImportInfo(list) => list.encode(e), + } + } +} + impl Encode for Tag<'_> { fn encode(&self, e: &mut Vec) { self.ty.encode(e); @@ -1045,6 +1183,12 @@ impl Encode for StructAccess<'_> { } } +impl Encode for ArrayFill<'_> { + fn encode(&self, e: &mut Vec) { + self.array.encode(e); + } +} + impl Encode for ArrayCopy<'_> { fn encode(&self, e: &mut Vec) { self.dest_array.encode(e); @@ -1052,6 +1196,13 @@ impl Encode for ArrayCopy<'_> { } } +impl Encode for ArrayInit<'_> { + fn encode(&self, e: &mut Vec) { + self.array.encode(e); + self.segment.encode(e); + } +} + impl Encode for ArrayNewFixed<'_> { fn encode(&self, e: &mut Vec) { self.array.encode(e); @@ -1073,9 +1224,65 @@ impl Encode for ArrayNewElem<'_> { } } +impl Encode for RefTest<'_> { + fn encode(&self, e: &mut Vec) { + e.push(0xfb); + if self.r#type.nullable { + e.push(0x15); + } else { + e.push(0x14); + } + self.r#type.heap.encode(e); + } +} + +impl Encode for RefCast<'_> { + fn encode(&self, e: &mut Vec) { + e.push(0xfb); + if self.r#type.nullable { + e.push(0x17); + } else { + e.push(0x16); + } + self.r#type.heap.encode(e); + } +} + +fn br_on_cast_flags(from_nullable: bool, to_nullable: bool) -> u8 { + let mut flag = 0; + if from_nullable { + flag |= 1 << 0; + } + if to_nullable { + flag |= 1 << 1; + } + flag +} + impl Encode for BrOnCast<'_> { fn encode(&self, e: &mut Vec) { + e.push(0xfb); + e.push(0x18); + e.push(br_on_cast_flags( + self.from_type.nullable, + self.to_type.nullable, + )); + self.label.encode(e); + self.from_type.heap.encode(e); + self.to_type.heap.encode(e); + } +} + +impl Encode for BrOnCastFail<'_> { + fn encode(&self, e: &mut Vec) { + e.push(0xfb); + e.push(0x19); + e.push(br_on_cast_flags( + self.from_type.nullable, + self.to_type.nullable, + )); self.label.encode(e); - self.r#type.encode(e); + self.from_type.heap.encode(e); + self.to_type.heap.encode(e); } } diff --git a/crates/wast/src/core/custom.rs b/crates/wast/src/core/custom.rs index 40c20b1cc7..4fe6c7c2e4 100644 --- a/crates/wast/src/core/custom.rs +++ b/crates/wast/src/core/custom.rs @@ -2,9 +2,52 @@ use crate::parser::{Parse, Parser, Result}; use crate::token::{self, Span}; use crate::{annotation, kw}; +/// A custom section within a wasm module. +#[derive(Debug)] +pub enum Custom<'a> { + /// A raw custom section with the manual placement and bytes specified. + Raw(RawCustomSection<'a>), + /// A producers custom section. + Producers(Producers<'a>), + /// The `dylink.0` custom section + Dylink0(Dylink0<'a>), +} + +impl Custom<'_> { + /// Where this custom section is placed. + pub fn place(&self) -> CustomPlace { + match self { + Custom::Raw(s) => s.place, + Custom::Producers(_) => CustomPlace::AfterLast, + Custom::Dylink0(_) => CustomPlace::BeforeFirst, + } + } + + /// The name of this custom section + pub fn name(&self) -> &str { + match self { + Custom::Raw(s) => s.name, + Custom::Producers(_) => "producers", + Custom::Dylink0(_) => "dylink.0", + } + } +} + +impl<'a> Parse<'a> for Custom<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::()? { + Ok(Custom::Producers(parser.parse()?)) + } else if parser.peek::()? { + Ok(Custom::Dylink0(parser.parse()?)) + } else { + Ok(Custom::Raw(parser.parse()?)) + } + } +} + /// A wasm custom section within a module. #[derive(Debug)] -pub struct Custom<'a> { +pub struct RawCustomSection<'a> { /// Where this `@custom` was defined. pub span: Span, @@ -49,11 +92,11 @@ pub enum CustomPlaceAnchor { Tag, } -impl<'a> Parse<'a> for Custom<'a> { +impl<'a> Parse<'a> for RawCustomSection<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let name = parser.parse()?; - let place = if parser.peek::() { + let place = if parser.peek::()? { parser.parens(|p| p.parse())? } else { CustomPlace::AfterLast @@ -62,7 +105,7 @@ impl<'a> Parse<'a> for Custom<'a> { while !parser.is_empty() { data.push(parser.parse()?); } - Ok(Custom { + Ok(RawCustomSection { span, name, place, @@ -74,16 +117,16 @@ impl<'a> Parse<'a> for Custom<'a> { impl<'a> Parse<'a> for CustomPlace { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - let ctor = if l.peek::() { + let ctor = if l.peek::()? { parser.parse::()?; - if l.peek::() { + if l.peek::()? { parser.parse::()?; return Ok(CustomPlace::BeforeFirst); } CustomPlace::Before as fn(CustomPlaceAnchor) -> _ - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; - if l.peek::() { + if l.peek::()? { parser.parse::()?; return Ok(CustomPlace::AfterLast); } @@ -97,51 +140,51 @@ impl<'a> Parse<'a> for CustomPlace { impl<'a> Parse<'a> for CustomPlaceAnchor { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Type); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Import); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Func); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Table); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Memory); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Global); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Export); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Start); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Elem); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Code); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Data); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(CustomPlaceAnchor::Tag); } @@ -149,3 +192,199 @@ impl<'a> Parse<'a> for CustomPlaceAnchor { Err(parser.error("expected a valid section name")) } } + +/// A producers custom section +#[allow(missing_docs)] +#[derive(Debug)] +pub struct Producers<'a> { + pub fields: Vec<(&'a str, Vec<(&'a str, &'a str)>)>, +} + +impl<'a> Parse<'a> for Producers<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?.0; + let mut languages = Vec::new(); + let mut sdks = Vec::new(); + let mut processed_by = Vec::new(); + while !parser.is_empty() { + parser.parens(|parser| { + let mut l = parser.lookahead1(); + let dst = if l.peek::()? { + parser.parse::()?; + &mut languages + } else if l.peek::()? { + parser.parse::()?; + &mut sdks + } else if l.peek::()? { + parser.parse::()?; + &mut processed_by + } else { + return Err(l.error()); + }; + + dst.push((parser.parse()?, parser.parse()?)); + Ok(()) + })?; + } + + let mut fields = Vec::new(); + if !languages.is_empty() { + fields.push(("language", languages)); + } + if !sdks.is_empty() { + fields.push(("sdk", sdks)); + } + if !processed_by.is_empty() { + fields.push(("processed-by", processed_by)); + } + Ok(Producers { fields }) + } +} + +/// A `dylink.0` custom section +#[allow(missing_docs)] +#[derive(Debug)] +pub struct Dylink0<'a> { + pub subsections: Vec>, +} + +/// Possible subsections of the `dylink.0` custom section +#[derive(Debug)] +#[allow(missing_docs)] +pub enum Dylink0Subsection<'a> { + MemInfo { + memory_size: u32, + memory_align: u32, + table_size: u32, + table_align: u32, + }, + Needed(Vec<&'a str>), + ExportInfo(Vec<(&'a str, u32)>), + ImportInfo(Vec<(&'a str, &'a str, u32)>), +} + +impl<'a> Parse<'a> for Dylink0<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?.0; + let mut ret = Dylink0 { + subsections: Vec::new(), + }; + while !parser.is_empty() { + parser.parens(|p| ret.parse_next(p))?; + } + Ok(ret) + } +} + +impl<'a> Dylink0<'a> { + fn parse_next(&mut self, parser: Parser<'a>) -> Result<()> { + let mut l = parser.lookahead1(); + if l.peek::()? { + parser.parse::()?; + let mut memory_size = 0; + let mut memory_align = 0; + let mut table_size = 0; + let mut table_align = 0; + if parser.peek2::()? { + parser.parens(|p| { + p.parse::()?; + memory_size = p.parse()?; + memory_align = p.parse()?; + Ok(()) + })?; + } + if parser.peek2::()? { + parser.parens(|p| { + p.parse::()?; + table_size = p.parse()?; + table_align = p.parse()?; + Ok(()) + })?; + } + self.subsections.push(Dylink0Subsection::MemInfo { + memory_size, + memory_align, + table_size, + table_align, + }); + } else if l.peek::()? { + parser.parse::()?; + let mut names = Vec::new(); + while !parser.is_empty() { + names.push(parser.parse()?); + } + self.subsections.push(Dylink0Subsection::Needed(names)); + } else if l.peek::()? { + parser.parse::()?; + let name = parser.parse()?; + let flags = parse_sym_flags(parser)?; + match self.subsections.last_mut() { + Some(Dylink0Subsection::ExportInfo(list)) => list.push((name, flags)), + _ => self + .subsections + .push(Dylink0Subsection::ExportInfo(vec![(name, flags)])), + } + } else if l.peek::()? { + parser.parse::()?; + let module = parser.parse()?; + let name = parser.parse()?; + let flags = parse_sym_flags(parser)?; + match self.subsections.last_mut() { + Some(Dylink0Subsection::ImportInfo(list)) => list.push((module, name, flags)), + _ => self + .subsections + .push(Dylink0Subsection::ImportInfo(vec![(module, name, flags)])), + } + } else { + return Err(l.error()); + } + Ok(()) + } +} + +fn parse_sym_flags(parser: Parser<'_>) -> Result { + let mut flags = 0; + while !parser.is_empty() { + let mut l = parser.lookahead1(); + if l.peek::()? { + flags |= parser.parse::()?; + continue; + } + macro_rules! parse_flags { + ($($kw:tt = $val:expr,)*) => {$({ + custom_keyword!(flag = $kw); + if l.peek::()? { + parser.parse::()?; + flags |= $val; + continue; + } + })*}; + } + parse_flags! { + "binding-weak" = 1 << 0, + "binding-local" = 1 << 1, + "visibility-hidden" = 1 << 2, + "undefined" = 1 << 4, + "exported" = 1 << 5, + "explicit-name" = 1 << 6, + "no-strip" = 1 << 7, + } + return Err(l.error()); + } + Ok(flags) +} + +mod flag {} + +impl Dylink0Subsection<'_> { + /// Returns the byte id of this subsection used to identify it. + pub fn id(&self) -> u8 { + use Dylink0Subsection::*; + match self { + MemInfo { .. } => 1, + Needed(..) => 2, + ExportInfo(..) => 3, + ImportInfo(..) => 4, + } + } +} diff --git a/crates/wast/src/core/export.rs b/crates/wast/src/core/export.rs index 66354d0546..19765d36df 100644 --- a/crates/wast/src/core/export.rs +++ b/crates/wast/src/core/export.rs @@ -44,19 +44,19 @@ impl<'a> Parse<'a> for Export<'a> { impl<'a> Parse<'a> for ExportKind { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(ExportKind::Func) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(ExportKind::Table) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(ExportKind::Memory) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(ExportKind::Global) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(ExportKind::Tag) } else { @@ -66,12 +66,12 @@ impl<'a> Parse<'a> for ExportKind { } impl Peek for ExportKind { - fn peek(cursor: Cursor<'_>) -> bool { - kw::func::peek(cursor) - || kw::table::peek(cursor) - || kw::memory::peek(cursor) - || kw::global::peek(cursor) - || kw::tag::peek(cursor) + fn peek(cursor: Cursor<'_>) -> Result { + Ok(kw::func::peek(cursor)? + || kw::table::peek(cursor)? + || kw::memory::peek(cursor)? + || kw::global::peek(cursor)? + || kw::tag::peek(cursor)?) } fn display() -> &'static str { "export kind" @@ -113,7 +113,7 @@ pub struct InlineExport<'a> { impl<'a> Parse<'a> for InlineExport<'a> { fn parse(parser: Parser<'a>) -> Result { let mut names = Vec::new(); - while parser.peek::() { + while parser.peek::()? { names.push(parser.parens(|p| { p.parse::()?; p.parse::<&str>() @@ -124,20 +124,20 @@ impl<'a> Parse<'a> for InlineExport<'a> { } impl Peek for InlineExport<'_> { - fn peek(cursor: Cursor<'_>) -> bool { - let cursor = match cursor.lparen() { + fn peek(cursor: Cursor<'_>) -> Result { + let cursor = match cursor.lparen()? { Some(cursor) => cursor, - None => return false, + None => return Ok(false), }; - let cursor = match cursor.keyword() { + let cursor = match cursor.keyword()? { Some(("export", cursor)) => cursor, - _ => return false, + _ => return Ok(false), }; - let cursor = match cursor.string() { + let cursor = match cursor.string()? { Some((_, cursor)) => cursor, - None => return false, + None => return Ok(false), }; - cursor.rparen().is_some() + Ok(cursor.rparen()?.is_some()) } fn display() -> &'static str { diff --git a/crates/wast/src/core/expr.rs b/crates/wast/src/core/expr.rs index b149244869..58e8c4397b 100644 --- a/crates/wast/src/core/expr.rs +++ b/crates/wast/src/core/expr.rs @@ -26,6 +26,31 @@ impl<'a> Parse<'a> for Expression<'a> { } } +impl<'a> Expression<'a> { + /// Parse an expression formed from a single folded instruction. + /// + /// Attempts to parse an expression formed from a single folded instruction. + /// + /// This method will mutate the state of `parser` after attempting to parse + /// the expression. If an error happens then it is likely fatal and + /// there is no guarantee of how many tokens have been consumed from + /// `parser`. + /// + /// # Errors + /// + /// This function will return an error if the expression could not be + /// parsed. Note that creating an [`crate::Error`] is not exactly a cheap + /// operation, so [`crate::Error`] is typically fatal and propagated all the + /// way back to the top parse call site. + pub fn parse_folded_instruction(parser: Parser<'a>) -> Result { + let mut exprs = ExpressionParser::default(); + exprs.parse_folded_instruction(parser)?; + Ok(Expression { + instrs: exprs.instrs.into(), + }) + } +} + /// Helper struct used to parse an `Expression` with helper methods and such. /// /// The primary purpose of this is to avoid defining expression parsing as a @@ -73,18 +98,18 @@ enum Level<'a> { TryArm, } -/// Possible states of "what should be parsed next?" in an `if` expression. +/// Possible states of "what is currently being parsed?" in an `if` expression. enum If<'a> { - /// Only the `if` has been parsed, next thing to parse is the clause, if - /// any, of the `if` instruction. + /// Only the `if` instructoin has been parsed, next thing to parse is the + /// clause, if any, of the `if` instruction. + /// + /// This parse ends when `(then ...)` is encountered. Clause(Instruction<'a>), - /// Next thing to parse is the `then` block - Then(Instruction<'a>), - /// Next thing to parse is the `else` block + /// Currently parsing the `then` block, and afterwards a closing paren is + /// required or an `(else ...)` expression. + Then, + /// Parsing the `else` expression, nothing can come after. Else, - /// This `if` statement has finished parsing and if anything remains it's a - /// syntax error. - End, } /// Possible state of "what should be parsed next?" in a `try` expression. @@ -117,7 +142,7 @@ impl<'a> ExpressionParser<'a> { // of an `if block then we require that all sub-components are // s-expressions surrounded by `(` and `)`, so verify that here. if let Some(Level::If(_)) | Some(Level::Try(_)) = self.stack.last() { - if !parser.is_empty() && !parser.peek::() { + if !parser.is_empty() && !parser.peek::()? { return Err(parser.error("expected `(`")); } } @@ -191,9 +216,6 @@ impl<'a> ExpressionParser<'a> { // items in the `if` statement. Otherwise we're just careful // to terminate with an `end` instruction. Level::If(If::Clause(_)) => { - return Err(parser.error("previous `if` had no clause")); - } - Level::If(If::Then(_)) => { return Err(parser.error("previous `if` had no `then`")); } Level::If(_) => { @@ -217,13 +239,38 @@ impl<'a> ExpressionParser<'a> { Ok(()) } + fn parse_folded_instruction(&mut self, parser: Parser<'a>) -> Result<()> { + let mut done = false; + while !done { + match self.paren(parser)? { + Paren::Left => { + self.stack.push(Level::EndWith(parser.parse()?)); + } + Paren::Right => { + let top_instr = match self.stack.pop().unwrap() { + Level::EndWith(i) => i, + _ => panic!("unknown level type"), + }; + self.instrs.push(top_instr); + if self.stack.is_empty() { + done = true; + } + } + Paren::None => { + return Err(parser.error("expected to continue a folded instruction")) + } + } + } + Ok(()) + } + /// Parses either `(`, `)`, or nothing. fn paren(&self, parser: Parser<'a>) -> Result { parser.step(|cursor| { - Ok(match cursor.lparen() { + Ok(match cursor.lparen()? { Some(rest) => (Paren::Left, rest), None if self.stack.is_empty() => (Paren::None, cursor), - None => match cursor.rparen() { + None => match cursor.rparen()? { Some(rest) => (Paren::Right, rest), None => (Paren::None, cursor), }, @@ -231,23 +278,16 @@ impl<'a> ExpressionParser<'a> { }) } - /// Handles all parsing of an `if` statement. + /// State transitions with parsing an `if` statement. /// /// The syntactical form of an `if` stament looks like: /// /// ```wat - /// (if $clause (then $then) (else $else)) + /// (if ($clause)... (then $then) (else $else)) /// ``` /// - /// but it turns out we practically see a few things in the wild: - /// - /// * inside the `(if ...)` every sub-thing is surrounded by parens - /// * The `then` and `else` keywords are optional - /// * The `$then` and `$else` blocks don't need to be surrounded by parens - /// - /// That's all attempted to be handled here. The part about all sub-parts - /// being surrounded by `(` and `)` means that we hook into the `LParen` - /// parsing above to call this method there unconditionally. + /// THis method is called after a `(` is parsed within the `(if ...` block. + /// This determines what to do next. /// /// Returns `true` if the rest of the arm above should be skipped, or /// `false` if we should parse the next item as an instruction (because we @@ -259,53 +299,37 @@ impl<'a> ExpressionParser<'a> { _ => return Ok(false), }; - // The first thing parsed in an `if` statement is the clause. If the - // clause starts with `then`, however, then we know to skip the clause - // and fall through to below. - if let If::Clause(if_instr) = i { - let instr = mem::replace(if_instr, Instruction::End(None)); - *i = If::Then(instr); - if !parser.peek::() { - return Ok(false); - } - } - - // All `if` statements are required to have a `then`. This is either the - // second s-expr (with or without a leading `then`) or the first s-expr - // with a leading `then`. The optionality of `then` isn't strictly what - // the text spec says but it matches wabt for now. - // - // Note that when we see the `then`, that's when we actually add the - // original `if` instruction to the stream. - if let If::Then(if_instr) = i { - let instr = mem::replace(if_instr, Instruction::End(None)); - self.instrs.push(instr); - *i = If::Else; - if parser.parse::>()?.is_some() { + match i { + // If the clause is still being parsed then interpret this `(` as a + // folded instruction unless it starts with `then`, in which case + // this transitions to the `Then` state and a new level has been + // reached. + If::Clause(if_instr) => { + if !parser.peek::()? { + return Ok(false); + } + parser.parse::()?; + let instr = mem::replace(if_instr, Instruction::End(None)); + self.instrs.push(instr); + *i = If::Then; self.stack.push(Level::IfArm); - return Ok(true); + Ok(true) } - return Ok(false); - } - // effectively the same as the `then` parsing above - if let If::Else = i { - self.instrs.push(Instruction::Else(None)); - if parser.parse::>()?.is_some() { - if parser.is_empty() { - self.instrs.pop(); - } + // Previously we were parsing the `(then ...)` clause so this next + // `(` must be followed by `else`. + If::Then => { + parser.parse::()?; + self.instrs.push(Instruction::Else(None)); + *i = If::Else; self.stack.push(Level::IfArm); - return Ok(true); + Ok(true) } - *i = If::End; - return Ok(false); - } - // If we made it this far then we're at `If::End` which means that there - // were too many s-expressions inside the `(if)` and we don't want to - // parse anything else. - Err(parser.error("unexpected token: too many payloads inside of `(if)`")) + // If after a `(else ...` clause is parsed there's another `(` then + // that's not syntactically allowed. + If::Else => Err(parser.error("unexpected token: too many payloads inside of `(if)`")), + } } /// Handles parsing of a `try` statement. A `try` statement is simpler @@ -426,7 +450,7 @@ macro_rules! instructions { } )* let parse_remainder = parser.step(|c| { - let (kw, rest) = match c.keyword() { + let (kw, rest) = match c.keyword() ?{ Some(pair) => pair, None => return Err(c.error("expected an instruction")), }; @@ -502,10 +526,10 @@ macro_rules! instructions { instructions! { pub enum Instruction<'a> { - Block(BlockType<'a>) : [0x02] : "block", - If(BlockType<'a>) : [0x04] : "if", + Block(Box>) : [0x02] : "block", + If(Box>) : [0x04] : "if", Else(Option>) : [0x05] : "else", - Loop(BlockType<'a>) : [0x03] : "loop", + Loop(Box>) : [0x03] : "loop", End(Option>) : [0x0b] : "end", Unreachable : [0x00] : "unreachable", @@ -515,25 +539,25 @@ instructions! { BrTable(BrTableIndices<'a>) : [0x0e] : "br_table", Return : [0x0f] : "return", Call(Index<'a>) : [0x10] : "call", - CallIndirect(CallIndirect<'a>) : [0x11] : "call_indirect", + CallIndirect(Box>) : [0x11] : "call_indirect", // tail-call proposal ReturnCall(Index<'a>) : [0x12] : "return_call", - ReturnCallIndirect(CallIndirect<'a>) : [0x13] : "return_call_indirect", + ReturnCallIndirect(Box>) : [0x13] : "return_call_indirect", // function-references proposal - CallRef(HeapType<'a>) : [0x14] : "call_ref", - ReturnCallRef(HeapType<'a>) : [0x15] : "return_call_ref", + CallRef(Index<'a>) : [0x14] : "call_ref", + ReturnCallRef(Index<'a>) : [0x15] : "return_call_ref", FuncBind(FuncBindType<'a>) : [0x16] : "func.bind", Let(LetType<'a>) : [0x17] : "let", Drop : [0x1a] : "drop", Select(SelectTypes<'a>) : [] : "select", - LocalGet(Index<'a>) : [0x20] : "local.get" | "get_local", - LocalSet(Index<'a>) : [0x21] : "local.set" | "set_local", - LocalTee(Index<'a>) : [0x22] : "local.tee" | "tee_local", - GlobalGet(Index<'a>) : [0x23] : "global.get" | "get_global", - GlobalSet(Index<'a>) : [0x24] : "global.set" | "set_global", + LocalGet(Index<'a>) : [0x20] : "local.get", + LocalSet(Index<'a>) : [0x21] : "local.set", + LocalTee(Index<'a>) : [0x22] : "local.tee", + GlobalGet(Index<'a>) : [0x23] : "global.get", + GlobalSet(Index<'a>) : [0x24] : "global.set", TableGet(TableArg<'a>) : [0x25] : "table.get", TableSet(TableArg<'a>) : [0x26] : "table.set", @@ -563,11 +587,12 @@ instructions! { I64Store32(MemArg<4>) : [0x3e] : "i64.store32", // Lots of bulk memory proposal here as well - MemorySize(MemoryArg<'a>) : [0x3f] : "memory.size" | "current_memory", - MemoryGrow(MemoryArg<'a>) : [0x40] : "memory.grow" | "grow_memory", + MemorySize(MemoryArg<'a>) : [0x3f] : "memory.size", + MemoryGrow(MemoryArg<'a>) : [0x40] : "memory.grow", MemoryInit(MemoryInit<'a>) : [0xfc, 0x08] : "memory.init", MemoryCopy(MemoryCopy<'a>) : [0xfc, 0x0a] : "memory.copy", MemoryFill(MemoryArg<'a>) : [0xfc, 0x0b] : "memory.fill", + MemoryDiscard(MemoryArg<'a>) : [0xfc, 0x12] : "memory.discard", DataDrop(Index<'a>) : [0xfc, 0x09] : "data.drop", ElemDrop(Index<'a>) : [0xfc, 0x0d] : "elem.drop", TableInit(TableInit<'a>) : [0xfc, 0x0c] : "table.init", @@ -581,65 +606,51 @@ instructions! { RefFunc(Index<'a>) : [0xd2] : "ref.func", // function-references proposal - RefAsNonNull : [0xd3] : "ref.as_non_null", - BrOnNull(Index<'a>) : [0xd4] : "br_on_null", + RefAsNonNull : [0xd4] : "ref.as_non_null", + BrOnNull(Index<'a>) : [0xd5] : "br_on_null", BrOnNonNull(Index<'a>) : [0xd6] : "br_on_non_null", // gc proposal: eqref - RefEq : [0xd5] : "ref.eq", + RefEq : [0xd3] : "ref.eq", // gc proposal: struct - StructNew(Index<'a>) : [0xfb, 0x07] : "struct.new", - StructNewDefault(Index<'a>) : [0xfb, 0x08] : "struct.new_default", - StructGet(StructAccess<'a>) : [0xfb, 0x03] : "struct.get", - StructGetS(StructAccess<'a>) : [0xfb, 0x04] : "struct.get_s", - StructGetU(StructAccess<'a>) : [0xfb, 0x05] : "struct.get_u", - StructSet(StructAccess<'a>) : [0xfb, 0x06] : "struct.set", + StructNew(Index<'a>) : [0xfb, 0x00] : "struct.new", + StructNewDefault(Index<'a>) : [0xfb, 0x01] : "struct.new_default", + StructGet(StructAccess<'a>) : [0xfb, 0x02] : "struct.get", + StructGetS(StructAccess<'a>) : [0xfb, 0x03] : "struct.get_s", + StructGetU(StructAccess<'a>) : [0xfb, 0x04] : "struct.get_u", + StructSet(StructAccess<'a>) : [0xfb, 0x05] : "struct.set", // gc proposal: array - ArrayNew(Index<'a>) : [0xfb, 0x1b] : "array.new", - ArrayNewDefault(Index<'a>) : [0xfb, 0x1c] : "array.new_default", - ArrayNewFixed(ArrayNewFixed<'a>) : [0xfb, 0x1a] : "array.new_fixed", - ArrayNewData(ArrayNewData<'a>) : [0xfb, 0x1d] : "array.new_data", - ArrayNewElem(ArrayNewElem<'a>) : [0xfb, 0x10] : "array.new_elem", - ArrayGet(Index<'a>) : [0xfb, 0x13] : "array.get", - ArrayGetS(Index<'a>) : [0xfb, 0x14] : "array.get_s", - ArrayGetU(Index<'a>) : [0xfb, 0x15] : "array.get_u", - ArraySet(Index<'a>) : [0xfb, 0x16] : "array.set", - ArrayLen(Index<'a>) : [0xfb, 0x17] : "array.len", - ArrayCopy(ArrayCopy<'a>) : [0xfb, 0x18] : "array.copy", + ArrayNew(Index<'a>) : [0xfb, 0x06] : "array.new", + ArrayNewDefault(Index<'a>) : [0xfb, 0x07] : "array.new_default", + ArrayNewFixed(ArrayNewFixed<'a>) : [0xfb, 0x08] : "array.new_fixed", + ArrayNewData(ArrayNewData<'a>) : [0xfb, 0x09] : "array.new_data", + ArrayNewElem(ArrayNewElem<'a>) : [0xfb, 0x0a] : "array.new_elem", + ArrayGet(Index<'a>) : [0xfb, 0x0b] : "array.get", + ArrayGetS(Index<'a>) : [0xfb, 0x0c] : "array.get_s", + ArrayGetU(Index<'a>) : [0xfb, 0x0d] : "array.get_u", + ArraySet(Index<'a>) : [0xfb, 0x0e] : "array.set", + ArrayLen : [0xfb, 0x0f] : "array.len", + ArrayFill(ArrayFill<'a>) : [0xfb, 0x10] : "array.fill", + ArrayCopy(ArrayCopy<'a>) : [0xfb, 0x11] : "array.copy", + ArrayInitData(ArrayInit<'a>) : [0xfb, 0x12] : "array.init_data", + ArrayInitElem(ArrayInit<'a>) : [0xfb, 0x13] : "array.init_elem", // gc proposal, i31 - I31New : [0xfb, 0x20] : "i31.new", - I31GetS : [0xfb, 0x21] : "i31.get_s", - I31GetU : [0xfb, 0x22] : "i31.get_u", + RefI31 : [0xfb, 0x1c] : "ref.i31", + I31GetS : [0xfb, 0x1d] : "i31.get_s", + I31GetU : [0xfb, 0x1e] : "i31.get_u", // gc proposal, concrete casting - RefTest(Index<'a>) : [0xfb, 0x44] : "ref.test", - RefCast(Index<'a>) : [0xfb, 0x45] : "ref.cast", - BrOnCast(BrOnCast<'a>) : [0xfb, 0x46] : "br_on_cast", - BrOnCastFail(BrOnCast<'a>) : [0xfb, 0x47] : "br_on_cast_fail", - - // gc proposal, heap casting - RefIsFunc : [0xfb, 0x50] : "ref.is_func", - RefIsData : [0xfb, 0x51] : "ref.is_data", - RefIsI31 : [0xfb, 0x52] : "ref.is_i31", - RefIsArray : [0xfb, 0x53] : "ref.is_array", - - RefAsFunc : [0xfb, 0x58] : "ref.as_func", - RefAsData : [0xfb, 0x59] : "ref.as_data", - RefAsI31 : [0xfb, 0x5a] : "ref.as_i31", - RefAsArray : [0xfb, 0x5b] : "ref.as_array", - - BrOnFunc(Index<'a>) : [0xfb, 0x60] : "br_on_func", - BrOnData(Index<'a>) : [0xfb, 0x61] : "br_on_data", - BrOnI31(Index<'a>) : [0xfb, 0x62] : "br_on_i31", - BrOnArray(Index<'a>) : [0xfb, 0x66] : "br_on_array", - - BrOnNonFunc(Index<'a>) : [0xfb, 0x63] : "br_on_non_func", - BrOnNonData(Index<'a>) : [0xfb, 0x64] : "br_on_non_data", - BrOnNonI31(Index<'a>) : [0xfb, 0x65] : "br_on_non_i31", - BrOnNonArray(Index<'a>) : [0xfb, 0x67] : "br_on_non_array", + RefTest(RefTest<'a>) : [] : "ref.test", + RefCast(RefCast<'a>) : [] : "ref.cast", + BrOnCast(Box>) : [] : "br_on_cast", + BrOnCastFail(Box>) : [] : "br_on_cast_fail", + + // gc proposal extern/any coercion operations + ExternInternalize : [0xfb, 0x1a] : "extern.internalize", + ExternExternalize : [0xfb, 0x1b] : "extern.externalize", I32Const(i32) : [0x41] : "i32.const", I64Const(i64) : [0x42] : "i64.const", @@ -752,41 +763,41 @@ instructions! { F64Le : [0x65] : "f64.le", F64Ge : [0x66] : "f64.ge", - I32WrapI64 : [0xa7] : "i32.wrap_i64" | "i32.wrap/i64", - I32TruncF32S : [0xa8] : "i32.trunc_f32_s" | "i32.trunc_s/f32", - I32TruncF32U : [0xa9] : "i32.trunc_f32_u" | "i32.trunc_u/f32", - I32TruncF64S : [0xaa] : "i32.trunc_f64_s" | "i32.trunc_s/f64", - I32TruncF64U : [0xab] : "i32.trunc_f64_u" | "i32.trunc_u/f64", - I64ExtendI32S : [0xac] : "i64.extend_i32_s" | "i64.extend_s/i32", - I64ExtendI32U : [0xad] : "i64.extend_i32_u" | "i64.extend_u/i32", - I64TruncF32S : [0xae] : "i64.trunc_f32_s" | "i64.trunc_s/f32", - I64TruncF32U : [0xaf] : "i64.trunc_f32_u" | "i64.trunc_u/f32", - I64TruncF64S : [0xb0] : "i64.trunc_f64_s" | "i64.trunc_s/f64", - I64TruncF64U : [0xb1] : "i64.trunc_f64_u" | "i64.trunc_u/f64", - F32ConvertI32S : [0xb2] : "f32.convert_i32_s" | "f32.convert_s/i32", - F32ConvertI32U : [0xb3] : "f32.convert_i32_u" | "f32.convert_u/i32", - F32ConvertI64S : [0xb4] : "f32.convert_i64_s" | "f32.convert_s/i64", - F32ConvertI64U : [0xb5] : "f32.convert_i64_u" | "f32.convert_u/i64", - F32DemoteF64 : [0xb6] : "f32.demote_f64" | "f32.demote/f64", - F64ConvertI32S : [0xb7] : "f64.convert_i32_s" | "f64.convert_s/i32", - F64ConvertI32U : [0xb8] : "f64.convert_i32_u" | "f64.convert_u/i32", - F64ConvertI64S : [0xb9] : "f64.convert_i64_s" | "f64.convert_s/i64", - F64ConvertI64U : [0xba] : "f64.convert_i64_u" | "f64.convert_u/i64", - F64PromoteF32 : [0xbb] : "f64.promote_f32" | "f64.promote/f32", - I32ReinterpretF32 : [0xbc] : "i32.reinterpret_f32" | "i32.reinterpret/f32", - I64ReinterpretF64 : [0xbd] : "i64.reinterpret_f64" | "i64.reinterpret/f64", - F32ReinterpretI32 : [0xbe] : "f32.reinterpret_i32" | "f32.reinterpret/i32", - F64ReinterpretI64 : [0xbf] : "f64.reinterpret_i64" | "f64.reinterpret/i64", + I32WrapI64 : [0xa7] : "i32.wrap_i64", + I32TruncF32S : [0xa8] : "i32.trunc_f32_s", + I32TruncF32U : [0xa9] : "i32.trunc_f32_u", + I32TruncF64S : [0xaa] : "i32.trunc_f64_s", + I32TruncF64U : [0xab] : "i32.trunc_f64_u", + I64ExtendI32S : [0xac] : "i64.extend_i32_s", + I64ExtendI32U : [0xad] : "i64.extend_i32_u", + I64TruncF32S : [0xae] : "i64.trunc_f32_s", + I64TruncF32U : [0xaf] : "i64.trunc_f32_u", + I64TruncF64S : [0xb0] : "i64.trunc_f64_s", + I64TruncF64U : [0xb1] : "i64.trunc_f64_u", + F32ConvertI32S : [0xb2] : "f32.convert_i32_s", + F32ConvertI32U : [0xb3] : "f32.convert_i32_u", + F32ConvertI64S : [0xb4] : "f32.convert_i64_s", + F32ConvertI64U : [0xb5] : "f32.convert_i64_u", + F32DemoteF64 : [0xb6] : "f32.demote_f64", + F64ConvertI32S : [0xb7] : "f64.convert_i32_s", + F64ConvertI32U : [0xb8] : "f64.convert_i32_u", + F64ConvertI64S : [0xb9] : "f64.convert_i64_s", + F64ConvertI64U : [0xba] : "f64.convert_i64_u", + F64PromoteF32 : [0xbb] : "f64.promote_f32", + I32ReinterpretF32 : [0xbc] : "i32.reinterpret_f32", + I64ReinterpretF64 : [0xbd] : "i64.reinterpret_f64", + F32ReinterpretI32 : [0xbe] : "f32.reinterpret_i32", + F64ReinterpretI64 : [0xbf] : "f64.reinterpret_i64", // non-trapping float to int - I32TruncSatF32S : [0xfc, 0x00] : "i32.trunc_sat_f32_s" | "i32.trunc_s:sat/f32", - I32TruncSatF32U : [0xfc, 0x01] : "i32.trunc_sat_f32_u" | "i32.trunc_u:sat/f32", - I32TruncSatF64S : [0xfc, 0x02] : "i32.trunc_sat_f64_s" | "i32.trunc_s:sat/f64", - I32TruncSatF64U : [0xfc, 0x03] : "i32.trunc_sat_f64_u" | "i32.trunc_u:sat/f64", - I64TruncSatF32S : [0xfc, 0x04] : "i64.trunc_sat_f32_s" | "i64.trunc_s:sat/f32", - I64TruncSatF32U : [0xfc, 0x05] : "i64.trunc_sat_f32_u" | "i64.trunc_u:sat/f32", - I64TruncSatF64S : [0xfc, 0x06] : "i64.trunc_sat_f64_s" | "i64.trunc_s:sat/f64", - I64TruncSatF64U : [0xfc, 0x07] : "i64.trunc_sat_f64_u" | "i64.trunc_u:sat/f64", + I32TruncSatF32S : [0xfc, 0x00] : "i32.trunc_sat_f32_s", + I32TruncSatF32U : [0xfc, 0x01] : "i32.trunc_sat_f32_u", + I32TruncSatF64S : [0xfc, 0x02] : "i32.trunc_sat_f64_s", + I32TruncSatF64U : [0xfc, 0x03] : "i32.trunc_sat_f64_u", + I64TruncSatF32S : [0xfc, 0x04] : "i64.trunc_sat_f32_s", + I64TruncSatF32U : [0xfc, 0x05] : "i64.trunc_sat_f32_u", + I64TruncSatF64S : [0xfc, 0x06] : "i64.trunc_sat_f64_s", + I64TruncSatF64U : [0xfc, 0x07] : "i64.trunc_sat_f64_u", // sign extension proposal I32Extend8S : [0xc0] : "i32.extend8_s", @@ -796,9 +807,9 @@ instructions! { I64Extend32S : [0xc4] : "i64.extend32_s", // atomics proposal - MemoryAtomicNotify(MemArg<4>) : [0xfe, 0x00] : "memory.atomic.notify" | "atomic.notify", - MemoryAtomicWait32(MemArg<4>) : [0xfe, 0x01] : "memory.atomic.wait32" | "i32.atomic.wait", - MemoryAtomicWait64(MemArg<8>) : [0xfe, 0x02] : "memory.atomic.wait64" | "i64.atomic.wait", + MemoryAtomicNotify(MemArg<4>) : [0xfe, 0x00] : "memory.atomic.notify", + MemoryAtomicWait32(MemArg<4>) : [0xfe, 0x01] : "memory.atomic.wait32", + MemoryAtomicWait64(MemArg<8>) : [0xfe, 0x02] : "memory.atomic.wait64", AtomicFence : [0xfe, 0x03, 0x00] : "atomic.fence", I32AtomicLoad(MemArg<4>) : [0xfe, 0x10] : "i32.atomic.load", @@ -1131,40 +1142,58 @@ instructions! { F64x2PromoteLowF32x4 : [0xfd, 95] : "f64x2.promote_low_f32x4", // Exception handling proposal - Try(BlockType<'a>) : [0x06] : "try", + Try(Box>) : [0x06] : "try", Catch(Index<'a>) : [0x07] : "catch", Throw(Index<'a>) : [0x08] : "throw", Rethrow(Index<'a>) : [0x09] : "rethrow", Delegate(Index<'a>) : [0x18] : "delegate", CatchAll : [0x19] : "catch_all", + // Exception handling proposal extension for 'exnref' + ThrowRef : [0x0a] : "throw_ref", + TryTable(TryTable<'a>) : [0x1f] : "try_table", + // Relaxed SIMD proposal - I8x16RelaxedSwizzle : [0xfd, 0xa2]: "i8x16.relaxed_swizzle", - I32x4RelaxedTruncF32x4S : [0xfd, 0xa5]: "i32x4.relaxed_trunc_f32x4_s", - I32x4RelaxedTruncF32x4U : [0xfd, 0xa6]: "i32x4.relaxed_trunc_f32x4_u", - I32x4RelaxedTruncF64x2SZero : [0xfd, 0xc5]: "i32x4.relaxed_trunc_f64x2_s_zero", - I32x4RelaxedTruncF64x2UZero : [0xfd, 0xc6]: "i32x4.relaxed_trunc_f64x2_u_zero", - F32x4Fma : [0xfd, 0xaf]: "f32x4.fma", - F32x4Fms : [0xfd, 0xb0]: "f32x4.fms", - F64x4Fma : [0xfd, 0xcf]: "f64x2.fma", - F64x4Fms : [0xfd, 0xd0]: "f64x2.fms", - I8x16LaneSelect : [0xfd, 0xb2]: "i8x16.laneselect", - I16x8LaneSelect : [0xfd, 0xb3]: "i16x8.laneselect", - I32x4LaneSelect : [0xfd, 0xd2]: "i32x4.laneselect", - I64x2LaneSelect : [0xfd, 0xd3]: "i64x2.laneselect", - F32x4RelaxedMin : [0xfd, 0xb4]: "f32x4.relaxed_min", - F32x4RelaxedMax : [0xfd, 0xe2]: "f32x4.relaxed_max", - F64x2RelaxedMin : [0xfd, 0xd4]: "f64x2.relaxed_min", - F64x2RelaxedMax : [0xfd, 0xee]: "f64x2.relaxed_max", + I8x16RelaxedSwizzle : [0xfd, 0x100]: "i8x16.relaxed_swizzle", + I32x4RelaxedTruncF32x4S : [0xfd, 0x101]: "i32x4.relaxed_trunc_f32x4_s", + I32x4RelaxedTruncF32x4U : [0xfd, 0x102]: "i32x4.relaxed_trunc_f32x4_u", + I32x4RelaxedTruncF64x2SZero : [0xfd, 0x103]: "i32x4.relaxed_trunc_f64x2_s_zero", + I32x4RelaxedTruncF64x2UZero : [0xfd, 0x104]: "i32x4.relaxed_trunc_f64x2_u_zero", + F32x4RelaxedMadd : [0xfd, 0x105]: "f32x4.relaxed_madd", + F32x4RelaxedNmadd : [0xfd, 0x106]: "f32x4.relaxed_nmadd", + F64x2RelaxedMadd : [0xfd, 0x107]: "f64x2.relaxed_madd", + F64x2RelaxedNmadd : [0xfd, 0x108]: "f64x2.relaxed_nmadd", + I8x16RelaxedLaneselect : [0xfd, 0x109]: "i8x16.relaxed_laneselect", + I16x8RelaxedLaneselect : [0xfd, 0x10A]: "i16x8.relaxed_laneselect", + I32x4RelaxedLaneselect : [0xfd, 0x10B]: "i32x4.relaxed_laneselect", + I64x2RelaxedLaneselect : [0xfd, 0x10C]: "i64x2.relaxed_laneselect", + F32x4RelaxedMin : [0xfd, 0x10D]: "f32x4.relaxed_min", + F32x4RelaxedMax : [0xfd, 0x10E]: "f32x4.relaxed_max", + F64x2RelaxedMin : [0xfd, 0x10F]: "f64x2.relaxed_min", + F64x2RelaxedMax : [0xfd, 0x110]: "f64x2.relaxed_max", + I16x8RelaxedQ15mulrS: [0xfd, 0x111]: "i16x8.relaxed_q15mulr_s", + I16x8RelaxedDotI8x16I7x16S: [0xfd, 0x112]: "i16x8.relaxed_dot_i8x16_i7x16_s", + I32x4RelaxedDotI8x16I7x16AddS: [0xfd, 0x113]: "i32x4.relaxed_dot_i8x16_i7x16_add_s", } } +// As shown in #1095 the size of this variant is somewhat performance-sensitive +// since big `*.wat` files will have a lot of these. This is a small ratchet to +// make sure that this enum doesn't become larger than it already is, although +// ideally it also wouldn't be as large as it is now. +const _: () = { + let size = std::mem::size_of::>(); + let pointer = std::mem::size_of::(); + assert!(size <= pointer * 10); +}; + impl<'a> Instruction<'a> { pub(crate) fn needs_data_count(&self) -> bool { match self { Instruction::MemoryInit(_) | Instruction::DataDrop(_) - | Instruction::ArrayNewData(_) => true, + | Instruction::ArrayNewData(_) + | Instruction::ArrayInitData(_) => true, _ => false, } } @@ -1194,6 +1223,85 @@ impl<'a> Parse<'a> for BlockType<'a> { } } +#[derive(Debug)] +#[allow(missing_docs)] +pub struct TryTable<'a> { + pub block: Box>, + pub catches: Vec>, + pub catch_all: Option>, +} + +impl<'a> Parse<'a> for TryTable<'a> { + fn parse(parser: Parser<'a>) -> Result { + let block = parser.parse()?; + + let mut catches = Vec::new(); + while parser.peek2::()? || parser.peek2::()? { + catches.push(parser.parens(|p| { + let kind = if parser.peek::()? { + p.parse::()?; + TryTableCatchKind::Ref + } else { + p.parse::()?; + TryTableCatchKind::Drop + }; + Ok(TryTableCatch { + kind, + tag: p.parse()?, + label: p.parse()?, + }) + })?); + } + + let mut catch_all = None; + if parser.peek2::()? || parser.peek2::()? { + catch_all = Some(parser.parens(|p| { + let kind = if parser.peek::()? { + p.parse::()?; + TryTableCatchKind::Ref + } else { + p.parse::()?; + TryTableCatchKind::Drop + }; + Ok(TryTableCatchAll { + kind, + label: p.parse()?, + }) + })?); + } + + Ok(TryTable { + block, + catches, + catch_all, + }) + } +} + +#[derive(Debug)] +#[allow(missing_docs)] +pub enum TryTableCatchKind { + // Capture the exnref for the try + Ref, + // Drop the exnref for the try + Drop, +} + +#[derive(Debug)] +#[allow(missing_docs)] +pub struct TryTableCatch<'a> { + pub kind: TryTableCatchKind, + pub tag: Index<'a>, + pub label: Index<'a>, +} + +#[derive(Debug)] +#[allow(missing_docs)] +pub struct TryTableCatchAll<'a> { + pub kind: TryTableCatchKind, + pub label: Index<'a>, +} + /// Extra information associated with the func.bind instruction. #[derive(Debug)] #[allow(missing_docs)] @@ -1215,15 +1323,15 @@ impl<'a> Parse<'a> for FuncBindType<'a> { #[derive(Debug)] #[allow(missing_docs)] pub struct LetType<'a> { - pub block: BlockType<'a>, - pub locals: Vec>, + pub block: Box>, + pub locals: Box<[Local<'a>]>, } impl<'a> Parse<'a> for LetType<'a> { fn parse(parser: Parser<'a>) -> Result { Ok(LetType { block: parser.parse()?, - locals: Local::parse_remainder(parser)?, + locals: Local::parse_remainder(parser)?.into(), }) } } @@ -1239,7 +1347,7 @@ pub struct BrTableIndices<'a> { impl<'a> Parse<'a> for BrTableIndices<'a> { fn parse(parser: Parser<'a>) -> Result { let mut labels = vec![parser.parse()?]; - while parser.peek::() { + while parser.peek::()? { labels.push(parser.parse()?); } let default = labels.pop().unwrap(); @@ -1257,7 +1365,7 @@ pub struct LaneArg { impl<'a> Parse<'a> for LaneArg { fn parse(parser: Parser<'a>) -> Result { let lane = parser.step(|c| { - if let Some((i, rest)) = c.integer() { + if let Some((i, rest)) = c.integer()? { if i.sign() == None { let (src, radix) = i.val(); let val = u8::from_str_radix(src, radix) @@ -1297,7 +1405,7 @@ impl<'a> MemArg<'a> { f: impl FnOnce(Cursor<'_>, &str, u32) -> Result, ) -> Result> { parser.step(|c| { - let (kw, rest) = match c.keyword() { + let (kw, rest) = match c.keyword()? { Some(p) => p, None => return Ok((None, c)), }; @@ -1364,17 +1472,17 @@ impl<'a> LoadOrStoreLane<'a> { // This is sort of funky. The first integer we see could be the lane // index, but it could also be the memory index. To determine what it is // then if we see a second integer we need to look further. - let has_memarg = parser.step(|c| match c.integer() { + let has_memarg = parser.step(|c| match c.integer()? { Some((_, after_int)) => { // Two integers in a row? That means that the first one is the // memory index and the second must be the lane index. - if after_int.integer().is_some() { + if after_int.integer()?.is_some() { return Ok((true, c)); } // If the first integer is trailed by `offset=...` or // `align=...` then this is definitely a memarg. - if let Some((kw, _)) = after_int.keyword() { + if let Some((kw, _)) = after_int.keyword()? { if kw.starts_with("offset=") || kw.starts_with("align=") { return Ok((true, c)); } @@ -1437,7 +1545,7 @@ pub struct TableInit<'a> { impl<'a> Parse<'a> for TableInit<'a> { fn parse(parser: Parser<'a>) -> Result { let prev_span = parser.prev_span(); - let (elem, table) = if parser.peek2::() { + let (elem, table) = if parser.peek2::()? { let table = parser.parse()?; (parser.parse()?, table) } else { @@ -1517,7 +1625,7 @@ pub struct MemoryInit<'a> { impl<'a> Parse<'a> for MemoryInit<'a> { fn parse(parser: Parser<'a>) -> Result { let prev_span = parser.prev_span(); - let (data, mem) = if parser.peek2::() { + let (data, mem) = if parser.peek2::()? { let memory = parser.parse()?; (parser.parse()?, memory) } else { @@ -1567,6 +1675,21 @@ impl<'a> Parse<'a> for StructAccess<'a> { } } +/// Extra data associated with the `array.fill` instruction +#[derive(Debug)] +pub struct ArrayFill<'a> { + /// The index of the array type we're filling. + pub array: Index<'a>, +} + +impl<'a> Parse<'a> for ArrayFill<'a> { + fn parse(parser: Parser<'a>) -> Result { + Ok(ArrayFill { + array: parser.parse()?, + }) + } +} + /// Extra data associated with the `array.copy` instruction #[derive(Debug)] pub struct ArrayCopy<'a> { @@ -1585,6 +1708,24 @@ impl<'a> Parse<'a> for ArrayCopy<'a> { } } +/// Extra data associated with the `array.init_[data/elem]` instruction +#[derive(Debug)] +pub struct ArrayInit<'a> { + /// The index of the array type we're initializing. + pub array: Index<'a>, + /// The index of the data or elem segment we're reading from. + pub segment: Index<'a>, +} + +impl<'a> Parse<'a> for ArrayInit<'a> { + fn parse(parser: Parser<'a>) -> Result { + Ok(ArrayInit { + array: parser.parse()?, + segment: parser.parse()?, + }) + } +} + /// Extra data associated with the `array.new_fixed` instruction #[derive(Debug)] pub struct ArrayNewFixed<'a> { @@ -1639,20 +1780,74 @@ impl<'a> Parse<'a> for ArrayNewElem<'a> { } } +/// Extra data associated with the `ref.cast` instruction +#[derive(Debug)] +pub struct RefCast<'a> { + /// The type to cast to. + pub r#type: RefType<'a>, +} + +impl<'a> Parse<'a> for RefCast<'a> { + fn parse(parser: Parser<'a>) -> Result { + Ok(RefCast { + r#type: parser.parse()?, + }) + } +} + +/// Extra data associated with the `ref.test` instruction +#[derive(Debug)] +pub struct RefTest<'a> { + /// The type to test for. + pub r#type: RefType<'a>, +} + +impl<'a> Parse<'a> for RefTest<'a> { + fn parse(parser: Parser<'a>) -> Result { + Ok(RefTest { + r#type: parser.parse()?, + }) + } +} + /// Extra data associated with the `br_on_cast` instruction #[derive(Debug)] pub struct BrOnCast<'a> { /// The label to branch to. pub label: Index<'a>, - /// The index of the type we're casting. - pub r#type: Index<'a>, + /// The type we're casting from. + pub from_type: RefType<'a>, + /// The type we're casting to. + pub to_type: RefType<'a>, } impl<'a> Parse<'a> for BrOnCast<'a> { fn parse(parser: Parser<'a>) -> Result { Ok(BrOnCast { label: parser.parse()?, - r#type: parser.parse()?, + from_type: parser.parse()?, + to_type: parser.parse()?, + }) + } +} + +/// Extra data associated with the `br_on_cast_fail` instruction +#[derive(Debug)] +pub struct BrOnCastFail<'a> { + /// The label to branch to. + pub label: Index<'a>, + /// The type we're casting from. + pub from_type: RefType<'a>, + /// The type we're casting to. + pub to_type: RefType<'a>, +} + +impl<'a> Parse<'a> for BrOnCastFail<'a> { + fn parse(parser: Parser<'a>) -> Result { + Ok(BrOnCastFail { + label: parser.parse()?, + from_type: parser.parse()?, + to_type: parser.parse()?, }) } } @@ -1763,7 +1958,7 @@ impl V128Const { impl<'a> Parse<'a> for V128Const { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(V128Const::I8x16([ parser.parse()?, @@ -1783,7 +1978,7 @@ impl<'a> Parse<'a> for V128Const { parser.parse()?, parser.parse()?, ])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Const::I16x8([ parser.parse()?, @@ -1795,7 +1990,7 @@ impl<'a> Parse<'a> for V128Const { parser.parse()?, parser.parse()?, ])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Const::I32x4([ parser.parse()?, @@ -1803,10 +1998,10 @@ impl<'a> Parse<'a> for V128Const { parser.parse()?, parser.parse()?, ])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Const::I64x2([parser.parse()?, parser.parse()?])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Const::F32x4([ parser.parse()?, @@ -1814,7 +2009,7 @@ impl<'a> Parse<'a> for V128Const { parser.parse()?, parser.parse()?, ])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Const::F64x2([parser.parse()?, parser.parse()?])) } else { @@ -1864,9 +2059,10 @@ pub struct SelectTypes<'a> { impl<'a> Parse<'a> for SelectTypes<'a> { fn parse(parser: Parser<'a>) -> Result { - let mut tys = None; - while parser.peek2::() { - let mut list = Vec::new(); + let mut found = false; + let mut list = Vec::new(); + while parser.peek2::()? { + found = true; parser.parens(|p| { p.parse::()?; while !p.is_empty() { @@ -1874,8 +2070,9 @@ impl<'a> Parse<'a> for SelectTypes<'a> { } Ok(()) })?; - tys = Some(list); } - Ok(SelectTypes { tys }) + Ok(SelectTypes { + tys: if found { Some(list) } else { None }, + }) } } diff --git a/crates/wast/src/core/func.rs b/crates/wast/src/core/func.rs index 84abdf8578..24cc2993ca 100644 --- a/crates/wast/src/core/func.rs +++ b/crates/wast/src/core/func.rs @@ -38,7 +38,7 @@ pub enum FuncKind<'a> { /// Almost all functions, those defined inline in a wasm module. Inline { /// The list of locals, if any, for this function. - locals: Vec>, + locals: Box<[Local<'a>]>, /// The instructions of the function. expression: Expression<'a>, @@ -56,7 +56,7 @@ impl<'a> Parse<'a> for Func<'a> { (parser.parse()?, FuncKind::Import(import)) } else { let ty = parser.parse()?; - let locals = Local::parse_remainder(parser)?; + let locals = Local::parse_remainder(parser)?.into(); ( ty, FuncKind::Inline { @@ -92,27 +92,42 @@ pub struct Local<'a> { pub ty: ValType<'a>, } +/// Parser for `local` instruction. +/// +/// A single `local` instruction can generate multiple locals, hence this parser +pub struct LocalParser<'a> { + /// All the locals associated with this `local` instruction. + pub locals: Vec>, +} + +impl<'a> Parse<'a> for LocalParser<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut locals = Vec::new(); + parser.parse::()?; + if !parser.is_empty() { + let id: Option<_> = parser.parse()?; + let name: Option<_> = parser.parse()?; + let ty = parser.parse()?; + let parse_more = id.is_none() && name.is_none(); + locals.push(Local { id, name, ty }); + while parse_more && !parser.is_empty() { + locals.push(Local { + id: None, + name: None, + ty: parser.parse()?, + }); + } + } + Ok(LocalParser { locals }) + } +} + impl<'a> Local<'a> { pub(crate) fn parse_remainder(parser: Parser<'a>) -> Result>> { let mut locals = Vec::new(); - while parser.peek2::() { + while parser.peek2::()? { parser.parens(|p| { - p.parse::()?; - if p.is_empty() { - return Ok(()); - } - let id: Option<_> = p.parse()?; - let name: Option<_> = p.parse()?; - let ty = p.parse()?; - let parse_more = id.is_none() && name.is_none(); - locals.push(Local { id, name, ty }); - while parse_more && !p.is_empty() { - locals.push(Local { - id: None, - name: None, - ty: p.parse()?, - }); - } + locals.extend(p.parse::()?.locals); Ok(()) })?; } diff --git a/crates/wast/src/core/import.rs b/crates/wast/src/core/import.rs index e44057f72f..e7c49bb862 100644 --- a/crates/wast/src/core/import.rs +++ b/crates/wast/src/core/import.rs @@ -59,7 +59,7 @@ pub enum ItemKind<'a> { impl<'a> Parse<'a> for ItemSig<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { let span = parser.parse::()?.0; Ok(ItemSig { span, @@ -67,7 +67,7 @@ impl<'a> Parse<'a> for ItemSig<'a> { name: parser.parse()?, kind: ItemKind::Func(parser.parse()?), }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(ItemSig { span, @@ -75,7 +75,7 @@ impl<'a> Parse<'a> for ItemSig<'a> { name: None, kind: ItemKind::Table(parser.parse()?), }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(ItemSig { span, @@ -83,7 +83,7 @@ impl<'a> Parse<'a> for ItemSig<'a> { name: None, kind: ItemKind::Memory(parser.parse()?), }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(ItemSig { span, @@ -91,7 +91,7 @@ impl<'a> Parse<'a> for ItemSig<'a> { name: None, kind: ItemKind::Global(parser.parse()?), }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(ItemSig { span, @@ -131,25 +131,25 @@ impl<'a> Parse<'a> for InlineImport<'a> { } impl Peek for InlineImport<'_> { - fn peek(cursor: Cursor<'_>) -> bool { - let cursor = match cursor.lparen() { + fn peek(cursor: Cursor<'_>) -> Result { + let cursor = match cursor.lparen()? { Some(cursor) => cursor, - None => return false, + None => return Ok(false), }; - let cursor = match cursor.keyword() { + let cursor = match cursor.keyword()? { Some(("import", cursor)) => cursor, - _ => return false, + _ => return Ok(false), }; - let cursor = match cursor.string() { + let cursor = match cursor.string()? { Some((_, cursor)) => cursor, - None => return false, + None => return Ok(false), }; - let cursor = match cursor.string() { + let cursor = match cursor.string()? { Some((_, cursor)) => cursor, - None => return false, + None => return Ok(false), }; - cursor.rparen().is_some() + Ok(cursor.rparen()?.is_some()) } fn display() -> &'static str { diff --git a/crates/wast/src/core/memory.rs b/crates/wast/src/core/memory.rs index ed845e055d..3bc7345ef2 100644 --- a/crates/wast/src/core/memory.rs +++ b/crates/wast/src/core/memory.rs @@ -59,7 +59,7 @@ impl<'a> Parse<'a> for Memory<'a> { import, ty: parser.parse()?, } - } else if l.peek::() || parser.peek2::() { + } else if l.peek::()? || parser.peek2::()? { let is_32 = if parser.parse::>()?.is_some() { true } else { @@ -74,7 +74,7 @@ impl<'a> Parse<'a> for Memory<'a> { Ok(data) })?; MemoryKind::Inline { data, is_32 } - } else if l.peek::() || l.peek::() || l.peek::() { + } else if l.peek::()? || l.peek::()? || l.peek::()? { MemoryKind::Normal(parser.parse()?) } else { return Err(l.error()); @@ -133,19 +133,19 @@ impl<'a> Parse<'a> for Data<'a> { let id = parser.parse()?; let name = parser.parse()?; - let kind = if parser.peek::<&[u8]>() { + let kind = if parser.peek::<&[u8]>()? { DataKind::Passive // ... and otherwise we must be attached to a particular memory as well // as having an initialization offset. } else { - let memory = if parser.peek::() { + let memory = if parser.peek::()? { // FIXME: this is only here to accomodate // proposals/threads/imports.wast at this current moment in // time, this probably should get removed when the threads // proposal is rebased on the current spec. Index::Num(parser.parse()?, span) - } else if parser.peek2::() { + } else if parser.peek2::()? { parser.parens(|p| { p.parse::()?; p.parse() @@ -154,7 +154,7 @@ impl<'a> Parse<'a> for Data<'a> { Index::Num(0, span) }; let offset = parser.parens(|parser| { - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; parser.parse() } else { @@ -233,7 +233,7 @@ impl DataVal<'_> { impl<'a> Parse<'a> for DataVal<'a> { fn parse(parser: Parser<'a>) -> Result { - if !parser.peek::() { + if !parser.peek::()? { return Ok(DataVal::String(parser.parse()?)); } @@ -265,7 +265,7 @@ impl<'a> Parse<'a> for DataVal<'a> { where F: Fn(U, &mut Vec), { - if !lookahead.peek::() { + if !lookahead.peek::()? { return Ok(false); } parser.parse::()?; diff --git a/crates/wast/src/core/module.rs b/crates/wast/src/core/module.rs index b6e3ca0ad2..569a8884d4 100644 --- a/crates/wast/src/core/module.rs +++ b/crates/wast/src/core/module.rs @@ -111,11 +111,15 @@ impl<'a> Module<'a> { impl<'a> Parse<'a> for Module<'a> { fn parse(parser: Parser<'a>) -> Result { let _r = parser.register_annotation("custom"); + let _r = parser.register_annotation("producers"); + let _r = parser.register_annotation("name"); + let _r = parser.register_annotation("dylink.0"); + let span = parser.parse::()?.0; let id = parser.parse()?; let name = parser.parse()?; - let kind = if parser.peek::() { + let kind = if parser.peek::()? { parser.parse::()?; let mut data = Vec::new(); while !parser.is_empty() { @@ -165,44 +169,47 @@ impl<'a> ModuleField<'a> { impl<'a> Parse<'a> for ModuleField<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { + if parser.peek::>()? { return Ok(ModuleField::Type(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Rec(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Import(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Func(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Table(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Memory(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Global(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Export(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; return Ok(ModuleField::Start(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Elem(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Data(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? { return Ok(ModuleField::Tag(parser.parse()?)); } - if parser.peek::() { + if parser.peek::()? + || parser.peek::()? + || parser.peek::()? + { return Ok(ModuleField::Custom(parser.parse()?)); } Err(parser.error("expected valid module field")) diff --git a/crates/wast/src/core/resolve/deinline_import_export.rs b/crates/wast/src/core/resolve/deinline_import_export.rs index db88706817..c338407182 100644 --- a/crates/wast/src/core/resolve/deinline_import_export.rs +++ b/crates/wast/src/core/resolve/deinline_import_export.rs @@ -120,13 +120,16 @@ pub fn run(fields: &mut Vec) { ElemPayload::Indices(v) => v.len(), ElemPayload::Exprs { exprs, .. } => exprs.len(), }; - let kind = TableKind::Normal(TableType { - limits: Limits { - min: len as u32, - max: Some(len as u32), + let kind = TableKind::Normal { + ty: TableType { + limits: Limits { + min: len as u32, + max: Some(len as u32), + }, + elem: *elem, }, - elem: *elem, - }); + init_expr: None, + }; let payload = match mem::replace(&mut t.kind, kind) { TableKind::Inline { payload, .. } => payload, _ => unreachable!(), @@ -146,7 +149,7 @@ pub fn run(fields: &mut Vec) { })); } - TableKind::Normal(_) => {} + TableKind::Normal { .. } => {} } } diff --git a/crates/wast/src/core/resolve/names.rs b/crates/wast/src/core/resolve/names.rs index 85adb120de..4f252ad44b 100644 --- a/crates/wast/src/core/resolve/names.rs +++ b/crates/wast/src/core/resolve/names.rs @@ -3,6 +3,7 @@ use crate::core::*; use crate::names::{resolve_error, Namespace}; use crate::token::{Id, Index}; use crate::Error; +use std::collections::HashMap; pub fn resolve<'a>(fields: &mut Vec>) -> Result, Error> { let mut resolver = Resolver::default(); @@ -25,7 +26,7 @@ pub struct Resolver<'a> { tags: Namespace<'a>, datas: Namespace<'a>, elems: Namespace<'a>, - fields: Namespace<'a>, + fields: HashMap>, type_info: Vec>, } @@ -46,16 +47,20 @@ impl<'a> Resolver<'a> { } fn register_type(&mut self, ty: &Type<'a>) -> Result<(), Error> { + let type_index = self.types.register(ty.id, "type")?; + match &ty.def { // For GC structure types we need to be sure to populate the // field namespace here as well. // - // The field namespace is global, but the resolved indices - // are relative to the struct they are defined in + // The field namespace is relative to the struct fields are defined in TypeDef::Struct(r#struct) => { for (i, field) in r#struct.fields.iter().enumerate() { if let Some(id) = field.id { - self.fields.register_specific(id, i as u32, "field")?; + self.fields + .entry(type_index) + .or_insert(Namespace::default()) + .register_specific(id, i as u32, "field")?; } } } @@ -75,7 +80,6 @@ impl<'a> Resolver<'a> { _ => self.type_info.push(TypeInfo::Other), } - self.types.register(ty.id, "type")?; Ok(()) } @@ -176,7 +180,7 @@ impl<'a> Resolver<'a> { } // .. followed by locals themselves - for local in locals { + for local in locals.iter() { scope.register(local.id, "local")?; } @@ -262,8 +266,11 @@ impl<'a> Resolver<'a> { } ModuleField::Table(t) => { - if let TableKind::Normal(t) = &mut t.kind { - self.resolve_heaptype(&mut t.elem.heap)?; + if let TableKind::Normal { ty, init_expr } = &mut t.kind { + self.resolve_heaptype(&mut ty.elem.heap)?; + if let Some(init_expr) = init_expr { + self.resolve_expr(init_expr)?; + } } Ok(()) } @@ -280,6 +287,10 @@ impl<'a> Resolver<'a> { Ok(()) } + fn resolve_reftype(&self, ty: &mut RefType<'a>) -> Result<(), Error> { + self.resolve_heaptype(&mut ty.heap) + } + fn resolve_heaptype(&self, ty: &mut HeapType<'a>) -> Result<(), Error> { match ty { HeapType::Index(i) => { @@ -384,54 +395,21 @@ impl<'a, 'b> ExprResolver<'a, 'b> { } fn resolve_block_type(&mut self, bt: &mut BlockType<'a>) -> Result<(), Error> { - // Ok things get interesting here. First off when parsing `bt` - // *optionally* has an index and a function type listed. If - // they're both not present it's equivalent to 0 params and 0 - // results. - // - // In MVP wasm blocks can have 0 params and 0-1 results. Now - // there's also multi-value. We want to prefer MVP wasm wherever - // possible (for backcompat) so we want to list this block as - // being an "MVP" block if we can. The encoder only has - // `BlockType` to work with, so it'll be looking at `params` and - // `results` to figure out what to encode. If `params` and - // `results` fit within MVP, then it uses MVP encoding + // If the index is specified on this block type then that's the source + // of resolution and the resolver step here will verify the inline type + // matches. Note that indexes may come from the source text itself but + // may also come from being injected as part of the type expansion phase + // of resolution. // - // To put all that together, here we handle: - // - // * If the `index` was specified, resolve it and use it as the - // source of truth. If this turns out to be an MVP type, - // record it as such. - // * Otherwise use `params` and `results` as the source of - // truth. *If* this were a non-MVP compatible block `index` - // would be filled by by `tyexpand.rs`. - // - // tl;dr; we handle the `index` here if it's set and then fill - // out `params` and `results` if we can, otherwise no work - // happens. + // If no type is present then that means that the inline type is not + // present or has 0-1 results. In that case the nested value types are + // resolved, if they're there, to get encoded later on. if bt.ty.index.is_some() { - let (ty, _) = self.resolver.resolve_type_use(&mut bt.ty)?; - let n = match ty { - Index::Num(n, _) => *n, - Index::Id(_) => panic!("expected `Num`"), - }; - let ty = match self.resolver.type_info.get(n as usize) { - Some(TypeInfo::Func { params, results }) => (params, results), - _ => return Ok(()), - }; - if ty.0.len() == 0 && ty.1.len() <= 1 { - let mut inline = FunctionType::default(); - inline.results = ty.1.clone(); - bt.ty.inline = Some(inline); - bt.ty.index = None; - } - } - - // If the inline annotation persists to this point then resolve - // all of its inline value types. - if let Some(inline) = &mut bt.ty.inline { + self.resolver.resolve_type_use(&mut bt.ty)?; + } else if let Some(inline) = &mut bt.ty.inline { inline.resolve(self.resolver)?; } + Ok(()) } @@ -443,7 +421,7 @@ impl<'a, 'b> ExprResolver<'a, 'b> { } match instr { - MemorySize(i) | MemoryGrow(i) | MemoryFill(i) => { + MemorySize(i) | MemoryGrow(i) | MemoryFill(i) | MemoryDiscard(i) => { self.resolver.resolve(&mut i.mem, Ns::Memory)?; } MemoryInit(i) => { @@ -508,19 +486,23 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolver.resolve_type_use(&mut c.ty)?; } + CallRef(i) | ReturnCallRef(i) => { + self.resolver.resolve(i, Ns::Type)?; + } + FuncBind(b) => { self.resolver.resolve_type_use(&mut b.ty)?; } Let(t) => { // Resolve (ref T) in locals - for local in &mut t.locals { + for local in t.locals.iter_mut() { self.resolver.resolve_valtype(&mut local.ty)?; } // Register all locals defined in this let let mut scope = Namespace::default(); - for local in &t.locals { + for local in t.locals.iter() { scope.register(local.id, "local")?; } self.scopes.push(scope); @@ -539,6 +521,20 @@ impl<'a, 'b> ExprResolver<'a, 'b> { }); self.resolve_block_type(bt)?; } + TryTable(try_table) => { + self.blocks.push(ExprBlock { + label: try_table.block.label, + pushed_scope: false, + }); + self.resolve_block_type(&mut try_table.block)?; + for catch in &mut try_table.catches { + self.resolver.resolve(&mut catch.tag, Ns::Tag)?; + self.resolve_label(&mut catch.label)?; + } + if let Some(catch_all) = &mut try_table.catch_all { + self.resolve_label(&mut catch_all.label)?; + } + } // On `End` instructions we pop a label from the stack, and for both // `End` and `Else` instructions if they have labels listed we @@ -601,16 +597,6 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolve_label(i)?; } - BrOnCast(i) | BrOnCastFail(i) => { - self.resolve_label(&mut i.label)?; - self.resolver.resolve(&mut i.r#type, Ns::Type)?; - } - - BrOnFunc(l) | BrOnData(l) | BrOnI31(l) | BrOnArray(l) | BrOnNonFunc(l) - | BrOnNonData(l) | BrOnNonI31(l) | BrOnNonArray(l) => { - self.resolve_label(l)?; - } - Select(s) => { if let Some(list) = &mut s.tys { for ty in list { @@ -619,15 +605,37 @@ impl<'a, 'b> ExprResolver<'a, 'b> { } } - RefTest(i) | RefCast(i) | StructNew(i) | StructNewDefault(i) | ArrayNew(i) - | ArrayNewDefault(i) | ArrayGet(i) | ArrayGetS(i) | ArrayGetU(i) | ArraySet(i) - | ArrayLen(i) => { + RefTest(i) => { + self.resolver.resolve_reftype(&mut i.r#type)?; + } + RefCast(i) => { + self.resolver.resolve_reftype(&mut i.r#type)?; + } + BrOnCast(i) => { + self.resolve_label(&mut i.label)?; + self.resolver.resolve_reftype(&mut i.to_type)?; + self.resolver.resolve_reftype(&mut i.from_type)?; + } + BrOnCastFail(i) => { + self.resolve_label(&mut i.label)?; + self.resolver.resolve_reftype(&mut i.to_type)?; + self.resolver.resolve_reftype(&mut i.from_type)?; + } + + StructNew(i) | StructNewDefault(i) | ArrayNew(i) | ArrayNewDefault(i) | ArrayGet(i) + | ArrayGetS(i) | ArrayGetU(i) | ArraySet(i) => { self.resolver.resolve(i, Ns::Type)?; } StructSet(s) | StructGet(s) | StructGetS(s) | StructGetU(s) => { - self.resolver.resolve(&mut s.r#struct, Ns::Type)?; - self.resolver.fields.resolve(&mut s.field, "field")?; + let type_index = self.resolver.resolve(&mut s.r#struct, Ns::Type)?; + if let Index::Id(field_id) = s.field { + self.resolver + .fields + .get(&type_index) + .ok_or(Error::new(field_id.span(), format!("accessing a named field `{}` in a struct without named fields, type index {}", field_id.name(), type_index)))? + .resolve(&mut s.field, "field")?; + } } ArrayNewFixed(a) => { @@ -641,14 +649,23 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolver.resolve(&mut a.array, Ns::Type)?; self.resolver.elems.resolve(&mut a.elem_idx, "elem")?; } + ArrayFill(a) => { + self.resolver.resolve(&mut a.array, Ns::Type)?; + } ArrayCopy(a) => { self.resolver.resolve(&mut a.dest_array, Ns::Type)?; self.resolver.resolve(&mut a.src_array, Ns::Type)?; } - - RefNull(ty) | CallRef(ty) | ReturnCallRef(ty) => { - self.resolver.resolve_heaptype(ty)? + ArrayInitData(a) => { + self.resolver.resolve(&mut a.array, Ns::Type)?; + self.resolver.datas.resolve(&mut a.segment, "data")?; } + ArrayInitElem(a) => { + self.resolver.resolve(&mut a.array, Ns::Type)?; + self.resolver.elems.resolve(&mut a.segment, "elem")?; + } + + RefNull(ty) => self.resolver.resolve_heaptype(ty)?, _ => {} } diff --git a/crates/wast/src/core/resolve/types.rs b/crates/wast/src/core/resolve/types.rs index 38af9e6808..bfb996b4b6 100644 --- a/crates/wast/src/core/resolve/types.rs +++ b/crates/wast/src/core/resolve/types.rs @@ -103,8 +103,16 @@ impl<'a> Expander<'a> { } }, - ModuleField::Table(_) - | ModuleField::Memory(_) + ModuleField::Table(t) => match &mut t.kind { + TableKind::Normal { init_expr, .. } => { + if let Some(expr) = init_expr { + self.expand_expression(expr); + } + } + TableKind::Import { .. } | TableKind::Inline { .. } => {} + }, + + ModuleField::Memory(_) | ModuleField::Start(_) | ModuleField::Export(_) | ModuleField::Custom(_) => {} @@ -132,7 +140,8 @@ impl<'a> Expander<'a> { | Instruction::If(bt) | Instruction::Loop(bt) | Instruction::Let(LetType { block: bt, .. }) - | Instruction::Try(bt) => { + | Instruction::Try(bt) + | Instruction::TryTable(TryTable { block: bt, .. }) => { // No expansion necessary, a type reference is already here. // We'll verify that it's the same as the inline type, if any, // later. @@ -210,6 +219,7 @@ impl<'a> Expander<'a> { name: None, def: key.to_def(span), parent: None, + final_type: None, })); let idx = Index::Id(id); key.insert(self, idx); diff --git a/crates/wast/src/core/table.rs b/crates/wast/src/core/table.rs index 005bfe2046..280244498f 100644 --- a/crates/wast/src/core/table.rs +++ b/crates/wast/src/core/table.rs @@ -1,6 +1,6 @@ use crate::core::*; use crate::kw; -use crate::parser::{Parse, Parser, Result}; +use crate::parser::{Parse, Parser, Peek, Result}; use crate::token::{Id, Index, LParen, NameAnnotation, Span}; /// A WebAssembly `table` directive in a module. @@ -30,7 +30,12 @@ pub enum TableKind<'a> { }, /// A typical memory definition which simply says the limits of the table - Normal(TableType<'a>), + Normal { + /// Table type. + ty: TableType<'a>, + /// Optional items initializer expression. + init_expr: Option>, + }, /// The elem segments of this table, starting from 0, explicitly listed Inline { @@ -51,24 +56,30 @@ impl<'a> Parse<'a> for Table<'a> { // Afterwards figure out which style this is, either: // - // * `elemtype (elem ...)` - // * `(import "a" "b") limits` - // * `limits` + // * `elemtype (elem ...)` + // * `(import "a" "b") limits` + // * `limits` let mut l = parser.lookahead1(); - let kind = if l.peek::() { + let kind = if l.peek::()? { let elem = parser.parse()?; let payload = parser.parens(|p| { p.parse::()?; - let ty = if parser.peek::() { - Some(elem) + if p.peek::()? { + ElemPayload::parse_exprs(p, elem) } else { - None - }; - ElemPayload::parse_tail(parser, ty) + ElemPayload::parse_indices(p, Some(elem)) + } })?; TableKind::Inline { elem, payload } - } else if l.peek::() { - TableKind::Normal(parser.parse()?) + } else if l.peek::()? { + TableKind::Normal { + ty: parser.parse()?, + init_expr: if !parser.is_empty() { + Some(parser.parse::()?) + } else { + None + }, + } } else if let Some(import) = parser.parse()? { TableKind::Import { import, @@ -144,35 +155,67 @@ impl<'a> Parse<'a> for Elem<'a> { let id = parser.parse()?; let name = parser.parse()?; - let kind = if parser.peek::() { + // Element segments can start in a number of different ways: + // + // * `(elem ...` + // * `(elem declare ...` + // * `(elem (table ...` + // * `(elem (offset ...` + // * `(elem ( ...` (omitted `offset`) + let mut table_omitted = false; + let kind = if parser.peek::()? { parser.parse::()?; ElemKind::Declared - } else if parser.peek::() || (parser.peek::() && !parser.peek::()) { - let table = if parser.peek::() { + } else if parser.peek::()? + || (parser.peek::()? && !parser.peek::()?) + { + let table = if parser.peek::()? { // FIXME: this is only here to accomodate // proposals/threads/imports.wast at this current moment in // time, this probably should get removed when the threads // proposal is rebased on the current spec. + table_omitted = true; Index::Num(parser.parse()?, span) - } else if parser.peek2::() { + } else if parser.peek2::()? { parser.parens(|p| { p.parse::()?; p.parse() })? } else { + table_omitted = true; Index::Num(0, span) }; - let offset = parser.parens(|parser| { - if parser.peek::() { - parser.parse::()?; - } - parser.parse() - })?; + + let offset = parse_expr_or_single_instr::(parser)?; ElemKind::Active { table, offset } } else { ElemKind::Passive }; - let payload = parser.parse()?; + + // Element segments can have a number of ways to specify their element + // lists: + // + // * `func 0 1 ...` - list of indices + // * ` (ref.null func) ...` - list of expressions + // * `0 1 ...` - list of indices, only if the table was omitted for the + // legacy way tables were printed. + let indices = if parser.peek::()? { + parser.parse::()?; + true + } else if parser.peek::()? { + false + } else if table_omitted { + true + } else { + false // this will fall through to failing to parse a `RefType` + }; + let payload = if indices { + ElemPayload::parse_indices(parser, None)? + } else { + let ty = parser.parse()?; + ElemPayload::parse_exprs(parser, ty)? + }; + Ok(Elem { span, id, @@ -183,47 +226,63 @@ impl<'a> Parse<'a> for Elem<'a> { } } -impl<'a> Parse<'a> for ElemPayload<'a> { - fn parse(parser: Parser<'a>) -> Result { - ElemPayload::parse_tail(parser, parser.parse()?) - } -} - impl<'a> ElemPayload<'a> { - fn parse_tail(parser: Parser<'a>, ty: Option>) -> Result { - let (must_use_indices, ty) = match ty { - None => { - parser.parse::>()?; - (true, RefType::func()) - } - Some(ty) => (false, ty), + fn parse_indices(parser: Parser<'a>, ty: Option>) -> Result { + let mut ret = match ty { + // If there is no requested type, then it's ok to parse a list of + // indices. + None => ElemPayload::Indices(Vec::new()), + + // If the requested type is a `funcref` type then a list of indices + // can be parsed. This is because the list-of-indices encoding in + // the binary format can only accomodate the `funcref` type. + Some(ty) if ty == RefType::func() => ElemPayload::Indices(Vec::new()), + + // Otherwise silently translate this list-of-indices into a + // list-of-expressions because that's the only way to accomodate a + // non-funcref type. + Some(ty) => ElemPayload::Exprs { + ty, + exprs: Vec::new(), + }, }; - if let HeapType::Func = ty.heap { - if must_use_indices || parser.peek::>() { - let mut elems = Vec::new(); - while !parser.is_empty() { - elems.push(parser.parse()?); + while !parser.is_empty() { + let func = parser.parse()?; + match &mut ret { + ElemPayload::Indices(list) => list.push(func), + ElemPayload::Exprs { exprs, .. } => { + let expr = Expression { + instrs: [Instruction::RefFunc(func)].into(), + }; + exprs.push(expr); } - return Ok(ElemPayload::Indices(elems)); } } + Ok(ret) + } + + fn parse_exprs(parser: Parser<'a>, ty: RefType<'a>) -> Result { let mut exprs = Vec::new(); while !parser.is_empty() { - let expr = parser.parens(|parser| { - if parser.peek::() { - parser.parse::()?; - parser.parse() - } else { - // Without `item` this is "sugar" for a single-instruction - // expression. - let insn = parser.parse()?; - Ok(Expression { - instrs: [insn].into(), - }) - } - })?; + let expr = parse_expr_or_single_instr::(parser)?; exprs.push(expr); } Ok(ElemPayload::Exprs { exprs, ty }) } } + +// Parses either `(T expr)` or `(instr)`, returning the resulting expression. +fn parse_expr_or_single_instr<'a, T>(parser: Parser<'a>) -> Result> +where + T: Parse<'a> + Peek, +{ + if parser.peek2::()? { + parser.parens(|parser| { + parser.parse::()?; + parser.parse() + }) + } else { + // Without `T` this is "sugar" for a single instruction (still possibly folded). + Ok(Expression::parse_folded_instruction(parser)?) + } +} diff --git a/crates/wast/src/core/types.rs b/crates/wast/src/core/types.rs index f3870f5b6a..4bf69fe051 100644 --- a/crates/wast/src/core/types.rs +++ b/crates/wast/src/core/types.rs @@ -19,22 +19,22 @@ pub enum ValType<'a> { impl<'a> Parse<'a> for ValType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(ValType::I32) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(ValType::I64) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(ValType::F32) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(ValType::F64) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(ValType::V128) - } else if l.peek::() { + } else if l.peek::()? { Ok(ValType::Ref(parser.parse()?)) } else { Err(l.error()) @@ -43,13 +43,13 @@ impl<'a> Parse<'a> for ValType<'a> { } impl<'a> Peek for ValType<'a> { - fn peek(cursor: Cursor<'_>) -> bool { - kw::i32::peek(cursor) - || kw::i64::peek(cursor) - || kw::f32::peek(cursor) - || kw::f64::peek(cursor) - || kw::v128::peek(cursor) - || RefType::peek(cursor) + fn peek(cursor: Cursor<'_>) -> Result { + Ok(kw::i32::peek(cursor)? + || kw::i64::peek(cursor)? + || kw::f32::peek(cursor)? + || kw::f64::peek(cursor)? + || kw::v128::peek(cursor)? + || RefType::peek(cursor)?) } fn display() -> &'static str { "valtype" @@ -66,19 +66,26 @@ pub enum HeapType<'a> { /// A reference to any host value: externref. This is part of the reference /// types proposal. Extern, + /// A reference to a wasm exception. This is part of the exceptions proposal. + Exn, /// A reference to any reference value: anyref. This is part of the GC /// proposal. Any, /// A reference that has an identity that can be compared: eqref. This is /// part of the GC proposal. Eq, - /// A reference to a GC object. This is part of the GC proposal. - Data, + /// A reference to a GC struct. This is part of the GC proposal. + Struct, /// A reference to a GC array. This is part of the GC proposal. Array, - /// An unboxed 31-bit integer: i31ref. This may be going away if there is no common - /// supertype of all reference types. Part of the GC proposal. + /// An unboxed 31-bit integer: i31ref. Part of the GC proposal. I31, + /// The bottom type of the funcref hierarchy. Part of the GC proposal. + NoFunc, + /// The bottom type of the externref hierarchy. Part of the GC proposal. + NoExtern, + /// The bottom type of the anyref hierarchy. Part of the GC proposal. + None, /// A reference to a function, struct, or array: ref T. This is part of the /// GC proposal. Index(Index<'a>), @@ -87,28 +94,40 @@ pub enum HeapType<'a> { impl<'a> Parse<'a> for HeapType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(HeapType::Func) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Extern) - } else if l.peek::() { + } else if l.peek::()? { + parser.parse::()?; + Ok(HeapType::Exn) + } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Any) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Eq) - } else if l.peek::() { - parser.parse::()?; - Ok(HeapType::Data) - } else if l.peek::() { + } else if l.peek::()? { + parser.parse::()?; + Ok(HeapType::Struct) + } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Array) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(HeapType::I31) - } else if l.peek::() { + } else if l.peek::()? { + parser.parse::()?; + Ok(HeapType::NoFunc) + } else if l.peek::()? { + parser.parse::()?; + Ok(HeapType::NoExtern) + } else if l.peek::()? { + parser.parse::()?; + Ok(HeapType::None) + } else if l.peek::()? { Ok(HeapType::Index(parser.parse()?)) } else { Err(l.error()) @@ -117,15 +136,19 @@ impl<'a> Parse<'a> for HeapType<'a> { } impl<'a> Peek for HeapType<'a> { - fn peek(cursor: Cursor<'_>) -> bool { - kw::func::peek(cursor) - || kw::r#extern::peek(cursor) - || kw::any::peek(cursor) - || kw::eq::peek(cursor) - || kw::data::peek(cursor) - || kw::array::peek(cursor) - || kw::i31::peek(cursor) - || (LParen::peek(cursor) && kw::r#type::peek2(cursor)) + fn peek(cursor: Cursor<'_>) -> Result { + Ok(kw::func::peek(cursor)? + || kw::r#extern::peek(cursor)? + || kw::exn::peek(cursor)? + || kw::any::peek(cursor)? + || kw::eq::peek(cursor)? + || kw::r#struct::peek(cursor)? + || kw::array::peek(cursor)? + || kw::i31::peek(cursor)? + || kw::nofunc::peek(cursor)? + || kw::noextern::peek(cursor)? + || kw::none::peek(cursor)? + || (LParen::peek(cursor)? && kw::r#type::peek2(cursor)?)) } fn display() -> &'static str { "heaptype" @@ -157,6 +180,14 @@ impl<'a> RefType<'a> { } } + /// An `exnrefr` as an abbreviation for `(ref null exn)`. + pub fn exn() -> Self { + RefType { + nullable: true, + heap: HeapType::Exn, + } + } + /// An `anyref` as an abbreviation for `(ref null any)`. pub fn any() -> Self { RefType { @@ -173,11 +204,11 @@ impl<'a> RefType<'a> { } } - /// An `dataref` as an abbreviation for `(ref null data)`. - pub fn data() -> Self { + /// An `structref` as an abbreviation for `(ref null struct)`. + pub fn r#struct() -> Self { RefType { nullable: true, - heap: HeapType::Data, + heap: HeapType::Struct, } } @@ -196,43 +227,79 @@ impl<'a> RefType<'a> { heap: HeapType::I31, } } + + /// A `nullfuncref` as an abbreviation for `(ref null nofunc)`. + pub fn nullfuncref() -> Self { + RefType { + nullable: true, + heap: HeapType::NoFunc, + } + } + + /// A `nullexternref` as an abbreviation for `(ref null noextern)`. + pub fn nullexternref() -> Self { + RefType { + nullable: true, + heap: HeapType::NoExtern, + } + } + + /// A `nullref` as an abbreviation for `(ref null none)`. + pub fn nullref() -> Self { + RefType { + nullable: true, + heap: HeapType::None, + } + } } impl<'a> Parse<'a> for RefType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(RefType::func()) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(RefType::func()) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(RefType::r#extern()) - } else if l.peek::() { + } else if l.peek::()? { + parser.parse::()?; + Ok(RefType::exn()) + } else if l.peek::()? { parser.parse::()?; Ok(RefType::any()) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(RefType::eq()) - } else if l.peek::() { - parser.parse::()?; - Ok(RefType::data()) - } else if l.peek::() { + } else if l.peek::()? { + parser.parse::()?; + Ok(RefType::r#struct()) + } else if l.peek::()? { parser.parse::()?; Ok(RefType::array()) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(RefType::i31()) - } else if l.peek::() { + } else if l.peek::()? { + parser.parse::()?; + Ok(RefType::nullfuncref()) + } else if l.peek::()? { + parser.parse::()?; + Ok(RefType::nullexternref()) + } else if l.peek::()? { + parser.parse::()?; + Ok(RefType::nullref()) + } else if l.peek::()? { parser.parens(|p| { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { p.parse::()?; let mut nullable = false; - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; nullable = true; } @@ -252,16 +319,20 @@ impl<'a> Parse<'a> for RefType<'a> { } impl<'a> Peek for RefType<'a> { - fn peek(cursor: Cursor<'_>) -> bool { - kw::funcref::peek(cursor) - || /* legacy */ kw::anyfunc::peek(cursor) - || kw::externref::peek(cursor) - || kw::anyref::peek(cursor) - || kw::eqref::peek(cursor) - || kw::dataref::peek(cursor) - || kw::arrayref::peek(cursor) - || kw::i31ref::peek(cursor) - || (LParen::peek(cursor) && kw::r#ref::peek2(cursor)) + fn peek(cursor: Cursor<'_>) -> Result { + Ok(kw::funcref::peek(cursor)? + || /* legacy */ kw::anyfunc::peek(cursor)? + || kw::externref::peek(cursor)? + || kw::exnref::peek(cursor)? + || kw::anyref::peek(cursor)? + || kw::eqref::peek(cursor)? + || kw::structref::peek(cursor)? + || kw::arrayref::peek(cursor)? + || kw::i31ref::peek(cursor)? + || kw::nullfuncref::peek(cursor)? + || kw::nullexternref::peek(cursor)? + || kw::nullref::peek(cursor)? + || (LParen::peek(cursor)? && kw::r#ref::peek2(cursor)?)) } fn display() -> &'static str { "reftype" @@ -280,13 +351,13 @@ pub enum StorageType<'a> { impl<'a> Parse<'a> for StorageType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(StorageType::I8) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(StorageType::I16) - } else if l.peek::() { + } else if l.peek::()? { Ok(StorageType::Val(parser.parse()?)) } else { Err(l.error()) @@ -305,7 +376,7 @@ pub struct GlobalType<'a> { impl<'a> Parse<'a> for GlobalType<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek2::() { + if parser.peek2::()? { parser.parens(|p| { p.parse::()?; Ok(GlobalType { @@ -334,7 +405,7 @@ pub struct Limits { impl<'a> Parse<'a> for Limits { fn parse(parser: Parser<'a>) -> Result { let min = parser.parse()?; - let max = if parser.peek::() { + let max = if parser.peek::()? { Some(parser.parse()?) } else { None @@ -355,7 +426,7 @@ pub struct Limits64 { impl<'a> Parse<'a> for Limits64 { fn parse(parser: Parser<'a>) -> Result { let min = parser.parse()?; - let max = if parser.peek::() { + let max = if parser.peek::()? { Some(parser.parse()?) } else { None @@ -403,7 +474,7 @@ pub enum MemoryType { impl<'a> Parse<'a> for MemoryType { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; let limits = parser.parse()?; let shared = parser.parse::>()?.is_some(); @@ -431,10 +502,10 @@ impl<'a> FunctionType<'a> { fn finish_parse(&mut self, allow_names: bool, parser: Parser<'a>) -> Result<()> { let mut params = Vec::from(mem::take(&mut self.params)); let mut results = Vec::from(mem::take(&mut self.results)); - while parser.peek2::() || parser.peek2::() { + while parser.peek2::()? || parser.peek2::()? { parser.parens(|p| { let mut l = p.lookahead1(); - if l.peek::() { + if l.peek::()? { if results.len() > 0 { return Err(p.error( "result before parameter (or unexpected token): \ @@ -456,7 +527,7 @@ impl<'a> FunctionType<'a> { while parse_more && !p.is_empty() { params.push((None, None, p.parse()?)); } - } else if l.peek::() { + } else if l.peek::()? { p.parse::()?; while !p.is_empty() { results.push(p.parse()?); @@ -485,15 +556,15 @@ impl<'a> Parse<'a> for FunctionType<'a> { } impl<'a> Peek for FunctionType<'a> { - fn peek(cursor: Cursor<'_>) -> bool { - if let Some(next) = cursor.lparen() { - match next.keyword() { - Some(("param", _)) | Some(("result", _)) => return true, + fn peek(cursor: Cursor<'_>) -> Result { + if let Some(next) = cursor.lparen()? { + match next.keyword()? { + Some(("param", _)) | Some(("result", _)) => return Ok(true), _ => {} } } - false + Ok(false) } fn display() -> &'static str { @@ -517,7 +588,7 @@ impl<'a> Parse<'a> for FunctionTypeNoNames<'a> { } impl<'a> Peek for FunctionTypeNoNames<'a> { - fn peek(cursor: Cursor<'_>) -> bool { + fn peek(cursor: Cursor<'_>) -> Result { FunctionType::peek(cursor) } @@ -543,15 +614,19 @@ impl<'a> Parse<'a> for StructType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut ret = StructType { fields: Vec::new() }; while !parser.is_empty() { - let field = if parser.peek2::() { - parser.parens(|parser| { - parser.parse::()?; - StructField::parse(parser, true) - }) - } else { - StructField::parse(parser, false) - }; - ret.fields.push(field?); + parser.parens(|parser| { + parser.parse::()?; + if parser.peek::()? { + let field = StructField::parse(parser, true); + ret.fields.push(field?); + } else { + while !parser.is_empty() { + let field = StructField::parse(parser, false); + ret.fields.push(field?); + } + } + Ok(()) + })?; } Ok(ret) } @@ -571,7 +646,7 @@ pub struct StructField<'a> { impl<'a> StructField<'a> { fn parse(parser: Parser<'a>, with_id: bool) -> Result { let id = if with_id { parser.parse()? } else { None }; - let (ty, mutable) = if parser.peek2::() { + let (ty, mutable) = if parser.peek2::()? { let ty = parser.parens(|parser| { parser.parse::()?; parser.parse() @@ -595,7 +670,7 @@ pub struct ArrayType<'a> { impl<'a> Parse<'a> for ArrayType<'a> { fn parse(parser: Parser<'a>) -> Result { - let (ty, mutable) = if parser.peek2::() { + let (ty, mutable) = if parser.peek2::()? { let ty = parser.parens(|parser| { parser.parse::()?; parser.parse() @@ -642,13 +717,13 @@ pub enum TypeDef<'a> { impl<'a> Parse<'a> for TypeDef<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(TypeDef::Func(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(TypeDef::Struct(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(TypeDef::Array(parser.parse()?)) } else { @@ -671,48 +746,59 @@ pub struct Type<'a> { pub def: TypeDef<'a>, /// The declared parent type of this definition. pub parent: Option>, + /// Whether this type is final or not. By default types are final. + pub final_type: Option, } -impl<'a> Type<'a> { - fn parse_inner(parser: Parser<'a>, parent: Option>) -> Result { +impl<'a> Peek for Type<'a> { + fn peek(cursor: Cursor<'_>) -> Result { + kw::r#type::peek(cursor) + } + fn display() -> &'static str { + "type" + } +} + +impl<'a> Parse<'a> for Type<'a> { + fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let id = parser.parse()?; let name = parser.parse()?; - let def = parser.parens(|parser| parser.parse())?; + + let (parent, def, final_type) = if parser.peek2::()? { + parser.parens(|parser| { + parser.parse::()?; + + let final_type: Option = if parser.peek::()? { + parser.parse::()?; + Some(true) + } else { + Some(false) + }; + + let parent = if parser.peek::>()? { + parser.parse()? + } else { + None + }; + let def = parser.parens(|parser| parser.parse())?; + Ok((parent, def, final_type)) + })? + } else { + (None, parser.parens(|parser| parser.parse())?, None) + }; + Ok(Type { span, id, name, def, parent, + final_type, }) } } -impl<'a> Peek for Type<'a> { - fn peek(cursor: Cursor<'_>) -> bool { - kw::r#type::peek(cursor) || kw::sub::peek(cursor) - } - fn display() -> &'static str { - "type" - } -} - -impl<'a> Parse<'a> for Type<'a> { - fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { - parser.parse::()?; - let parent = if parser.peek::>() { - parser.parse()? - } else { - None - }; - return parser.parens(|parser| Type::parse_inner(parser, parent)); - } - Type::parse_inner(parser, None) - } -} - /// A recursion group declaration in a module #[derive(Debug)] pub struct Rec<'a> { @@ -726,7 +812,7 @@ impl<'a> Parse<'a> for Rec<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let mut types = Vec::new(); - while parser.peek2::>() { + while parser.peek2::>()? { types.push(parser.parens(|p| p.parse())?); } Ok(Rec { span, types }) @@ -755,7 +841,7 @@ impl<'a, T> TypeUse<'a, T> { impl<'a, T: Peek + Parse<'a>> Parse<'a> for TypeUse<'a, T> { fn parse(parser: Parser<'a>) -> Result { - let index = if parser.peek2::() { + let index = if parser.peek2::()? { Some(parser.parens(|p| { p.parse::()?; p.parse() diff --git a/crates/wast/src/core/wast.rs b/crates/wast/src/core/wast.rs index 5780b9de4f..2d3b51b061 100644 --- a/crates/wast/src/core/wast.rs +++ b/crates/wast/src/core/wast.rs @@ -15,6 +15,7 @@ pub enum WastArgCore<'a> { V128(V128Const), RefNull(HeapType<'a>), RefExtern(u32), + RefHost(u32), } static ARGS: &[(&str, fn(Parser<'_>) -> Result>)] = { @@ -27,13 +28,14 @@ static ARGS: &[(&str, fn(Parser<'_>) -> Result>)] = { ("v128.const", |p| Ok(V128(p.parse()?))), ("ref.null", |p| Ok(RefNull(p.parse()?))), ("ref.extern", |p| Ok(RefExtern(p.parse()?))), + ("ref.host", |p| Ok(RefHost(p.parse()?))), ] }; impl<'a> Parse<'a> for WastArgCore<'a> { fn parse(parser: Parser<'a>) -> Result { let parse = parser.step(|c| { - if let Some((kw, rest)) = c.keyword() { + if let Some((kw, rest)) = c.keyword()? { if let Some(i) = ARGS.iter().position(|(name, _)| *name == kw) { return Ok((ARGS[i].1, rest)); } @@ -45,12 +47,12 @@ impl<'a> Parse<'a> for WastArgCore<'a> { } impl Peek for WastArgCore<'_> { - fn peek(cursor: Cursor<'_>) -> bool { - let kw = match cursor.keyword() { + fn peek(cursor: Cursor<'_>) -> Result { + let kw = match cursor.keyword()? { Some((kw, _)) => kw, - None => return false, + None => return Ok(false), }; - ARGS.iter().find(|(name, _)| *name == kw).is_some() + Ok(ARGS.iter().find(|(name, _)| *name == kw).is_some()) } fn display() -> &'static str { @@ -73,9 +75,23 @@ pub enum WastRetCore<'a> { RefNull(Option>), /// A non-null externref is expected which should contain the specified /// value. - RefExtern(u32), + RefExtern(Option), + /// A non-null anyref is expected which should contain the specified host value. + RefHost(u32), /// A non-null funcref is expected. RefFunc(Option>), + /// A non-null anyref is expected. + RefAny, + /// A non-null eqref is expected. + RefEq, + /// A non-null arrayref is expected. + RefArray, + /// A non-null structref is expected. + RefStruct, + /// A non-null i31ref is expected. + RefI31, + + Either(Vec>), } static RETS: &[(&str, fn(Parser<'_>) -> Result>)] = { @@ -88,14 +104,28 @@ static RETS: &[(&str, fn(Parser<'_>) -> Result>)] = { ("v128.const", |p| Ok(V128(p.parse()?))), ("ref.null", |p| Ok(RefNull(p.parse()?))), ("ref.extern", |p| Ok(RefExtern(p.parse()?))), + ("ref.host", |p| Ok(RefHost(p.parse()?))), ("ref.func", |p| Ok(RefFunc(p.parse()?))), + ("ref.any", |_| Ok(RefAny)), + ("ref.eq", |_| Ok(RefEq)), + ("ref.array", |_| Ok(RefArray)), + ("ref.struct", |_| Ok(RefStruct)), + ("ref.i31", |_| Ok(RefI31)), + ("either", |p| { + p.depth_check()?; + let mut cases = Vec::new(); + while !p.is_empty() { + cases.push(p.parens(|p| p.parse())?); + } + Ok(Either(cases)) + }), ] }; impl<'a> Parse<'a> for WastRetCore<'a> { fn parse(parser: Parser<'a>) -> Result { let parse = parser.step(|c| { - if let Some((kw, rest)) = c.keyword() { + if let Some((kw, rest)) = c.keyword()? { if let Some(i) = RETS.iter().position(|(name, _)| *name == kw) { return Ok((RETS[i].1, rest)); } @@ -107,12 +137,12 @@ impl<'a> Parse<'a> for WastRetCore<'a> { } impl Peek for WastRetCore<'_> { - fn peek(cursor: Cursor<'_>) -> bool { - let kw = match cursor.keyword() { + fn peek(cursor: Cursor<'_>) -> Result { + let kw = match cursor.keyword()? { Some((kw, _)) => kw, - None => return false, + None => return Ok(false), }; - RETS.iter().find(|(name, _)| *name == kw).is_some() + Ok(RETS.iter().find(|(name, _)| *name == kw).is_some()) } fn display() -> &'static str { @@ -134,10 +164,10 @@ where T: Parse<'a>, { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { + if parser.peek::()? { parser.parse::()?; Ok(NanPattern::CanonicalNan) - } else if parser.peek::() { + } else if parser.peek::()? { parser.parse::()?; Ok(NanPattern::ArithmeticNan) } else { @@ -165,7 +195,7 @@ pub enum V128Pattern { impl<'a> Parse<'a> for V128Pattern { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { parser.parse::()?; Ok(V128Pattern::I8x16([ parser.parse()?, @@ -185,7 +215,7 @@ impl<'a> Parse<'a> for V128Pattern { parser.parse()?, parser.parse()?, ])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Pattern::I16x8([ parser.parse()?, @@ -197,7 +227,7 @@ impl<'a> Parse<'a> for V128Pattern { parser.parse()?, parser.parse()?, ])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Pattern::I32x4([ parser.parse()?, @@ -205,10 +235,10 @@ impl<'a> Parse<'a> for V128Pattern { parser.parse()?, parser.parse()?, ])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Pattern::I64x2([parser.parse()?, parser.parse()?])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Pattern::F32x4([ parser.parse()?, @@ -216,7 +246,7 @@ impl<'a> Parse<'a> for V128Pattern { parser.parse()?, parser.parse()?, ])) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(V128Pattern::F64x2([parser.parse()?, parser.parse()?])) } else { diff --git a/crates/wast/src/encode.rs b/crates/wast/src/encode.rs index 3fc932690e..2fa57d60f7 100644 --- a/crates/wast/src/encode.rs +++ b/crates/wast/src/encode.rs @@ -8,6 +8,12 @@ impl Encode for &'_ T { } } +impl Encode for Box { + fn encode(&self, e: &mut Vec) { + T::encode(self, e) + } +} + impl Encode for [T] { fn encode(&self, e: &mut Vec) { self.len().encode(e); @@ -73,3 +79,11 @@ impl Encode for (T, U) { self.1.encode(e); } } + +impl Encode for (T, U, V) { + fn encode(&self, e: &mut Vec) { + self.0.encode(e); + self.1.encode(e); + self.2.encode(e); + } +} diff --git a/crates/wast/src/lexer.rs b/crates/wast/src/lexer.rs index ee40807f8d..2040fa3224 100644 --- a/crates/wast/src/lexer.rs +++ b/crates/wast/src/lexer.rs @@ -12,7 +12,7 @@ //! use wast::lexer::Lexer; //! //! let wat = "(module (func $foo))"; -//! for token in Lexer::new(wat) { +//! for token in Lexer::new(wat).iter(0) { //! println!("{:?}", token?); //! } //! # Ok(()) @@ -29,6 +29,7 @@ use crate::Error; use std::borrow::Cow; use std::char; use std::fmt; +use std::slice; use std::str; /// A structure used to lex the s-expression syntax of WAT files. @@ -38,56 +39,106 @@ use std::str; /// returned for any non-lexable text. #[derive(Clone)] pub struct Lexer<'a> { - remaining: &'a str, input: &'a str, allow_confusing_unicode: bool, } -/// A fragment of source lex'd from an input string. +/// A single token parsed from a `Lexer`. +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Token { + /// The kind of token this represents, such as whether it's whitespace, a + /// keyword, etc. + pub kind: TokenKind, + /// The byte offset within the original source for where this token came + /// from. + pub offset: usize, + /// The byte length of this token as it resides in the original source. + // + // NB: this is `u32` to enable packing `Token` into two pointers of size. + // This does limit a single token to being at most 4G large, but that seems + // probably ok. + pub len: u32, +} + +const _: () = { + assert!(std::mem::size_of::() <= std::mem::size_of::() * 2); +}; + +/// Classification of what was parsed from the input stream. /// /// This enumeration contains all kinds of fragments, including comments and -/// whitespace. For most cases you'll probably ignore these and simply look at -/// tokens. -#[derive(Debug, PartialEq)] -pub enum Token<'a> { +/// whitespace. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum TokenKind { /// A line comment, preceded with `;;` - LineComment(&'a str), + LineComment, /// A block comment, surrounded by `(;` and `;)`. Note that these can be /// nested. - BlockComment(&'a str), + BlockComment, /// A fragment of source that represents whitespace. - Whitespace(&'a str), + Whitespace, /// A left-parenthesis, including the source text for where it comes from. - LParen(&'a str), + LParen, /// A right-parenthesis, including the source text for where it comes from. - RParen(&'a str), + RParen, /// A string literal, which is actually a list of bytes. - String(WasmString<'a>), + String, /// An identifier (like `$foo`). /// /// All identifiers start with `$` and the payload here is the original /// source text. - Id(&'a str), + Id, /// A keyword, or something that starts with an alphabetic character. /// /// The payload here is the original source text. - Keyword(&'a str), + Keyword, /// A reserved series of `idchar` symbols. Unknown what this is meant to be /// used for, you'll probably generate an error about an unexpected token. - Reserved(&'a str), + Reserved, /// An integer. - Integer(Integer<'a>), + Integer(IntegerKind), /// A float. - Float(Float<'a>), + Float(FloatKind), +} + +/// Description of the parsed integer from the source. +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct IntegerKind { + sign: Option, + has_underscores: bool, + hex: bool, +} + +/// Description of a parsed float from the source. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum FloatKind { + #[doc(hidden)] + Inf { negative: bool }, + #[doc(hidden)] + Nan { negative: bool }, + #[doc(hidden)] + NanVal { + negative: bool, + has_underscores: bool, + }, + #[doc(hidden)] + Normal { has_underscores: bool, hex: bool }, +} + +enum ReservedKind { + String, + Idchars, + Reserved, } /// Errors that can be generated while lexing. @@ -159,49 +210,22 @@ pub enum SignToken { Minus, } -/// A parsed integer, signed or unsigned. -/// -/// Methods can be use to access the value of the integer. +/// A fully parsed integer from a source string with a payload ready to parse +/// into an integral type. #[derive(Debug, PartialEq)] -pub struct Integer<'a>(Box>); - -#[derive(Debug, PartialEq)] -struct IntegerInner<'a> { +pub struct Integer<'a> { sign: Option, - src: &'a str, val: Cow<'a, str>, hex: bool, } -/// A parsed float. -/// -/// Methods can be use to access the value of the float. -#[derive(Debug, PartialEq)] -pub struct Float<'a>(Box>); - -#[derive(Debug, PartialEq)] -struct FloatInner<'a> { - src: &'a str, - val: FloatVal<'a>, -} - -/// A parsed string. -#[derive(Debug, PartialEq)] -pub struct WasmString<'a>(Box>); - -#[derive(Debug, PartialEq)] -struct WasmStringInner<'a> { - src: &'a str, - val: Cow<'a, [u8]>, -} - /// Possible parsed float values #[derive(Debug, PartialEq, Eq)] -pub enum FloatVal<'a> { +pub enum Float<'a> { /// A float `NaN` representation Nan { /// The specific bits to encode for this float, optionally - val: Option, + val: Option>, /// Whether or not this is a negative `NaN` or not. negative: bool, }, @@ -261,7 +285,6 @@ impl<'a> Lexer<'a> { /// Creates a new lexer which will lex the `input` source string. pub fn new(input: &str) -> Lexer<'_> { Lexer { - remaining: input, input, allow_confusing_unicode: false, } @@ -288,19 +311,35 @@ impl<'a> Lexer<'a> { self } - /// Lexes the next token in the input. + /// Lexes the next at the byte position `pos` in the input. /// /// Returns `Some` if a token is found or `None` if we're at EOF. /// + /// The `pos` argument will be updated to point to the next token on a + /// successful parse. + /// /// # Errors /// /// Returns an error if the input is malformed. - pub fn parse(&mut self) -> Result>, Error> { - let pos = self.cur(); + pub fn parse(&self, pos: &mut usize) -> Result, Error> { + let offset = *pos; + Ok(match self.parse_kind(pos)? { + Some(kind) => Some(Token { + kind, + offset, + len: (*pos - offset).try_into().unwrap(), + }), + None => None, + }) + } + + fn parse_kind(&self, pos: &mut usize) -> Result, Error> { + let start = *pos; // This `match` generally parses the grammar specified at // // https://webassembly.github.io/spec/core/text/lexical.html#text-token - let byte = match self.remaining.as_bytes().first() { + let remaining = &self.input.as_bytes()[start..]; + let byte = match remaining.first() { Some(b) => b, None => return Ok(None), }; @@ -309,12 +348,12 @@ impl<'a> Lexer<'a> { // Open-parens check the next character to see if this is the start // of a block comment, otherwise it's just a bland left-paren // token. - b'(' => match self.remaining.as_bytes().get(1) { + b'(' => match remaining.get(1) { Some(b';') => { let mut level = 1; // Note that we're doing a byte-level search here for the // close-delimiter of `;)`. The actual source text is utf-8 - // encode in `self.remaining` but due to how utf-8 works we + // encode in `remaining` but due to how utf-8 works we // can safely search for an ASCII byte since it'll never // otherwise appear in the middle of a codepoint and if we // find it then it's guaranteed to be the right byte. @@ -322,7 +361,7 @@ impl<'a> Lexer<'a> { // Mainly we're avoiding the overhead of decoding utf-8 // characters into a Rust `char` since it's otherwise // unnecessary work. - let mut iter = self.remaining.as_bytes()[2..].iter(); + let mut iter = remaining[2..].iter(); while let Some(ch) = iter.next() { match ch { b'(' => { @@ -336,88 +375,110 @@ impl<'a> Lexer<'a> { level -= 1; iter.next(); if level == 0 { - let len = self.remaining.len() - iter.as_slice().len(); - let (comment, remaining) = self.remaining.split_at(len); - self.remaining = remaining; - self.check_confusing_comment(comment)?; - return Ok(Some(Token::BlockComment(comment))); + let len = remaining.len() - iter.as_slice().len(); + let comment = &self.input[start..][..len]; + *pos += len; + self.check_confusing_comment(*pos, comment)?; + return Ok(Some(TokenKind::BlockComment)); } } } _ => {} } } - Err(self.error(pos, LexError::DanglingBlockComment)) + Err(self.error(start, LexError::DanglingBlockComment)) } - _ => Ok(Some(Token::LParen(self.split_first_byte()))), - }, + _ => { + *pos += 1; - b')' => Ok(Some(Token::RParen(self.split_first_byte()))), + Ok(Some(TokenKind::LParen)) + } + }, - b'"' => { - let val = self.string()?; - let src = &self.input[pos..self.cur()]; - return Ok(Some(Token::String(WasmString(Box::new(WasmStringInner { - val, - src, - }))))); + b')' => { + *pos += 1; + Ok(Some(TokenKind::RParen)) } // https://webassembly.github.io/spec/core/text/lexical.html#white-space - b' ' | b'\n' | b'\r' | b'\t' => Ok(Some(Token::Whitespace(self.split_ws()))), - - c @ idchars!() => { - let reserved = self.split_while(|b| matches!(b, idchars!())); - - // https://webassembly.github.io/spec/core/text/values.html#integers - if let Some(number) = self.number(reserved) { - Ok(Some(number)) - // https://webassembly.github.io/spec/core/text/values.html#text-id - } else if *c == b'$' && reserved.len() > 1 { - Ok(Some(Token::Id(reserved))) - // https://webassembly.github.io/spec/core/text/lexical.html#text-keyword - } else if b'a' <= *c && *c <= b'z' { - Ok(Some(Token::Keyword(reserved))) - } else { - Ok(Some(Token::Reserved(reserved))) + b' ' | b'\n' | b'\r' | b'\t' => { + self.skip_ws(pos); + Ok(Some(TokenKind::Whitespace)) + } + + c @ (idchars!() | b'"') => { + let (kind, src) = self.parse_reserved(pos)?; + match kind { + // If the reserved token was simply a single string then + // that is converted to a standalone string token + ReservedKind::String => return Ok(Some(TokenKind::String)), + + // If only idchars were consumed then this could be a + // specific kind of standalone token we're interested in. + ReservedKind::Idchars => { + // https://webassembly.github.io/spec/core/text/values.html#integers + if let Some(ret) = self.classify_number(src) { + return Ok(Some(ret)); + // https://webassembly.github.io/spec/core/text/values.html#text-id + } else if *c == b'$' && src.len() > 1 { + return Ok(Some(TokenKind::Id)); + // https://webassembly.github.io/spec/core/text/lexical.html#text-keyword + } else if b'a' <= *c && *c <= b'z' { + return Ok(Some(TokenKind::Keyword)); + } + } + + // ... otherwise this was a conglomeration of idchars, + // strings, or just idchars that don't match a prior rule, + // meaning this falls through to the fallback `Reserved` + // token. + ReservedKind::Reserved => {} } + + Ok(Some(TokenKind::Reserved)) } // This could be a line comment, otherwise `;` is a reserved token. // The second byte is checked to see if it's a `;;` line comment - b';' => match self.remaining.as_bytes().get(1) { + // + // Note that this character being considered as part of a + // `reserved` token is part of the annotations proposal. + b';' => match remaining.get(1) { Some(b';') => { - let comment = self.split_until(b'\n'); - self.check_confusing_comment(comment)?; - Ok(Some(Token::LineComment(comment))) + let comment = self.split_until(pos, b'\n'); + self.check_confusing_comment(*pos, comment)?; + Ok(Some(TokenKind::LineComment)) + } + _ => { + *pos += 1; + Ok(Some(TokenKind::Reserved)) } - _ => Ok(Some(Token::Reserved(self.split_first_byte()))), }, // Other known reserved tokens other than `;` - b',' | b'[' | b']' | b'{' | b'}' => Ok(Some(Token::Reserved(self.split_first_byte()))), + // + // Note that these characters being considered as part of a + // `reserved` token is part of the annotations proposal. + b',' | b'[' | b']' | b'{' | b'}' => { + *pos += 1; + Ok(Some(TokenKind::Reserved)) + } _ => { - let ch = self.remaining.chars().next().unwrap(); - Err(self.error(pos, LexError::Unexpected(ch))) + let ch = self.input[start..].chars().next().unwrap(); + Err(self.error(*pos, LexError::Unexpected(ch))) } } } - fn split_first_byte(&mut self) -> &'a str { - let (token, remaining) = self.remaining.split_at(1); - self.remaining = remaining; - token + fn split_until(&self, pos: &mut usize, byte: u8) -> &'a str { + let remaining = &self.input[*pos..]; + let byte_pos = memchr::memchr(byte, remaining.as_bytes()).unwrap_or(remaining.len()); + *pos += byte_pos; + &remaining[..byte_pos] } - fn split_until(&mut self, byte: u8) -> &'a str { - let pos = memchr::memchr(byte, self.remaining.as_bytes()).unwrap_or(self.remaining.len()); - let (ret, remaining) = self.remaining.split_at(pos); - self.remaining = remaining; - ret - } - - fn split_ws(&mut self) -> &'a str { + fn skip_ws(&self, pos: &mut usize) { // This table is a byte lookup table to determine whether a byte is a // whitespace byte. There are only 4 whitespace bytes for the `*.wat` // format right now which are ' ', '\t', '\r', and '\n'. These 4 bytes @@ -427,7 +488,7 @@ impl<'a> Lexer<'a> { // known that if these bytes are found they're guaranteed to be the // whitespace byte, so they can be safely skipped and we don't have to // do full utf-8 decoding. This means that the goal of this function is - // to find the first non-whitespace byte in `self.remaining`. + // to find the first non-whitespace byte in `remaining`. // // For now this lookup table seems to be the fastest, but projects like // https://github.com/lemire/despacer show other simd algorithms which @@ -455,30 +516,76 @@ impl<'a> Lexer<'a> { /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - let pos = self - .remaining + let remaining = &self.input[*pos..]; + let non_ws_pos = remaining .as_bytes() .iter() .position(|b| WS[*b as usize] != 1) - .unwrap_or(self.remaining.len()); - let (ret, remaining) = self.remaining.split_at(pos); - self.remaining = remaining; - ret + .unwrap_or(remaining.len()); + *pos += non_ws_pos; } - fn split_while(&mut self, f: impl Fn(u8) -> bool) -> &'a str { - let pos = self - .remaining - .as_bytes() - .iter() - .position(|b| !f(*b)) - .unwrap_or(self.remaining.len()); - let (ret, remaining) = self.remaining.split_at(pos); - self.remaining = remaining; - ret + /// Splits off a "reserved" token which is then further processed later on + /// to figure out which kind of token it is `depending on `ReservedKind`. + /// + /// For more information on this method see the clarification at + /// but the general gist is + /// that this is parsing the grammar: + /// + /// ```text + /// reserved := (idchar | string)+ + /// ``` + /// + /// which means that it is eating any number of adjacent string/idchar + /// tokens (e.g. `a"b"c`) and returning the classification of what was + /// eaten. The classification assists in determining what the actual token + /// here eaten looks like. + fn parse_reserved(&self, pos: &mut usize) -> Result<(ReservedKind, &'a str), Error> { + let mut idchars = false; + let mut strings = 0u32; + let start = *pos; + while let Some(byte) = self.input.as_bytes().get(*pos) { + match byte { + // Normal `idchars` production which appends to the reserved + // token that's being produced. + idchars!() => { + idchars = true; + *pos += 1; + } + + // https://webassembly.github.io/spec/core/text/values.html#text-string + b'"' => { + strings += 1; + *pos += 1; + let mut it = self.input[*pos..].chars(); + let result = Lexer::parse_str(&mut it, self.allow_confusing_unicode); + *pos = self.input.len() - it.as_str().len(); + match result { + Ok(_) => {} + Err(e) => { + let err_pos = match &e { + LexError::UnexpectedEof => self.input.len(), + _ => self.input[..*pos].char_indices().next_back().unwrap().0, + }; + return Err(self.error(err_pos, e)); + } + } + } + + // Nothing else is considered part of a reserved token + _ => break, + } + } + let ret = &self.input[start..*pos]; + Ok(match (idchars, strings) { + (false, 0) => unreachable!(), + (false, 1) => (ReservedKind::String, ret), + (true, 0) => (ReservedKind::Idchars, ret), + _ => (ReservedKind::Reserved, ret), + }) } - fn number(&self, src: &'a str) -> Option> { + fn classify_number(&self, src: &str) -> Option { let (sign, num) = if let Some(stripped) = src.strip_prefix('+') { (Some(SignToken::Plus), stripped) } else if let Some(stripped) = src.strip_prefix('-') { @@ -491,51 +598,33 @@ impl<'a> Lexer<'a> { // Handle `inf` and `nan` which are special numbers here if num == "inf" { - return Some(Token::Float(Float(Box::new(FloatInner { - src, - val: FloatVal::Inf { negative }, - })))); + return Some(TokenKind::Float(FloatKind::Inf { negative })); } else if num == "nan" { - return Some(Token::Float(Float(Box::new(FloatInner { - src, - val: FloatVal::Nan { - val: None, - negative, - }, - })))); + return Some(TokenKind::Float(FloatKind::Nan { negative })); } else if let Some(stripped) = num.strip_prefix("nan:0x") { - let mut it = stripped.chars(); - let to_parse = skip_undescores(&mut it, false, char::is_ascii_hexdigit)?; + let mut it = stripped.as_bytes().iter(); + let has_underscores = skip_underscores(&mut it, |x| char::from(x).is_ascii_hexdigit())?; if it.next().is_some() { return None; } - let n = u64::from_str_radix(&to_parse, 16).ok()?; - return Some(Token::Float(Float(Box::new(FloatInner { - src, - val: FloatVal::Nan { - val: Some(n), - negative, - }, - })))); + return Some(TokenKind::Float(FloatKind::NanVal { + negative, + has_underscores, + })); } // Figure out if we're a hex number or not - let (mut it, hex, test_valid) = if let Some(stripped) = num.strip_prefix("0x") { - ( - stripped.chars(), - true, - char::is_ascii_hexdigit as fn(&char) -> bool, - ) + let test_valid: fn(u8) -> bool; + let (mut it, hex) = if let Some(stripped) = num.strip_prefix("0x") { + test_valid = |x: u8| char::from(x).is_ascii_hexdigit(); + (stripped.as_bytes().iter(), true) } else { - ( - num.chars(), - false, - char::is_ascii_digit as fn(&char) -> bool, - ) + test_valid = |x: u8| char::from(x).is_ascii_digit(); + (num.as_bytes().iter(), false) }; // Evaluate the first part, moving out all underscores - let val = skip_undescores(&mut it, negative, test_valid)?; + let mut has_underscores = skip_underscores(&mut it, test_valid)?; match it.clone().next() { // If we're followed by something this may be a float so keep going. @@ -543,47 +632,48 @@ impl<'a> Lexer<'a> { // Otherwise this is a valid integer literal! None => { - return Some(Token::Integer(Integer(Box::new(IntegerInner { + return Some(TokenKind::Integer(IntegerKind { + has_underscores, sign, - src, - val, hex, - })))) + })) } } // A number can optionally be after the decimal so only actually try to // parse one if it's there. - let decimal = if it.clone().next() == Some('.') { + if it.clone().next() == Some(&b'.') { it.next(); match it.clone().next() { - Some(c) if test_valid(&c) => Some(skip_undescores(&mut it, false, test_valid)?), - Some(_) | None => None, + Some(c) if test_valid(*c) => { + if skip_underscores(&mut it, test_valid)? { + has_underscores = true; + } + } + Some(_) | None => {} } - } else { - None }; // Figure out if there's an exponential part here to make a float, and // if so parse it but defer its actual calculation until later. - let exponent = match (hex, it.next()) { - (true, Some('p')) | (true, Some('P')) | (false, Some('e')) | (false, Some('E')) => { - let negative = match it.clone().next() { - Some('-') => { + match (hex, it.next()) { + (true, Some(b'p')) | (true, Some(b'P')) | (false, Some(b'e')) | (false, Some(b'E')) => { + match it.clone().next() { + Some(b'-') => { it.next(); - true } - Some('+') => { + Some(b'+') => { it.next(); - false } - _ => false, - }; - Some(skip_undescores(&mut it, negative, char::is_ascii_digit)?) + _ => {} + } + if skip_underscores(&mut it, |x| char::from(x).is_ascii_digit())? { + has_underscores = true; + } } - (_, None) => None, + (_, None) => {} _ => return None, - }; + } // We should have eaten everything by now, if not then this is surely // not a float or integer literal. @@ -591,73 +681,45 @@ impl<'a> Lexer<'a> { return None; } - return Some(Token::Float(Float(Box::new(FloatInner { - src, - val: FloatVal::Val { - hex, - integral: val, - exponent, - decimal, - }, - })))); - - fn skip_undescores<'a>( - it: &mut str::Chars<'a>, - negative: bool, - good: fn(&char) -> bool, - ) -> Option> { - enum State { - Raw, - Collecting(String), - } + return Some(TokenKind::Float(FloatKind::Normal { + has_underscores, + hex, + })); + + fn skip_underscores<'a>( + it: &mut slice::Iter<'_, u8>, + good: fn(u8) -> bool, + ) -> Option { let mut last_underscore = false; - let mut state = if negative { - State::Collecting("-".to_string()) - } else { - State::Raw - }; - let input = it.as_str(); - let first = it.next()?; - if !good(&first) { + let mut has_underscores = false; + let first = *it.next()?; + if !good(first) { return None; } - if let State::Collecting(s) = &mut state { - s.push(first); - } - let mut last = 1; while let Some(c) = it.clone().next() { - if c == '_' && !last_underscore { - if let State::Raw = state { - state = State::Collecting(input[..last].to_string()); - } + if *c == b'_' && !last_underscore { + has_underscores = true; it.next(); last_underscore = true; continue; } - if !good(&c) { + if !good(*c) { break; } - if let State::Collecting(s) = &mut state { - s.push(c); - } last_underscore = false; it.next(); - last += 1; } if last_underscore { return None; } - Some(match state { - State::Raw => input[..last].into(), - State::Collecting(s) => s.into(), - }) + Some(has_underscores) } } /// Verifies that `comment`, which is about to be returned, has a "confusing /// unicode character" in it and should instead be transformed into an /// error. - fn check_confusing_comment(&self, comment: &str) -> Result<(), Error> { + fn check_confusing_comment(&self, end: usize, comment: &str) -> Result<(), Error> { if self.allow_confusing_unicode { return Ok(()); } @@ -679,7 +741,7 @@ impl<'a> Lexer<'a> { // parsed `comment`, so we move backwards to where // `comment` started and then add the index within // `comment`. - let pos = self.cur() - comment.len() + pos; + let pos = end - comment.len() + pos; return Err(self.error(pos, LexError::ConfusingUnicode(c))); } } @@ -688,24 +750,6 @@ impl<'a> Lexer<'a> { Ok(()) } - /// Reads everything for a literal string except the leading `"`. Returns - /// the string value that has been read. - /// - /// https://webassembly.github.io/spec/core/text/values.html#text-string - fn string(&mut self) -> Result, Error> { - let mut it = self.remaining[1..].chars(); - let result = Lexer::parse_str(&mut it, self.allow_confusing_unicode); - let end = self.input.len() - it.as_str().len(); - self.remaining = &self.input[end..]; - result.map_err(|e| { - let err_pos = match &e { - LexError::UnexpectedEof => self.input.len(), - _ => self.input[..end].char_indices().next_back().unwrap().0, - }; - self.error(err_pos, e) - }) - } - fn parse_str( it: &mut str::Chars<'a>, allow_confusing_unicode: bool, @@ -826,84 +870,212 @@ impl<'a> Lexer<'a> { } } - /// Returns the current position of our iterator through the input string - fn cur(&self) -> usize { - self.input.len() - self.remaining.len() - } - /// Creates an error at `pos` with the specified `kind` fn error(&self, pos: usize, kind: LexError) -> Error { Error::lex(Span { offset: pos }, self.input, kind) } -} -impl<'a> Iterator for Lexer<'a> { - type Item = Result, Error>; + /// Returns an iterator over all tokens in the original source string + /// starting at the `pos` specified. + pub fn iter(&self, mut pos: usize) -> impl Iterator> + '_ { + std::iter::from_fn(move || self.parse(&mut pos).transpose()) + } - fn next(&mut self) -> Option { - self.parse().transpose() + /// Returns whether an annotation is present at `pos` and the name of the + /// annotation. + pub fn annotation(&self, mut pos: usize) -> Option<&'a str> { + let bytes = self.input.as_bytes(); + // Quickly reject anything that for sure isn't an annotation since this + // method is used every time an lparen is parsed. + if bytes.get(pos) != Some(&b'@') { + return None; + } + match self.parse(&mut pos) { + Ok(Some(token)) => { + match token.kind { + TokenKind::Reserved => {} + _ => return None, + } + if token.len == 1 { + None // just the `@` character isn't a valid annotation + } else { + Some(&token.src(self.input)[1..]) + } + } + Ok(None) | Err(_) => None, + } } } -impl<'a> Token<'a> { +impl Token { /// Returns the original source text for this token. - pub fn src(&self) -> &'a str { - match self { - Token::Whitespace(s) => s, - Token::BlockComment(s) => s, - Token::LineComment(s) => s, - Token::LParen(s) => s, - Token::RParen(s) => s, - Token::String(s) => s.src(), - Token::Id(s) => s, - Token::Keyword(s) => s, - Token::Reserved(s) => s, - Token::Integer(i) => i.src(), - Token::Float(f) => f.src(), - } + pub fn src<'a>(&self, s: &'a str) -> &'a str { + &s[self.offset..][..self.len.try_into().unwrap()] } -} -impl<'a> Integer<'a> { - /// Returns the sign token for this integer. - pub fn sign(&self) -> Option { - self.0.sign + /// Returns the identifier, without the leading `$` symbol, that this token + /// represents. + /// + /// Should only be used with `TokenKind::Id`. + pub fn id<'a>(&self, s: &'a str) -> &'a str { + &self.src(s)[1..] } - /// Returns the original source text for this integer. - pub fn src(&self) -> &'a str { - self.0.src + /// Returns the keyword this token represents. + /// + /// Should only be used with [`TokenKind::Keyword`]. + pub fn keyword<'a>(&self, s: &'a str) -> &'a str { + self.src(s) } - /// Returns the value string that can be parsed for this integer, as well as - /// the base that it should be parsed in - pub fn val(&self) -> (&str, u32) { - (&self.0.val, if self.0.hex { 16 } else { 10 }) + /// Returns the reserved string this token represents. + /// + /// Should only be used with [`TokenKind::Reserved`]. + pub fn reserved<'a>(&self, s: &'a str) -> &'a str { + self.src(s) } -} -impl<'a> Float<'a> { - /// Returns the original source text for this integer. - pub fn src(&self) -> &'a str { - self.0.src + /// Returns the parsed string that this token represents. + /// + /// This returns either a raw byte slice into the source if that's possible + /// or an owned representation to handle escaped characters and such. + /// + /// Should only be used with [`TokenKind::String`]. + pub fn string<'a>(&self, s: &'a str) -> Cow<'a, [u8]> { + let mut ch = self.src(s).chars(); + ch.next().unwrap(); + Lexer::parse_str(&mut ch, true).unwrap() } - /// Returns a parsed value of this float with all of the components still - /// listed as strings. - pub fn val(&self) -> &FloatVal<'a> { - &self.0.val + /// Returns the decomposed float token that this represents. + /// + /// This will slice up the float token into its component parts and return a + /// description of the float token in the source. + /// + /// Should only be used with [`TokenKind::Float`]. + pub fn float<'a>(&self, s: &'a str, kind: FloatKind) -> Float<'a> { + match kind { + FloatKind::Inf { negative } => Float::Inf { negative }, + FloatKind::Nan { negative } => Float::Nan { + val: None, + negative, + }, + FloatKind::NanVal { + negative, + has_underscores, + } => { + let src = self.src(s); + let src = if src.starts_with("n") { src } else { &src[1..] }; + let mut val = Cow::Borrowed(src.strip_prefix("nan:0x").unwrap()); + if has_underscores { + *val.to_mut() = val.replace("_", ""); + } + Float::Nan { + val: Some(val), + negative, + } + } + FloatKind::Normal { + has_underscores, + hex, + } => { + let src = self.src(s); + let (integral, decimal, exponent) = match src.find('.') { + Some(i) => { + let integral = &src[..i]; + let rest = &src[i + 1..]; + let exponent = if hex { + rest.find('p').or_else(|| rest.find('P')) + } else { + rest.find('e').or_else(|| rest.find('E')) + }; + match exponent { + Some(i) => (integral, Some(&rest[..i]), Some(&rest[i + 1..])), + None => (integral, Some(rest), None), + } + } + None => { + let exponent = if hex { + src.find('p').or_else(|| src.find('P')) + } else { + src.find('e').or_else(|| src.find('E')) + }; + match exponent { + Some(i) => (&src[..i], None, Some(&src[i + 1..])), + None => (src, None, None), + } + } + }; + let mut integral = Cow::Borrowed(integral.strip_prefix('+').unwrap_or(integral)); + let mut decimal = decimal.and_then(|s| { + if s.is_empty() { + None + } else { + Some(Cow::Borrowed(s)) + } + }); + let mut exponent = + exponent.map(|s| Cow::Borrowed(s.strip_prefix('+').unwrap_or(s))); + if has_underscores { + *integral.to_mut() = integral.replace("_", ""); + if let Some(decimal) = &mut decimal { + *decimal.to_mut() = decimal.replace("_", ""); + } + if let Some(exponent) = &mut exponent { + *exponent.to_mut() = exponent.replace("_", ""); + } + } + if hex { + *integral.to_mut() = integral.replace("0x", ""); + } + Float::Val { + hex, + integral, + decimal, + exponent, + } + } + } + } + + /// Returns the decomposed integer token that this represents. + /// + /// This will slice up the integer token into its component parts and + /// return a description of the integer token in the source. + /// + /// Should only be used with [`TokenKind::Integer`]. + pub fn integer<'a>(&self, s: &'a str, kind: IntegerKind) -> Integer<'a> { + let src = self.src(s); + let val = match kind.sign { + Some(SignToken::Plus) => src.strip_prefix('+').unwrap(), + Some(SignToken::Minus) => src, + None => src, + }; + let mut val = Cow::Borrowed(val); + if kind.has_underscores { + *val.to_mut() = val.replace("_", ""); + } + if kind.hex { + *val.to_mut() = val.replace("0x", ""); + } + Integer { + sign: kind.sign, + hex: kind.hex, + val, + } } } -impl<'a> WasmString<'a> { - /// Returns the original source text for this string. - pub fn src(&self) -> &'a str { - self.0.src +impl<'a> Integer<'a> { + /// Returns the sign token for this integer. + pub fn sign(&self) -> Option { + self.sign } - /// Returns a parsed value, as a list of bytes, for this string. - pub fn val(&self) -> &[u8] { - &self.0.val + /// Returns the value string that can be parsed for this integer, as well + /// as the base that it should be parsed in + pub fn val(&self) -> (&str, u32) { + (&self.val, if self.hex { 16 } else { 10 }) } } @@ -986,8 +1158,9 @@ mod tests { #[test] fn ws_smoke() { fn get_whitespace(input: &str) -> &str { - match Lexer::new(input).parse().expect("no first token") { - Some(Token::Whitespace(s)) => s, + let token = get_token(input); + match token.kind { + TokenKind::Whitespace => token.src(input), other => panic!("unexpected {:?}", other), } } @@ -1001,8 +1174,9 @@ mod tests { #[test] fn line_comment_smoke() { fn get_line_comment(input: &str) -> &str { - match Lexer::new(input).parse().expect("no first token") { - Some(Token::LineComment(s)) => s, + let token = get_token(input); + match token.kind { + TokenKind::LineComment => token.src(input), other => panic!("unexpected {:?}", other), } } @@ -1016,8 +1190,9 @@ mod tests { #[test] fn block_comment_smoke() { fn get_block_comment(input: &str) -> &str { - match Lexer::new(input).parse().expect("no first token") { - Some(Token::BlockComment(s)) => s, + let token = get_token(input); + match token.kind { + TokenKind::BlockComment => token.src(input), other => panic!("unexpected {:?}", other), } } @@ -1026,32 +1201,30 @@ mod tests { assert_eq!(get_block_comment("(; (;;) ;)"), "(; (;;) ;)"); } - fn get_token(input: &str) -> Token<'_> { + fn get_token(input: &str) -> Token { Lexer::new(input) - .parse() + .parse(&mut 0) .expect("no first token") .expect("no token") } #[test] fn lparen() { - assert_eq!(get_token("(("), Token::LParen("(")); + assert_eq!(get_token("((").kind, TokenKind::LParen); } #[test] fn rparen() { - assert_eq!(get_token(")("), Token::RParen(")")); + assert_eq!(get_token(")(").kind, TokenKind::RParen); } #[test] fn strings() { fn get_string(input: &str) -> Vec { - match get_token(input) { - Token::String(s) => { - assert_eq!(input, s.src()); - s.val().to_vec() - } - other => panic!("not string {:?}", other), + let token = get_token(input); + match token.kind { + TokenKind::String => token.string(input).to_vec(), + other => panic!("not keyword {:?}", other), } } assert_eq!(&*get_string("\"\""), b""); @@ -1083,25 +1256,27 @@ mod tests { #[test] fn id() { fn get_id(input: &str) -> &str { - match get_token(input) { - Token::Id(s) => s, + let token = get_token(input); + match token.kind { + TokenKind::Id => token.id(input), other => panic!("not id {:?}", other), } } - assert_eq!(get_id("$x"), "$x"); - assert_eq!(get_id("$xyz"), "$xyz"); - assert_eq!(get_id("$x_z"), "$x_z"); - assert_eq!(get_id("$0^"), "$0^"); - assert_eq!(get_id("$0^;;"), "$0^"); - assert_eq!(get_id("$0^ ;;"), "$0^"); + assert_eq!(get_id("$x"), "x"); + assert_eq!(get_id("$xyz"), "xyz"); + assert_eq!(get_id("$x_z"), "x_z"); + assert_eq!(get_id("$0^"), "0^"); + assert_eq!(get_id("$0^;;"), "0^"); + assert_eq!(get_id("$0^ ;;"), "0^"); } #[test] fn keyword() { fn get_keyword(input: &str) -> &str { - match get_token(input) { - Token::Keyword(s) => s, - other => panic!("not id {:?}", other), + let token = get_token(input); + match token.kind { + TokenKind::Keyword => token.keyword(input), + other => panic!("not keyword {:?}", other), } } assert_eq!(get_keyword("x"), "x"); @@ -1114,8 +1289,9 @@ mod tests { #[test] fn reserved() { fn get_reserved(input: &str) -> &str { - match get_token(input) { - Token::Reserved(s) => s, + let token = get_token(input); + match token.kind { + TokenKind::Reserved => token.reserved(input), other => panic!("not reserved {:?}", other), } } @@ -1126,11 +1302,9 @@ mod tests { #[test] fn integer() { fn get_integer(input: &str) -> String { - match get_token(input) { - Token::Integer(i) => { - assert_eq!(input, i.src()); - i.val().0.to_string() - } + let token = get_token(input); + match token.kind { + TokenKind::Integer(i) => token.integer(input, i).val.to_string(), other => panic!("not integer {:?}", other), } } @@ -1147,57 +1321,55 @@ mod tests { #[test] fn float() { - fn get_float(input: &str) -> FloatVal<'_> { - match get_token(input) { - Token::Float(i) => { - assert_eq!(input, i.src()); - i.0.val - } - other => panic!("not reserved {:?}", other), + fn get_float(input: &str) -> Float<'_> { + let token = get_token(input); + match token.kind { + TokenKind::Float(f) => token.float(input, f), + other => panic!("not float {:?}", other), } } assert_eq!( get_float("nan"), - FloatVal::Nan { + Float::Nan { val: None, negative: false }, ); assert_eq!( get_float("-nan"), - FloatVal::Nan { + Float::Nan { val: None, negative: true, }, ); assert_eq!( get_float("+nan"), - FloatVal::Nan { + Float::Nan { val: None, negative: false, }, ); assert_eq!( get_float("+nan:0x1"), - FloatVal::Nan { - val: Some(1), + Float::Nan { + val: Some("1".into()), negative: false, }, ); assert_eq!( get_float("nan:0x7f_ffff"), - FloatVal::Nan { - val: Some(0x7fffff), + Float::Nan { + val: Some("7fffff".into()), negative: false, }, ); - assert_eq!(get_float("inf"), FloatVal::Inf { negative: false }); - assert_eq!(get_float("-inf"), FloatVal::Inf { negative: true }); - assert_eq!(get_float("+inf"), FloatVal::Inf { negative: false }); + assert_eq!(get_float("inf"), Float::Inf { negative: false }); + assert_eq!(get_float("-inf"), Float::Inf { negative: true }); + assert_eq!(get_float("+inf"), Float::Inf { negative: false }); assert_eq!( get_float("1.2"), - FloatVal::Val { + Float::Val { integral: "1".into(), decimal: Some("2".into()), exponent: None, @@ -1206,7 +1378,7 @@ mod tests { ); assert_eq!( get_float("1.2e3"), - FloatVal::Val { + Float::Val { integral: "1".into(), decimal: Some("2".into()), exponent: Some("3".into()), @@ -1215,7 +1387,7 @@ mod tests { ); assert_eq!( get_float("-1_2.1_1E+0_1"), - FloatVal::Val { + Float::Val { integral: "-12".into(), decimal: Some("11".into()), exponent: Some("01".into()), @@ -1224,7 +1396,7 @@ mod tests { ); assert_eq!( get_float("+1_2.1_1E-0_1"), - FloatVal::Val { + Float::Val { integral: "12".into(), decimal: Some("11".into()), exponent: Some("-01".into()), @@ -1233,7 +1405,7 @@ mod tests { ); assert_eq!( get_float("0x1_2.3_4p5_6"), - FloatVal::Val { + Float::Val { integral: "12".into(), decimal: Some("34".into()), exponent: Some("56".into()), @@ -1242,7 +1414,7 @@ mod tests { ); assert_eq!( get_float("+0x1_2.3_4P-5_6"), - FloatVal::Val { + Float::Val { integral: "12".into(), decimal: Some("34".into()), exponent: Some("-56".into()), @@ -1251,7 +1423,7 @@ mod tests { ); assert_eq!( get_float("1."), - FloatVal::Val { + Float::Val { integral: "1".into(), decimal: None, exponent: None, @@ -1260,7 +1432,7 @@ mod tests { ); assert_eq!( get_float("0x1p-24"), - FloatVal::Val { + Float::Val { integral: "1".into(), decimal: None, exponent: Some("-24".into()), diff --git a/crates/wast/src/lib.rs b/crates/wast/src/lib.rs index 3d301cca56..5d65df137b 100644 --- a/crates/wast/src/lib.rs +++ b/crates/wast/src/lib.rs @@ -101,7 +101,7 @@ macro_rules! custom_keyword { impl<'a> $crate::parser::Parse<'a> for $name { fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { parser.step(|c| { - if let Some((kw, rest)) = c.keyword() { + if let Some((kw, rest)) = c.keyword()? { if kw == $kw { return Ok(($name(c.cur_span()), rest)); } @@ -112,12 +112,12 @@ macro_rules! custom_keyword { } impl $crate::parser::Peek for $name { - fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { - if let Some((kw, _rest)) = cursor.keyword() { + fn peek(cursor: $crate::parser::Cursor<'_>) -> $crate::parser::Result { + Ok(if let Some((kw, _rest)) = cursor.keyword()? { kw == $kw } else { false - } + }) } fn display() -> &'static str { @@ -168,7 +168,7 @@ macro_rules! custom_reserved { impl<'a> $crate::parser::Parse<'a> for $name { fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { parser.step(|c| { - if let Some((rsv, rest)) = c.reserved() { + if let Some((rsv, rest)) = c.reserved()? { if rsv == $rsv { return Ok(($name(c.cur_span()), rest)); } @@ -179,11 +179,11 @@ macro_rules! custom_reserved { } impl $crate::parser::Peek for $name { - fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { - if let Some((rsv, _rest)) = cursor.reserved() { - rsv == $rsv + fn peek(cursor: $crate::parser::Cursor<'_>) -> Result { + if let Some((rsv, _rest)) = cursor.reserved()? { + Ok(rsv == $rsv) } else { - false + Ok(false) } } @@ -290,7 +290,7 @@ macro_rules! custom_reserved { /// fn parse(parser: Parser<'a>) -> Result { /// // and here `peek` works and our delegated parsing works because the /// // annotation has been registered. -/// if parser.peek::() { +/// if parser.peek::()? { /// return Ok(ModuleField::Producer(parser.parse()?)); /// } /// @@ -317,8 +317,8 @@ macro_rules! annotation { impl<'a> $crate::parser::Parse<'a> for $name { fn parse(parser: $crate::parser::Parser<'a>) -> $crate::parser::Result { parser.step(|c| { - if let Some((a, rest)) = c.annotation() { - if a == $annotation { + if let Some((a, rest)) = c.reserved()? { + if a == concat!("@", $annotation) { return Ok(($name(c.cur_span()), rest)); } } @@ -328,12 +328,12 @@ macro_rules! annotation { } impl $crate::parser::Peek for $name { - fn peek(cursor: $crate::parser::Cursor<'_>) -> bool { - if let Some((a, _rest)) = cursor.annotation() { - a == $annotation + fn peek(cursor: $crate::parser::Cursor<'_>) -> $crate::parser::Result { + Ok(if let Some((a, _rest)) = cursor.reserved()? { + a == concat!("@", $annotation) } else { false - } + }) } fn display() -> &'static str { @@ -391,18 +391,23 @@ pub mod kw { custom_keyword!(before); custom_keyword!(binary); custom_keyword!(block); + custom_keyword!(borrow); custom_keyword!(catch); + custom_keyword!(catch_ref); custom_keyword!(catch_all); + custom_keyword!(catch_all_ref); custom_keyword!(code); custom_keyword!(component); custom_keyword!(data); - custom_keyword!(dataref); custom_keyword!(declare); custom_keyword!(delegate); custom_keyword!(r#do = "do"); + custom_keyword!(dtor); custom_keyword!(elem); custom_keyword!(end); custom_keyword!(tag); + custom_keyword!(exn); + custom_keyword!(exnref); custom_keyword!(export); custom_keyword!(r#extern = "extern"); custom_keyword!(externref); @@ -431,6 +436,7 @@ pub mod kw { custom_keyword!(import); custom_keyword!(instance); custom_keyword!(instantiate); + custom_keyword!(interface); custom_keyword!(invoke); custom_keyword!(item); custom_keyword!(last); @@ -440,10 +446,16 @@ pub mod kw { custom_keyword!(modulecode); custom_keyword!(nan_arithmetic = "nan:arithmetic"); custom_keyword!(nan_canonical = "nan:canonical"); + custom_keyword!(nofunc); + custom_keyword!(noextern); + custom_keyword!(none); custom_keyword!(null); + custom_keyword!(nullfuncref); + custom_keyword!(nullexternref); custom_keyword!(nullref); custom_keyword!(offset); custom_keyword!(outer); + custom_keyword!(own); custom_keyword!(param); custom_keyword!(parent); custom_keyword!(passive); @@ -458,11 +470,16 @@ pub mod kw { custom_keyword!(ref_null = "ref.null"); custom_keyword!(register); custom_keyword!(rec); + custom_keyword!(rep); + custom_keyword!(resource); + custom_keyword!(resource_new = "resource.new"); + custom_keyword!(resource_drop = "resource.drop"); + custom_keyword!(resource_rep = "resource.rep"); custom_keyword!(result); custom_keyword!(shared); custom_keyword!(start); - custom_keyword!(r#struct = "struct"); custom_keyword!(sub); + custom_keyword!(r#final = "final"); custom_keyword!(table); custom_keyword!(then); custom_keyword!(r#try = "try"); @@ -490,7 +507,6 @@ pub mod kw { custom_keyword!(tuple); custom_keyword!(list); custom_keyword!(error); - custom_keyword!(union); custom_keyword!(canon); custom_keyword!(lift); custom_keyword!(lower); @@ -498,16 +514,29 @@ pub mod kw { custom_keyword!(string_utf8 = "string-encoding=utf8"); custom_keyword!(string_utf16 = "string-encoding=utf16"); custom_keyword!(string_latin1_utf16 = "string-encoding=latin1+utf16"); + custom_keyword!(r#struct = "struct"); + custom_keyword!(structref); custom_keyword!(realloc); custom_keyword!(post_return = "post-return"); custom_keyword!(with); custom_keyword!(core); custom_keyword!(true_ = "true"); custom_keyword!(false_ = "false"); + custom_keyword!(language); + custom_keyword!(sdk); + custom_keyword!(processed_by = "processed-by"); + custom_keyword!(mem_info = "mem-info"); + custom_keyword!(needed); + custom_keyword!(export_info = "export-info"); + custom_keyword!(import_info = "import-info"); + custom_keyword!(thread); + custom_keyword!(wait); } /// Common annotations used to parse WebAssembly text files. pub mod annotation { annotation!(custom); annotation!(name); + annotation!(producers); + annotation!(dylink_0 = "dylink.0"); } diff --git a/crates/wast/src/names.rs b/crates/wast/src/names.rs index b6cf06f443..547412b36f 100644 --- a/crates/wast/src/names.rs +++ b/crates/wast/src/names.rs @@ -54,7 +54,7 @@ impl<'a> Namespace<'a> { if let Some(_prev) = self.names.insert(name, index) { return Err(Error::new( name.span(), - format!("duplicate identifier for {}", desc), + format!("duplicate identifier `{}` for {}", name.name(), desc), )); } Ok(()) @@ -81,6 +81,6 @@ pub fn resolve_error(id: Id<'_>, ns: &str) -> Error { ); Error::new( id.span(), - format!("failed to find {} named `${}`", ns, id.name()), + format!("unknown {ns}: failed to find name `${}`", id.name()), ) } diff --git a/crates/wast/src/parser.rs b/crates/wast/src/parser.rs index 658fadfcd1..9b1d945aa7 100644 --- a/crates/wast/src/parser.rs +++ b/crates/wast/src/parser.rs @@ -42,7 +42,7 @@ //! // parentheses. The `parens` function here ensures that what we //! // parse inside of it is surrounded by `(` and `)`. //! let mut imports = Vec::new(); -//! while parser.peek2::() { +//! while parser.peek2::()? { //! let import = parser.parens(|p| p.parse())?; //! imports.push(import); //! } @@ -64,9 +64,10 @@ //! This module is heavily inspired by [`syn`](https://docs.rs/syn) so you can //! likely also draw inspiration from the excellent examples in the `syn` crate. -use crate::lexer::{Float, Integer, Lexer, Token}; +use crate::lexer::{Float, Integer, Lexer, Token, TokenKind}; use crate::token::Span; use crate::Error; +use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::fmt; @@ -84,7 +85,7 @@ use std::usize; /// nested items. It would be great to not return an error here, though! pub(crate) const MAX_PARENS_DEPTH: usize = 100; -/// A top-level convenience parseing function that parss a `T` from `buf` and +/// A top-level convenience parsing function that parses a `T` from `buf` and /// requires that all tokens in `buf` are consume. /// /// This generic parsing function can be used to parse any `T` implementing the @@ -120,7 +121,7 @@ pub(crate) const MAX_PARENS_DEPTH: usize = 100; pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result { let parser = buf.parser(); let result = parser.parse()?; - if parser.cursor().advance_token().is_none() { + if parser.cursor().token()?.is_none() { Ok(result) } else { Err(parser.error("extra tokens remaining after parse")) @@ -202,7 +203,7 @@ pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result { /// // parentheses. The `parens` function here ensures that what we /// // parse inside of it is surrounded by `(` and `)`. /// let mut imports = Vec::new(); -/// while parser.peek2::() { +/// while parser.peek2::()? { /// let import = parser.parens(|p| p.parse())?; /// imports.push(import); /// } @@ -243,6 +244,15 @@ pub trait Parse<'a>: Sized { fn parse(parser: Parser<'a>) -> Result; } +impl<'a, T> Parse<'a> for Box +where + T: Parse<'a>, +{ + fn parse(parser: Parser<'a>) -> Result { + Ok(Box::new(parser.parse()?)) + } +} + /// A trait for types which be used to "peek" to see if they're the next token /// in an input stream of [`Parser`]. /// @@ -264,16 +274,16 @@ pub trait Peek { /// Returns `true` if [`Parse`] for this type is highly likely to succeed /// failing no other error conditions happening (like an integer literal /// being too big). - fn peek(cursor: Cursor<'_>) -> bool; + fn peek(cursor: Cursor<'_>) -> Result; /// The same as `peek`, except it checks the token immediately following /// the current token. - fn peek2(mut cursor: Cursor<'_>) -> bool { - if cursor.advance_token().is_some() { - Self::peek(cursor) - } else { - false + fn peek2(mut cursor: Cursor<'_>) -> Result { + match cursor.token()? { + Some(token) => cursor.advance_past(&token), + None => return Ok(false), } + Self::peek(cursor) } /// Returns a human-readable name of this token to display when generating @@ -291,24 +301,30 @@ pub type Result = std::result::Result; /// tokens internally. A `ParseBuffer` only used to pass to the top-level /// [`parse`] function. pub struct ParseBuffer<'a> { - // list of tokens from the tokenized source (including whitespace and - // comments), and the second element is how to skip this token, if it can be - // skipped. - tokens: Box<[(Token<'a>, Cell)]>, - input: &'a str, - cur: Cell, + lexer: Lexer<'a>, + cur: Cell, known_annotations: RefCell>, depth: Cell, + strings: RefCell>>, } -#[derive(Copy, Clone, Debug)] -enum NextTokenAt { - /// Haven't computed where the next token is yet. - Unknown, - /// Previously computed the index of the next token. - Index(usize), - /// There is no next token, this is the last token. - Eof, +/// The current position within a `Lexer` that we're at. This simultaneously +/// stores the byte position that the lexer was last positioned at as well as +/// the next significant token. +/// +/// Note that "significant" here does not mean that `token` is the next token +/// to be lexed at `offset`. Instead it's the next non-whitespace, +/// non-annotation, non-coment token. This simple cache-of-sorts avoids +/// re-parsing tokens the majority of the time, or at least that's the +/// intention. +/// +/// If `token` is set to `None` then it means that either it hasn't been +/// calculated at or the lexer is at EOF. Basically it means go talk to the +/// lexer. +#[derive(Copy, Clone)] +struct Position { + offset: usize, + token: Option, } /// An in-progress parser for the tokens of a WebAssembly text file. @@ -341,7 +357,7 @@ pub struct Lookahead1<'a> { #[derive(Copy, Clone)] pub struct Cursor<'a> { parser: Parser<'a>, - cur: usize, + pos: Position, } impl ParseBuffer<'_> { @@ -360,80 +376,100 @@ impl ParseBuffer<'_> { /// /// Returns an error if `input` fails to lex. pub fn new_with_lexer(lexer: Lexer<'_>) -> Result> { - let mut tokens = Vec::new(); - let input = lexer.input(); - for token in lexer { - tokens.push((token?, Cell::new(NextTokenAt::Unknown))); - } - let ret = ParseBuffer { - tokens: tokens.into_boxed_slice(), - cur: Cell::new(0), + Ok(ParseBuffer { + lexer, depth: Cell::new(0), - input, + cur: Cell::new(Position { + offset: 0, + token: None, + }), known_annotations: Default::default(), - }; - ret.validate_annotations()?; - Ok(ret) + strings: Default::default(), + }) } fn parser(&self) -> Parser<'_> { Parser { buf: self } } - // Validates that all annotations properly parse in that they have balanced - // delimiters. This is required since while parsing we generally skip - // annotations and there's no real opportunity to return a parse error. - fn validate_annotations(&self) -> Result<()> { - use crate::lexer::Token::*; - enum State { - None, - LParen, - Annotation { depth: usize, span: Span }, - } - let mut state = State::None; - for token in self.tokens.iter() { - state = match (&token.0, state) { - // From nothing, a `(` starts the search for an annotation - (LParen(_), State::None) => State::LParen, - // ... otherwise in nothing we alwyas preserve that state. - (_, State::None) => State::None, - - // If the previous state was an `LParen`, we may have an - // annotation if the next keyword is reserved - (Reserved(s), State::LParen) if s.starts_with('@') && !s.is_empty() => { - let offset = self.input_pos(s); - State::Annotation { - span: Span { offset }, - depth: 1, + /// Stores an owned allocation in this `Parser` to attach the lifetime of + /// the vector to `self`. + /// + /// This will return a reference to `s`, but one that's safely rooted in the + /// `Parser`. + fn push_str(&self, s: Vec) -> &[u8] { + let s = Box::from(s); + let ret = &*s as *const [u8]; + self.strings.borrow_mut().push(s); + // This should be safe in that the address of `ret` isn't changing as + // it's on the heap itself. Additionally the lifetime of this return + // value is tied to the lifetime of `self` (nothing is deallocated + // early), so it should be safe to say the two have the same lifetime. + unsafe { &*ret } + } + + /// Lexes the next "significant" token from the `pos` specified. + /// + /// This will skip irrelevant tokens such as whitespace, comments, and + /// unknown annotations. + fn advance_token(&self, mut pos: usize) -> Result> { + let token = loop { + let token = match self.lexer.parse(&mut pos)? { + Some(token) => token, + None => return Ok(None), + }; + match token.kind { + // Always skip whitespace and comments. + TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment => { + continue + } + + // If an lparen is seen then this may be skipped if it's an + // annotation of the form `(@foo ...)`. In this situation + // everything up to and including the closing rparen is skipped. + // + // Note that the annotation is only skipped if it's an unknown + // annotation as known annotations are specifically registered + // as "someone's gonna parse this". + TokenKind::LParen => { + if let Some(annotation) = self.lexer.annotation(pos) { + match self.known_annotations.borrow().get(annotation) { + Some(0) | None => { + self.skip_annotation(&mut pos)?; + continue; + } + Some(_) => {} + } } + break token; } - // ... otherwise anything after an `LParen` kills the lparen - // state. - (_, State::LParen) => State::None, - - // Once we're in an annotation we need to balance parentheses, - // so handle the depth changes. - (LParen(_), State::Annotation { span, depth }) => State::Annotation { - span, - depth: depth + 1, - }, - (RParen(_), State::Annotation { depth: 1, .. }) => State::None, - (RParen(_), State::Annotation { span, depth }) => State::Annotation { - span, - depth: depth - 1, - }, - // ... and otherwise all tokens are allowed in annotations. - (_, s @ State::Annotation { .. }) => s, - }; - } - if let State::Annotation { span, .. } = state { - return Err(Error::new(span, "unclosed annotation".to_string())); - } - Ok(()) + _ => break token, + } + }; + Ok(Some(token)) } - fn input_pos(&self, src: &str) -> usize { - src.as_ptr() as usize - self.input.as_ptr() as usize + fn skip_annotation(&self, pos: &mut usize) -> Result<()> { + let mut depth = 1; + let span = Span { offset: *pos }; + loop { + let token = match self.lexer.parse(pos)? { + Some(token) => token, + None => { + break Err(Error::new(span, "unclosed annotation".to_string())); + } + }; + match token.kind { + TokenKind::LParen => depth += 1, + TokenKind::RParen => { + depth -= 1; + if depth == 0 { + break Ok(()); + } + } + _ => {} + } + } } } @@ -448,18 +484,20 @@ impl<'a> Parser<'a> { /// Note that if `false` is returned there *may* be more comments. Comments /// and whitespace are not considered for whether this parser is empty. pub fn is_empty(self) -> bool { - match self.cursor().advance_token() { - Some(Token::RParen(_)) | None => true, - Some(_) => false, // more tokens to parse! + match self.cursor().token() { + Ok(Some(token)) => matches!(token.kind, TokenKind::RParen), + Ok(None) => true, + Err(_) => false, } } pub(crate) fn has_meaningful_tokens(self) -> bool { - self.buf.tokens[self.cursor().cur..].iter().any(|(t, _)| { - !matches!( - t, - Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_) - ) + self.buf.lexer.iter(0).any(|t| match t { + Ok(token) => !matches!( + token.kind, + TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment + ), + Err(_) => true, }) } @@ -555,7 +593,7 @@ impl<'a> Parser<'a> { /// let min = parser.parse()?; /// /// // ... and then test if there's a second number before parsing - /// let max = if parser.peek::() { + /// let max = if parser.peek::()? { /// Some(parser.parse()?) /// } else { /// None @@ -568,30 +606,29 @@ impl<'a> Parser<'a> { /// /// [spec]: https://webassembly.github.io/spec/core/text/types.html#limits /// [`Limits`]: crate::core::Limits - pub fn peek(self) -> bool { + pub fn peek(self) -> Result { T::peek(self.cursor()) } /// Same as the [`Parser::peek`] method, except checks the next token, not /// the current token. - pub fn peek2(self) -> bool { - let mut cursor = self.cursor(); - if cursor.advance_token().is_some() { - T::peek(cursor) - } else { - false - } + pub fn peek2(self) -> Result { + T::peek2(self.cursor()) } /// Same as the [`Parser::peek2`] method, except checks the next next token, /// not the next token. - pub fn peek3(self) -> bool { + pub fn peek3(self) -> Result { let mut cursor = self.cursor(); - if cursor.advance_token().is_some() && cursor.advance_token().is_some() { - T::peek(cursor) - } else { - false + match cursor.token()? { + Some(token) => cursor.advance_past(&token), + None => return Ok(false), } + match cursor.token()? { + Some(token) => cursor.advance_past(&token), + None => return Ok(false), + } + T::peek(cursor) } /// A helper structure to perform a sequence of `peek` operations and if @@ -628,9 +665,9 @@ impl<'a> Parser<'a> { /// impl<'a> Parse<'a> for Index<'a> { /// fn parse(parser: Parser<'a>) -> Result { /// let mut l = parser.lookahead1(); - /// if l.peek::() { + /// if l.peek::()? { /// Ok(Index::Id(parser.parse()?)) - /// } else if l.peek::() { + /// } else if l.peek::()? { /// Ok(Index::Num(parser.parse()?)) /// } else { /// // produces error message of `expected identifier or u32` @@ -698,14 +735,18 @@ impl<'a> Parser<'a> { self.buf.depth.set(self.buf.depth.get() + 1); let before = self.buf.cur.get(); let res = self.step(|cursor| { - let mut cursor = match cursor.lparen() { + let mut cursor = match cursor.lparen()? { Some(rest) => rest, None => return Err(cursor.error("expected `(`")), }; - cursor.parser.buf.cur.set(cursor.cur); + cursor.parser.buf.cur.set(cursor.pos); let result = f(cursor.parser)?; - cursor.cur = cursor.parser.buf.cur.get(); - match cursor.rparen() { + + // Reset our cursor's state to whatever the current state of the + // parser is. + cursor.pos = cursor.parser.buf.cur.get(); + + match cursor.rparen()? { Some(rest) => Ok((result, rest)), None => Err(cursor.error("expected `)`")), } @@ -737,7 +778,7 @@ impl<'a> Parser<'a> { fn cursor(self) -> Cursor<'a> { Cursor { parser: self, - cur: self.buf.cur.get(), + pos: self.buf.cur.get(), } } @@ -752,7 +793,7 @@ impl<'a> Parser<'a> { F: FnOnce(Cursor<'a>) -> Result<(T, Cursor<'a>)>, { let (result, cursor) = f(self.cursor())?; - self.buf.cur.set(cursor.cur); + self.buf.cur.set(cursor.pos); Ok(result) } @@ -763,11 +804,13 @@ impl<'a> Parser<'a> { /// right location in the input stream, and the `msg` here is arbitrary text /// used to associate with the error and indicate why it was generated. pub fn error(self, msg: impl fmt::Display) -> Error { - self.error_at(self.cursor().cur_span(), &msg) + self.error_at(self.cursor().cur_span(), msg) } - fn error_at(self, span: Span, msg: &dyn fmt::Display) -> Error { - Error::parse(span, self.buf.input, msg.to_string()) + /// Creates an error whose line/column information is pointing at the + /// given span. + pub fn error_at(self, span: Span, msg: impl fmt::Display) -> Error { + Error::parse(span, self.buf.lexer.input(), msg.to_string()) } /// Returns the span of the current token @@ -900,7 +943,7 @@ impl<'a> Parser<'a> { /// // annotation with the parser we known that `peek` methods like /// // this, working on the annotation token, are enabled to ever /// // return `true`. - /// if parser.peek::() { + /// if parser.peek::()? { /// return Ok(ModuleField::Custom(parser.parse()?)); /// } /// @@ -941,9 +984,10 @@ impl<'a> Cursor<'a> { /// /// Does not take into account whitespace or comments. pub fn cur_span(&self) -> Span { - let offset = match self.clone().advance_token() { - Some(t) => self.parser.buf.input_pos(t.src()), - None => self.parser.buf.input.len(), + let offset = match self.token() { + Ok(Some(t)) => t.offset, + Ok(None) => self.parser.buf.lexer.input().len(), + Err(_) => self.pos.offset, }; Span { offset } } @@ -952,16 +996,108 @@ impl<'a> Cursor<'a> { /// /// Does not take into account whitespace or comments. pub(crate) fn prev_span(&self) -> Option { - let (token, _) = self.parser.buf.tokens.get(self.cur.checked_sub(1)?)?; + // TODO Some(Span { - offset: self.parser.buf.input_pos(token.src()), + offset: self.pos.offset, }) + // let (token, _) = self.parser.buf.tokens.get(self.cur.checked_sub(1)?)?; + // Some(Span { + // offset: token.offset, + // }) } /// Same as [`Parser::error`], but works with the current token in this /// [`Cursor`] instead. pub fn error(&self, msg: impl fmt::Display) -> Error { - self.parser.error_at(self.cur_span(), &msg) + self.parser.error_at(self.cur_span(), msg) + } + + /// Tests whether the next token is an lparen + pub fn peek_lparen(self) -> Result { + Ok(matches!( + self.token()?, + Some(Token { + kind: TokenKind::LParen, + .. + }) + )) + } + + /// Tests whether the next token is an rparen + pub fn peek_rparen(self) -> Result { + Ok(matches!( + self.token()?, + Some(Token { + kind: TokenKind::RParen, + .. + }) + )) + } + + /// Tests whether the next token is an id + pub fn peek_id(self) -> Result { + Ok(matches!( + self.token()?, + Some(Token { + kind: TokenKind::Id, + .. + }) + )) + } + + /// Tests whether the next token is reserved + pub fn peek_reserved(self) -> Result { + Ok(matches!( + self.token()?, + Some(Token { + kind: TokenKind::Reserved, + .. + }) + )) + } + + /// Tests whether the next token is a keyword + pub fn peek_keyword(self) -> Result { + Ok(matches!( + self.token()?, + Some(Token { + kind: TokenKind::Keyword, + .. + }) + )) + } + + /// Tests whether the next token is an integer + pub fn peek_integer(self) -> Result { + Ok(matches!( + self.token()?, + Some(Token { + kind: TokenKind::Integer(_), + .. + }) + )) + } + + /// Tests whether the next token is a float + pub fn peek_float(self) -> Result { + Ok(matches!( + self.token()?, + Some(Token { + kind: TokenKind::Float(_), + .. + }) + )) + } + + /// Tests whether the next token is a string + pub fn peek_string(self) -> Result { + Ok(matches!( + self.token()?, + Some(Token { + kind: TokenKind::String, + .. + }) + )) } /// Attempts to advance this cursor if the current token is a `(`. @@ -971,11 +1107,17 @@ impl<'a> Cursor<'a> { /// /// This function will automatically skip over any comments, whitespace, or /// unknown annotations. - pub fn lparen(mut self) -> Option { - match self.advance_token()? { - Token::LParen(_) => Some(self), - _ => None, + pub fn lparen(mut self) -> Result> { + let token = match self.token()? { + Some(token) => token, + None => return Ok(None), + }; + match token.kind { + TokenKind::LParen => {} + _ => return Ok(None), } + self.advance_past(&token); + Ok(Some(self)) } /// Attempts to advance this cursor if the current token is a `)`. @@ -985,11 +1127,17 @@ impl<'a> Cursor<'a> { /// /// This function will automatically skip over any comments, whitespace, or /// unknown annotations. - pub fn rparen(mut self) -> Option { - match self.advance_token()? { - Token::RParen(_) => Some(self), - _ => None, + pub fn rparen(mut self) -> Result> { + let token = match self.token()? { + Some(token) => token, + None => return Ok(None), + }; + match token.kind { + TokenKind::RParen => {} + _ => return Ok(None), } + self.advance_past(&token); + Ok(Some(self)) } /// Attempts to advance this cursor if the current token is a @@ -1001,11 +1149,17 @@ impl<'a> Cursor<'a> { /// /// This function will automatically skip over any comments, whitespace, or /// unknown annotations. - pub fn id(mut self) -> Option<(&'a str, Self)> { - match self.advance_token()? { - Token::Id(id) => Some((&id[1..], self)), - _ => None, + pub fn id(mut self) -> Result> { + let token = match self.token()? { + Some(token) => token, + None => return Ok(None), + }; + match token.kind { + TokenKind::Id => {} + _ => return Ok(None), } + self.advance_past(&token); + Ok(Some((token.id(self.parser.buf.lexer.input()), self))) } /// Attempts to advance this cursor if the current token is a @@ -1017,11 +1171,17 @@ impl<'a> Cursor<'a> { /// /// This function will automatically skip over any comments, whitespace, or /// unknown annotations. - pub fn keyword(mut self) -> Option<(&'a str, Self)> { - match self.advance_token()? { - Token::Keyword(id) => Some((id, self)), - _ => None, + pub fn keyword(mut self) -> Result> { + let token = match self.token()? { + Some(token) => token, + None => return Ok(None), + }; + match token.kind { + TokenKind::Keyword => {} + _ => return Ok(None), } + self.advance_past(&token); + Ok(Some((token.keyword(self.parser.buf.lexer.input()), self))) } /// Attempts to advance this cursor if the current token is a @@ -1033,11 +1193,17 @@ impl<'a> Cursor<'a> { /// /// This function will automatically skip over any comments, whitespace, or /// unknown annotations. - pub fn reserved(mut self) -> Option<(&'a str, Self)> { - match self.advance_token()? { - Token::Reserved(id) => Some((id, self)), - _ => None, + pub fn reserved(mut self) -> Result> { + let token = match self.token()? { + Some(token) => token, + None => return Ok(None), + }; + match token.kind { + TokenKind::Reserved => {} + _ => return Ok(None), } + self.advance_past(&token); + Ok(Some((token.reserved(self.parser.buf.lexer.input()), self))) } /// Attempts to advance this cursor if the current token is a @@ -1049,11 +1215,20 @@ impl<'a> Cursor<'a> { /// /// This function will automatically skip over any comments, whitespace, or /// unknown annotations. - pub fn integer(mut self) -> Option<(&'a Integer<'a>, Self)> { - match self.advance_token()? { - Token::Integer(i) => Some((i, self)), - _ => None, - } + pub fn integer(mut self) -> Result, Self)>> { + let token = match self.token()? { + Some(token) => token, + None => return Ok(None), + }; + let i = match token.kind { + TokenKind::Integer(i) => i, + _ => return Ok(None), + }; + self.advance_past(&token); + Ok(Some(( + token.integer(self.parser.buf.lexer.input(), i), + self, + ))) } /// Attempts to advance this cursor if the current token is a @@ -1065,11 +1240,17 @@ impl<'a> Cursor<'a> { /// /// This function will automatically skip over any comments, whitespace, or /// unknown annotations. - pub fn float(mut self) -> Option<(&'a Float<'a>, Self)> { - match self.advance_token()? { - Token::Float(f) => Some((f, self)), - _ => None, - } + pub fn float(mut self) -> Result, Self)>> { + let token = match self.token()? { + Some(token) => token, + None => return Ok(None), + }; + let f = match token.kind { + TokenKind::Float(f) => f, + _ => return Ok(None), + }; + self.advance_past(&token); + Ok(Some((token.float(self.parser.buf.lexer.input(), f), self))) } /// Attempts to advance this cursor if the current token is a @@ -1081,42 +1262,21 @@ impl<'a> Cursor<'a> { /// /// This function will automatically skip over any comments, whitespace, or /// unknown annotations. - pub fn string(mut self) -> Option<(&'a [u8], Self)> { - match self.advance_token()? { - Token::String(s) => Some((s.val(), self)), - _ => None, - } - } - - /// Attempts to advance this cursor if the current token is a - /// [`Token::Reserved`](crate::lexer::Token) and looks like the start of an - /// annotation. - /// - /// [Annotations][annotation] are a WebAssembly proposal for the text format - /// which allows placing structured text inside of a text file, for example - /// to specify the name section or other custom sections. - /// - /// This function will attempt to see if the current token is the `@foo` - /// part of the annotation. This requires the previous token to be `(` and - /// the current token is `Reserved` which starts with `@` and has a nonzero - /// length for the following name. - /// - /// Note that this will skip *unknown* annoations. Only pre-registered - /// annotations will be returned here. - /// - /// This function will automatically skip over any comments, whitespace, or - /// unknown annotations. - /// - /// [annotation]: https://github.com/WebAssembly/annotations - pub fn annotation(self) -> Option<(&'a str, Self)> { - let (token, cursor) = self.reserved()?; - if !token.starts_with('@') || token.len() <= 1 { - return None; - } - match &self.parser.buf.tokens.get(self.cur.wrapping_sub(1))?.0 { - Token::LParen(_) => Some((&token[1..], cursor)), - _ => None, + pub fn string(mut self) -> Result> { + let token = match self.token()? { + Some(token) => token, + None => return Ok(None), + }; + match token.kind { + TokenKind::String => {} + _ => return Ok(None), } + let string = match token.string(self.parser.buf.lexer.input()) { + Cow::Borrowed(s) => s, + Cow::Owned(s) => self.parser.buf.push_str(s), + }; + self.advance_past(&token); + Ok(Some((string, self))) } /// Attempts to advance this cursor if the current token is a @@ -1124,133 +1284,42 @@ impl<'a> Cursor<'a> { /// [`Token::BlockComment`](crate::lexer::Token) /// /// This function will only skip whitespace, no other tokens. - pub fn comment(mut self) -> Option<(&'a str, Self)> { + pub fn comment(mut self) -> Result> { + let start = self.pos.offset; + self.pos.token = None; let comment = loop { - match &self.parser.buf.tokens.get(self.cur)?.0 { - Token::LineComment(c) | Token::BlockComment(c) => { - self.cur += 1; - break c; + let token = match self.parser.buf.lexer.parse(&mut self.pos.offset)? { + Some(token) => token, + None => return Ok(None), + }; + match token.kind { + TokenKind::LineComment | TokenKind::BlockComment => { + break token.src(self.parser.buf.lexer.input()); } - Token::Whitespace(_) => { - self.cur += 1; + TokenKind::Whitespace => {} + _ => { + self.pos.offset = start; + return Ok(None); } - _ => return None, } }; - Some((comment, self)) + Ok(Some((comment, self))) } - fn advance_token(&mut self) -> Option<&'a Token<'a>> { - let known_annotations = self.parser.buf.known_annotations.borrow(); - let is_known_annotation = |name: &str| match known_annotations.get(name) { - Some(0) | None => false, - Some(_) => true, - }; - - loop { - let (token, next) = self.parser.buf.tokens.get(self.cur)?; - - // If we're currently pointing at a token, and it's not the start - // of an annotation, then we return that token and advance - // ourselves to just after that token. - match token { - Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_) => {} - _ => match self.annotation_start() { - Some(n) if !is_known_annotation(n) => {} - _ => { - self.cur += 1; - return Some(token); - } - }, - } - - // ... otherwise we need to skip the current token, and possibly - // more. Here we're skipping whitespace, comments, annotations, etc. - // Basically stuff that's intended to not be that relevant to the - // text format. This is a pretty common operation, though, and we - // may do it multiple times through peeks and such. As a result - // this is somewhat cached. - // - // The `next` field, if "unknown", means we haven't calculated the - // next token. Otherwise it's an index of where to resume searching - // for the next token. - // - // Note that this entire operation happens in a loop (hence the - // "somewhat cached") because the set of known annotations is - // dynamic and we can't cache which annotations are skipped. What we - // can do though is cache the number of tokens in the annotation so - // we know how to skip ahead of it. - match next.get() { - NextTokenAt::Unknown => match self.find_next() { - Some(i) => { - next.set(NextTokenAt::Index(i)); - self.cur = i; - } - None => { - next.set(NextTokenAt::Eof); - return None; - } - }, - NextTokenAt::Eof => return None, - NextTokenAt::Index(i) => self.cur = i, - } + fn token(&self) -> Result> { + match self.pos.token { + Some(token) => Ok(Some(token)), + None => self.parser.buf.advance_token(self.pos.offset), } } - fn annotation_start(&self) -> Option<&'a str> { - match self.parser.buf.tokens.get(self.cur).map(|p| &p.0) { - Some(Token::LParen(_)) => {} - _ => return None, - } - let reserved = match self.parser.buf.tokens.get(self.cur + 1).map(|p| &p.0) { - Some(Token::Reserved(n)) => n, - _ => return None, - }; - if reserved.starts_with('@') && reserved.len() > 1 { - Some(&reserved[1..]) - } else { - None - } - } - - /// Finds the next "real" token from the current position onwards. - /// - /// This is a somewhat expensive operation to call quite a lot, so it's - /// cached in the token list. See the comment above in `advance_token` for - /// how this works. - /// - /// Returns the index of the next relevant token to parse - fn find_next(mut self) -> Option { - // If we're pointing to the start of annotation we need to skip it - // in its entirety, so match the parentheses and figure out where - // the annotation ends. - if self.annotation_start().is_some() { - let mut depth = 1; - self.cur += 1; - while depth > 0 { - match &self.parser.buf.tokens.get(self.cur)?.0 { - Token::LParen(_) => depth += 1, - Token::RParen(_) => depth -= 1, - _ => {} - } - self.cur += 1; - } - return Some(self.cur); - } - - // ... otherwise we're pointing at whitespace/comments, so we need to - // figure out how many of them we can skip. - loop { - let (token, _) = self.parser.buf.tokens.get(self.cur)?; - // and otherwise we skip all comments/whitespace and otherwise - // get real intersted once a normal `Token` pops up. - match token { - Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_) => { - self.cur += 1 - } - _ => return Some(self.cur), - } - } + fn advance_past(&mut self, token: &Token) { + self.pos.offset = token.offset + (token.len as usize); + self.pos.token = self + .parser + .buf + .advance_token(self.pos.offset) + .unwrap_or(None); } } @@ -1259,13 +1328,13 @@ impl Lookahead1<'_> { /// [`Lookahead1`] references. /// /// For more information see [`Parser::lookahead1`] and [`Parser::peek`] - pub fn peek(&mut self) -> bool { - if self.parser.peek::() { + pub fn peek(&mut self) -> Result { + Ok(if self.parser.peek::()? { true } else { self.attempts.push(T::display()); false - } + }) } /// Generates an error message saying that one of the tokens passed to @@ -1304,7 +1373,7 @@ impl Lookahead1<'_> { impl<'a, T: Peek + Parse<'a>> Parse<'a> for Option { fn parse(parser: Parser<'a>) -> Result> { - if parser.peek::() { + if parser.peek::()? { Ok(Some(parser.parse()?)) } else { Ok(None) diff --git a/crates/wast/src/token.rs b/crates/wast/src/token.rs index 9b5665400c..fef4c73062 100644 --- a/crates/wast/src/token.rs +++ b/crates/wast/src/token.rs @@ -3,7 +3,7 @@ //! contexts too perhaps). use crate::annotation; -use crate::lexer::FloatVal; +use crate::lexer::Float; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use std::fmt; use std::hash::{Hash, Hasher}; @@ -105,7 +105,7 @@ impl<'a> Eq for Id<'a> {} impl<'a> Parse<'a> for Id<'a> { fn parse(parser: Parser<'a>) -> Result { parser.step(|c| { - if let Some((name, rest)) = c.id() { + if let Some((name, rest)) = c.id()? { return Ok((Id::new(name, c.cur_span()), rest)); } Err(c.error("expected an identifier")) @@ -124,8 +124,8 @@ impl fmt::Debug for Id<'_> { } impl Peek for Id<'_> { - fn peek(cursor: Cursor<'_>) -> bool { - cursor.id().is_some() + fn peek(cursor: Cursor<'_>) -> Result { + cursor.peek_id() } fn display() -> &'static str { @@ -167,21 +167,22 @@ impl Index<'_> { impl<'a> Parse<'a> for Index<'a> { fn parse(parser: Parser<'a>) -> Result { - let mut l = parser.lookahead1(); - if l.peek::() { + if parser.peek::()? { Ok(Index::Id(parser.parse()?)) - } else if l.peek::() { + } else if parser.peek::()? { let (val, span) = parser.parse()?; Ok(Index::Num(val, span)) } else { - Err(l.error()) + Err(parser.error(format!( + "unexpected token, expected an index or an identifier" + ))) } } } impl Peek for Index<'_> { - fn peek(cursor: Cursor<'_>) -> bool { - u32::peek(cursor) || Id::peek(cursor) + fn peek(cursor: Cursor<'_>) -> Result { + Ok(u32::peek(cursor)? || Id::peek(cursor)?) } fn display() -> &'static str { @@ -241,10 +242,10 @@ impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { } impl<'a, K: Peek> Peek for ItemRef<'a, K> { - fn peek(cursor: Cursor<'_>) -> bool { - match cursor.lparen() { + fn peek(cursor: Cursor<'_>) -> Result { + match cursor.lparen()? { Some(remaining) => K::peek(remaining), - None => false, + None => Ok(false), } } @@ -270,8 +271,7 @@ impl<'a> Parse<'a> for NameAnnotation<'a> { impl<'a> Parse<'a> for Option> { fn parse(parser: Parser<'a>) -> Result { - let _r = parser.register_annotation("name"); - Ok(if parser.peek2::() { + Ok(if parser.peek2::()? { Some(parser.parens(|p| p.parse())?) } else { None @@ -290,7 +290,7 @@ macro_rules! integers { impl<'a> Parse<'a> for ($i, Span) { fn parse(parser: Parser<'a>) -> Result { parser.step(|c| { - if let Some((i, rest)) = c.integer() { + if let Some((i, rest)) = c.integer()? { let (s, base) = i.val(); let val = $i::from_str_radix(s, base) .or_else(|_| { @@ -311,8 +311,8 @@ macro_rules! integers { } impl Peek for $i { - fn peek(cursor: Cursor<'_>) -> bool { - cursor.integer().is_some() + fn peek(cursor: Cursor<'_>) -> Result { + cursor.peek_integer() } fn display() -> &'static str { @@ -330,7 +330,7 @@ integers! { impl<'a> Parse<'a> for &'a [u8] { fn parse(parser: Parser<'a>) -> Result { parser.step(|c| { - if let Some((i, rest)) = c.string() { + if let Some((i, rest)) = c.string()? { return Ok((i, rest)); } Err(c.error("expected a string")) @@ -339,8 +339,8 @@ impl<'a> Parse<'a> for &'a [u8] { } impl Peek for &'_ [u8] { - fn peek(cursor: Cursor<'_>) -> bool { - cursor.string().is_some() + fn peek(cursor: Cursor<'_>) -> Result { + cursor.peek_string() } fn display() -> &'static str { @@ -350,7 +350,8 @@ impl Peek for &'_ [u8] { impl<'a> Parse<'a> for &'a str { fn parse(parser: Parser<'a>) -> Result { - str::from_utf8(parser.parse()?).map_err(|_| parser.error("malformed UTF-8 encoding")) + str::from_utf8(parser.parse()?) + .map_err(|_| parser.error_at(parser.prev_span(), "malformed UTF-8 encoding")) } } @@ -361,7 +362,7 @@ impl Parse<'_> for String { } impl Peek for &'_ str { - fn peek(cursor: Cursor<'_>) -> bool { + fn peek(cursor: Cursor<'_>) -> Result { <&[u8]>::peek(cursor) } @@ -387,12 +388,12 @@ macro_rules! float { impl<'a> Parse<'a> for $name { fn parse(parser: Parser<'a>) -> Result { parser.step(|c| { - let (val, rest) = if let Some((f, rest)) = c.float() { - ($parse(f.val()), rest) - } else if let Some((i, rest)) = c.integer() { + let (val, rest) = if let Some((f, rest)) = c.float()? { + ($parse(&f), rest) + } else if let Some((i, rest)) = c.integer()? { let (s, base) = i.val(); ( - $parse(&FloatVal::Val { + $parse(&Float::Val { hex: base == 16, integral: s.into(), decimal: None, @@ -411,7 +412,7 @@ macro_rules! float { } } - fn $parse(val: &FloatVal<'_>) -> Option<$int> { + fn $parse(val: &Float<'_>) -> Option<$int> { // Compute a few well-known constants about the float representation // given the parameters to the macro here. let width = std::mem::size_of::<$int>() * 8; @@ -424,7 +425,7 @@ macro_rules! float { let (hex, integral, decimal, exponent_str) = match val { // Infinity is when the exponent bits are all set and // the significand is zero. - FloatVal::Inf { negative } => { + Float::Inf { negative } => { let exp_bits = (1 << $exp_bits) - 1; let neg_bit = *negative as $int; return Some( @@ -436,10 +437,13 @@ macro_rules! float { // NaN is when the exponent bits are all set and // the significand is nonzero. The default of NaN is // when only the highest bit of the significand is set. - FloatVal::Nan { negative, val } => { + Float::Nan { negative, val } => { let exp_bits = (1 << $exp_bits) - 1; let neg_bit = *negative as $int; - let signif = val.unwrap_or(1 << (signif_bits - 1)) as $int; + let signif = match val { + Some(val) => $int::from_str_radix(val,16).ok()?, + None => 1 << (signif_bits - 1), + }; // If the significand is zero then this is actually infinity // so we fail to parse it. if signif & signif_mask == 0 { @@ -453,7 +457,7 @@ macro_rules! float { } // This is trickier, handle this below - FloatVal::Val { hex, integral, decimal, exponent } => { + Float::Val { hex, integral, decimal, exponent } => { (hex, integral, decimal, exponent) } }; @@ -644,8 +648,8 @@ pub struct LParen { } impl Peek for LParen { - fn peek(cursor: Cursor<'_>) -> bool { - cursor.lparen().is_some() + fn peek(cursor: Cursor<'_>) -> Result { + cursor.peek_lparen() } fn display() -> &'static str { @@ -662,7 +666,7 @@ mod tests { ($a:tt p $e:tt) => (f!(@mk $a, None, Some($e.into()))); ($a:tt . $b:tt) => (f!(@mk $a, Some($b.into()), None)); ($a:tt . $b:tt p $e:tt) => (f!(@mk $a, Some($b.into()), Some($e.into()))); - (@mk $a:tt, $b:expr, $e:expr) => (crate::lexer::FloatVal::Val { + (@mk $a:tt, $b:expr, $e:expr) => (crate::lexer::Float::Val { hex: true, integral: $a.into(), decimal: $b, diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs index ec589e59d6..5e18f517d0 100644 --- a/crates/wast/src/wast.rs +++ b/crates/wast/src/wast.rs @@ -22,7 +22,7 @@ impl<'a> Parse<'a> for Wast<'a> { // If it looks like a directive token is in the stream then we parse a // bunch of directives, otherwise assume this is an inline module. - if parser.peek2::() { + if parser.peek2::()? { while !parser.is_empty() { directives.push(parser.parens(|p| p.parse())?); } @@ -37,16 +37,16 @@ impl<'a> Parse<'a> for Wast<'a> { struct WastDirectiveToken; impl Peek for WastDirectiveToken { - fn peek(cursor: Cursor<'_>) -> bool { - let kw = match cursor.keyword() { + fn peek(cursor: Cursor<'_>) -> Result { + let kw = match cursor.keyword()? { Some((kw, _)) => kw, - None => return false, + None => return Ok(false), }; - kw.starts_with("assert_") + Ok(kw.starts_with("assert_") || kw == "module" || kw == "component" || kw == "register" - || kw == "invoke" + || kw == "invoke") } fn display() -> &'static str { @@ -102,6 +102,11 @@ pub enum WastDirective<'a> { span: Span, exec: WastExecute<'a>, }, + Thread(WastThread<'a>), + Wait { + span: Span, + thread: Id<'a>, + }, } impl WastDirective<'_> { @@ -119,8 +124,10 @@ impl WastDirective<'_> { | WastDirective::AssertExhaustion { span, .. } | WastDirective::AssertUnlinkable { span, .. } | WastDirective::AssertInvalid { span, .. } - | WastDirective::AssertException { span, .. } => *span, + | WastDirective::AssertException { span, .. } + | WastDirective::Wait { span, .. } => *span, WastDirective::Invoke(i) => i.span, + WastDirective::Thread(t) => t.span, } } } @@ -128,39 +135,39 @@ impl WastDirective<'_> { impl<'a> Parse<'a> for WastDirective<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() || l.peek::() { + if l.peek::()? || l.peek::()? { Ok(WastDirective::Wat(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(WastDirective::AssertMalformed { span, module: parser.parens(|p| p.parse())?, message: parser.parse()?, }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(WastDirective::AssertInvalid { span, module: parser.parens(|p| p.parse())?, message: parser.parse()?, }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(WastDirective::Register { span, name: parser.parse()?, module: parser.parse()?, }) - } else if l.peek::() { + } else if l.peek::()? { Ok(WastDirective::Invoke(parser.parse()?)) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(WastDirective::AssertTrap { span, exec: parser.parens(|p| p.parse())?, message: parser.parse()?, }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; let exec = parser.parens(|p| p.parse())?; let mut results = Vec::new(); @@ -172,26 +179,34 @@ impl<'a> Parse<'a> for WastDirective<'a> { exec, results, }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(WastDirective::AssertExhaustion { span, call: parser.parens(|p| p.parse())?, message: parser.parse()?, }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(WastDirective::AssertUnlinkable { span, module: parser.parens(parse_wat)?, message: parser.parse()?, }) - } else if l.peek::() { + } else if l.peek::()? { let span = parser.parse::()?.0; Ok(WastDirective::AssertException { span, exec: parser.parens(|p| p.parse())?, }) + } else if l.peek::()? { + Ok(WastDirective::Thread(parser.parse()?)) + } else if l.peek::()? { + let span = parser.parse::()?.0; + Ok(WastDirective::Wait { + span, + thread: parser.parse()?, + }) } else { Err(l.error()) } @@ -212,11 +227,11 @@ pub enum WastExecute<'a> { impl<'a> Parse<'a> for WastExecute<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { + if l.peek::()? { Ok(WastExecute::Invoke(parser.parse()?)) - } else if l.peek::() || l.peek::() { + } else if l.peek::()? || l.peek::()? { Ok(WastExecute::Wat(parse_wat(parser)?)) - } else if l.peek::() { + } else if l.peek::()? { parser.parse::()?; Ok(WastExecute::Get { module: parser.parse()?, @@ -235,7 +250,7 @@ fn parse_wat(parser: Parser) -> Result { // the parens. Instead we can skip the sugar that `Wat` has for simply a // list of fields (no `(module ...)` container) and just parse the `Module` // itself. - if parser.peek::() { + if parser.peek::()? { Ok(Wat::Component(parser.parse()?)) } else { Ok(Wat::Module(parser.parse()?)) @@ -308,8 +323,8 @@ impl QuoteWat<'_> { impl<'a> Parse<'a> for QuoteWat<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek2::() { - let ctor = if parser.peek::() { + if parser.peek2::()? { + let ctor = if parser.peek::()? { parser.parse::()?; QuoteWat::QuoteComponent } else { @@ -339,7 +354,7 @@ pub enum WastArg<'a> { impl<'a> Parse<'a> for WastArg<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { + if parser.peek::>()? { Ok(WastArg::Core(parser.parse()?)) } else { Ok(WastArg::Component(parser.parse()?)) @@ -356,10 +371,50 @@ pub enum WastRet<'a> { impl<'a> Parse<'a> for WastRet<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { + if parser.peek::>()? { Ok(WastRet::Core(parser.parse()?)) } else { Ok(WastRet::Component(parser.parse()?)) } } } + +#[derive(Debug)] +#[allow(missing_docs)] +pub struct WastThread<'a> { + pub span: Span, + pub name: Id<'a>, + pub shared_module: Option>, + pub directives: Vec>, +} + +impl<'a> Parse<'a> for WastThread<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.depth_check()?; + let span = parser.parse::()?.0; + let name = parser.parse()?; + + let shared_module = if parser.peek2::()? { + let name = parser.parens(|p| { + p.parse::()?; + p.parens(|p| { + p.parse::()?; + p.parse() + }) + })?; + Some(name) + } else { + None + }; + let mut directives = Vec::new(); + while !parser.is_empty() { + directives.push(parser.parens(|p| p.parse())?); + } + Ok(WastThread { + span, + name, + shared_module, + directives, + }) + } +} diff --git a/crates/wast/src/wat.rs b/crates/wast/src/wat.rs index 631bc3d0ed..f74121187d 100644 --- a/crates/wast/src/wat.rs +++ b/crates/wast/src/wat.rs @@ -41,9 +41,11 @@ impl<'a> Parse<'a> for Wat<'a> { } let _r = parser.register_annotation("custom"); - let wat = if parser.peek2::() { + let _r = parser.register_annotation("producers"); + let _r = parser.register_annotation("name"); + let wat = if parser.peek2::()? { Wat::Module(parser.parens(|parser| parser.parse())?) - } else if parser.peek2::() { + } else if parser.peek2::()? { Wat::Component(parser.parens(|parser| parser.parse())?) } else { let fields = ModuleField::parse_remaining(parser)?; diff --git a/crates/wast/tests/annotations.rs b/crates/wast/tests/annotations.rs index b5ec894707..706a392cc1 100644 --- a/crates/wast/tests/annotations.rs +++ b/crates/wast/tests/annotations.rs @@ -9,13 +9,13 @@ fn name_annotations() -> anyhow::Result<()> { Ok(()) } -fn assert_module_name(name: &str, wat: &str) -> anyhow::Result<()> { +fn assert_module_name(expected_name: &str, wat: &str) -> anyhow::Result<()> { let wasm = wat::parse_str(wat)?; let mut found = false; for s in get_name_section(&wasm)? { match s? { - Name::Module(n) => { - assert_eq!(n.get_name()?, name); + Name::Module { name, .. } => { + assert_eq!(name, expected_name); found = true; } _ => {} @@ -40,8 +40,7 @@ fn assert_func_name(name: &str, wat: &str) -> anyhow::Result<()> { for s in get_name_section(&wasm)? { match s? { Name::Function(n) => { - let mut map = n.get_map()?; - let naming = map.read()?; + let naming = n.into_iter().next().unwrap()?; assert_eq!(naming.index, 0); assert_eq!(naming.name, name); found = true; @@ -78,10 +77,14 @@ fn assert_local_name(name: &str, wat: &str) -> anyhow::Result<()> { for s in get_name_section(&wasm)? { match s? { Name::Local(n) => { - let mut reader = n.get_indirect_map()?; - let section = reader.read()?; - let mut map = section.get_map()?; - let naming = map.read()?; + let naming = n + .into_iter() + .next() + .unwrap()? + .names + .into_iter() + .next() + .unwrap()?; assert_eq!(naming.index, 0); assert_eq!(naming.name, name); found = true; @@ -97,7 +100,7 @@ fn get_name_section(wasm: &[u8]) -> anyhow::Result> { for payload in Parser::new(0).parse_all(&wasm) { if let Payload::CustomSection(c) = payload? { if c.name() == "name" { - return Ok(NameSectionReader::new(c.data(), c.data_offset())?); + return Ok(NameSectionReader::new(c.data(), c.data_offset())); } } } diff --git a/crates/wast/tests/comments.rs b/crates/wast/tests/comments.rs index 97252650be..54fa366e4b 100644 --- a/crates/wast/tests/comments.rs +++ b/crates/wast/tests/comments.rs @@ -9,7 +9,7 @@ impl<'a> Parse<'a> for Comments<'a> { let comments = parser.step(|mut cursor| { let mut comments = Vec::new(); loop { - let (comment, c) = match cursor.comment() { + let (comment, c) = match cursor.comment()? { Some(pair) => pair, None => break, }; diff --git a/crates/wast/tests/parse-fail/bad-core-func-alias.wat b/crates/wast/tests/parse-fail/bad-core-func-alias.wat new file mode 100644 index 0000000000..c2ebee5ee9 --- /dev/null +++ b/crates/wast/tests/parse-fail/bad-core-func-alias.wat @@ -0,0 +1,7 @@ +(component + (core module $mod (func (export "fun"))) + (core instance $inst (instantiate $mod)) + (alias core export $inst "fun" (core func $fun1)) + (core func $fun2 (alias core export $inst "fun")) + (core func $fun3 (alias export $inst "fun")) +) diff --git a/crates/wast/tests/parse-fail/bad-core-func-alias.wat.err b/crates/wast/tests/parse-fail/bad-core-func-alias.wat.err new file mode 100644 index 0000000000..b782905f39 --- /dev/null +++ b/crates/wast/tests/parse-fail/bad-core-func-alias.wat.err @@ -0,0 +1,5 @@ +expected keyword `core` + --> tests/parse-fail/bad-core-func-alias.wat:6:27 + | + 6 | (core func $fun3 (alias export $inst "fun")) + | ^ diff --git a/crates/wast/tests/parse-fail/bad-func-alias.wat b/crates/wast/tests/parse-fail/bad-func-alias.wat new file mode 100644 index 0000000000..d558ebbf82 --- /dev/null +++ b/crates/wast/tests/parse-fail/bad-func-alias.wat @@ -0,0 +1,7 @@ +(component + (component $comp) + (instance $inst (instantiate $comp)) + (func $alias1 (alias export $inst "fun")) + (alias export $inst "fun" (func $alias2)) + (alias export $inst "fun" (core func $alias3)) +) diff --git a/crates/wast/tests/parse-fail/bad-func-alias.wat.err b/crates/wast/tests/parse-fail/bad-func-alias.wat.err new file mode 100644 index 0000000000..ff8a8ee3b0 --- /dev/null +++ b/crates/wast/tests/parse-fail/bad-func-alias.wat.err @@ -0,0 +1,5 @@ +unexpected token, expected `module` + --> tests/parse-fail/bad-func-alias.wat:6:37 + | + 6 | (alias export $inst "fun" (core func $alias3)) + | ^ diff --git a/crates/wast/tests/parse-fail/bad-index.wat.err b/crates/wast/tests/parse-fail/bad-index.wat.err index 717d46017b..f380bddec1 100644 --- a/crates/wast/tests/parse-fail/bad-index.wat.err +++ b/crates/wast/tests/parse-fail/bad-index.wat.err @@ -1,4 +1,4 @@ -failed to find label named `$s` +unknown label: failed to find name `$s` --> tests/parse-fail/bad-index.wat:1:18 | 1 | (func br_on_null $s) diff --git a/crates/wat/Cargo.toml b/crates/wat/Cargo.toml index a3db6a1cb7..bd514dbc2d 100644 --- a/crates/wat/Cargo.toml +++ b/crates/wat/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "wat" -version = "1.0.48" +version = "1.0.77" authors = ["Alex Crichton "] -edition = "2021" +edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" readme = "README.md" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wat" @@ -13,4 +13,4 @@ Rust parser for the WebAssembly Text format, WAT """ [dependencies] -wast = { path = '../wast', version = '46.0.0' } +wast = { workspace = true } diff --git a/crates/wat/README.md b/crates/wat/README.md index d9f4e0fe43..07db6174fa 100644 --- a/crates/wat/README.md +++ b/crates/wat/README.md @@ -17,11 +17,10 @@ ## Usage -Add this to your `Cargo.toml`: +Add `wat` to your `Cargo.toml` -```toml -[dependencies] -wat = "1.0" +```sh +$ cargo add wat ``` And then you can parse WAT to binary WebAssembly via: @@ -43,16 +42,16 @@ let wat = r#" let binary = wat::parse_str(wat)?; ``` -## Low-level parsing +## AST Representation -This repository and project also aims to provide low-level parsing support for -the WAT and WAST formats. Effectively, if you've got an s-expression lookalike -that you'd like to parse, you should be able to parse it! +The `wat` crate does not expose an AST as its goal is to provide a +forever-stable interface against the `wast` crate. Using `wat` is suitable when +all you want to do is translate from text-to-binary, for example parsing the +input of a CLI program into the WebAssembly binary format. -The `wat` crate does not support this because it strives to provide strong -API-level stability guarantees, but the `wast` crate has all the -low-level details and is the implementation of the `wast` crate. Be sure to -[check out its `README.md`](../wast/README.md) for more information. +If instead you're interested in working with the AST of a text file or otherwise +adding your own parsing to the text format you'll want to take a look at the +[`wast` crate](../wast/README.md). ## Stability and WebAssembly Features diff --git a/crates/wat/src/lib.rs b/crates/wat/src/lib.rs index f48f0526f4..c16174602e 100644 --- a/crates/wat/src/lib.rs +++ b/crates/wat/src/lib.rs @@ -216,9 +216,9 @@ pub fn parse_str(wat: impl AsRef) -> Result> { } fn _parse_str(wat: &str) -> Result> { - let buf = ParseBuffer::new(&wat).map_err(|e| Error::cvt(e, wat))?; + let buf = ParseBuffer::new(wat).map_err(|e| Error::cvt(e, wat))?; let mut ast = parser::parse::(&buf).map_err(|e| Error::cvt(e, wat))?; - Ok(ast.encode().map_err(|e| Error::cvt(e, wat))?) + ast.encode().map_err(|e| Error::cvt(e, wat)) } /// A convenience type definition for `Result` where the error is [`Error`] @@ -287,7 +287,7 @@ impl fmt::Display for Error { }, ErrorKind::Io { err, file, .. } => match file { Some(file) => { - write!(f, "failed to read from `{}`: {}", file.display(), err) + write!(f, "failed to read from `{}`", file.display()) } None => err.fmt(f), }, @@ -321,7 +321,7 @@ mod test { let e = parse_file("_does_not_exist_").unwrap_err(); assert!(e .to_string() - .starts_with("failed to read from `_does_not_exist_`: ")); + .starts_with("failed to read from `_does_not_exist_`")); let mut e = parse_bytes("()".as_bytes()).unwrap_err(); e.set_path("foo"); diff --git a/crates/wit-component/Cargo.toml b/crates/wit-component/Cargo.toml new file mode 100644 index 0000000000..a8d6f79d26 --- /dev/null +++ b/crates/wit-component/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "wit-component" +authors = ["Peter Huene "] +version = "0.15.0" +edition.workspace = true +license = "Apache-2.0 WITH LLVM-exception" +readme = "README.md" +repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component" +homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component" +documentation = "https://docs.rs/wit-component" +description = """ +Tooling for working with `*.wit` and component files together. +""" + +[dependencies] +wasmparser = { workspace = true } +wasm-encoder = { workspace = true } +wasm-metadata = { workspace = true } +wit-parser = { workspace = true } +anyhow = { workspace = true } +log = "0.4.17" +bitflags = "2.3.3" +indexmap = { workspace = true } +wast = { workspace = true, optional = true } +wat = { workspace = true, optional = true } +serde = { workspace = true } +serde_derive = { workspace = true } +serde_json = { workspace = true } + +[dev-dependencies] +wasmprinter = { workspace = true } +glob = "0.3.0" +pretty_assertions = "1.3.0" +env_logger = { workspace = true } +wat = { workspace = true } + +[target.'cfg(not(target_family = "wasm"))'.dev-dependencies] +wasmtime = { workspace = true } + +[features] +dummy-module = ['dep:wat'] +wat = ['dep:wast', 'dep:wat'] diff --git a/crates/wit-component/README.md b/crates/wit-component/README.md new file mode 100644 index 0000000000..38ff08112c --- /dev/null +++ b/crates/wit-component/README.md @@ -0,0 +1,95 @@ +# `wit-component` + +`wit-component` is a crate for creating and interacting with WebAssembly +components based on the [component model proposal][model]. + +## CLI usage + +The `wit-component` crate is available through the `wasm-tools` CLI suite under +two subcommands: + +``` +# Create a component from the input core wasm module +$ wasm-tools component new core.wasm -o component.wasm + +# Extract a `*.wit` interface from a component +$ wasm-tools component wit component.wasm +``` + +## Features + +* Creates WebAssembly [component binaries][model] from input core WebAssembly + modules. Input modules communicate with the [canonical ABI] to imported and + exported interfaces described with [`*.wit` files][wit]. The wit interface is + either embedded directly in the core wasm binary. + +* Supports "adapters" which can be used to bridge legacy core WebAssembly + imported functions into [component model][model] functions. Adapters are + themselves core wasm binaries which will be embedded into the final component. + An adapter's exports can be imported by the main core wasm binary and the + adapter can then call component model imports. + +* A [`*.wit`][wit] interface can be extracted from an existing component to + see the interface that it exports and intends to import. + +[model]: https://github.com/webassembly/component-model +[canonical ABI]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md +[wit]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md + +## Usage + +Note that this crate is intended to be a low-level detail of tooling for +components. Developers will not necessarily interact with this tooling +day-to-day, instead using wrappers such as +[`cargo-component`](https://github.com/bytecodealliance/cargo-component) which +will automatically execute `wit-component` to produce component binaries. + +First `wit-component` supports the wasm-based encoding of a WIT package: + +```sh +$ cat demo.wit +interface host { + hello: func() +} +default world demo { + import host: self.host +} + +$ wasm-tools component wit demo.wit -o demo.wasm --wasm + +# The output `demo.wasm` is a valid component binary +$ wasm-tools validate --features component-model demo.wasm +$ wasm-tools print demo.wasm + +# The `*.wit` file can be recovered from the `demo.wasm` as well +$ wasm-tools component wit demo.wasm +``` + +Toolchain authors can use `wit-component` to embed this component types section +into a core wasm binary. For a small demo here a raw `*.wat` wasm text file will +be used where the `demo.wit` argument is specified manually, however. + +```sh +$ cat demo.core.wat +(module + (import "host" "hello" (func)) +) + +$ wasm-tools component embed demo.wit --world demo demo.core.wat -o demo.wasm + +# See that there's a new `component-type` custom section +$ wasm-tools objdump demo.wasm + +# Convert the core wasm into a component now +$ wasm-tools component new demo.wasm -o demo.component.wasm + +# Like before the output `demo.wasm` is a valid component binary +$ wasm-tools validate --features component-model demo.component.wasm +$ wasm-tools print demo.component.wasm + +# Additionally like before the `*.wit` interface can still be extracted +$ wasm-tools component wit demo.component.wasm +``` + +Here the `demo.component.wasm` can now be shipped to a component runtime or +embedded into hosts. diff --git a/crates/wit-component/src/decoding.rs b/crates/wit-component/src/decoding.rs new file mode 100644 index 0000000000..8fc5ca21c3 --- /dev/null +++ b/crates/wit-component/src/decoding.rs @@ -0,0 +1,1421 @@ +use anyhow::{anyhow, bail, Context, Result}; +use indexmap::{IndexMap, IndexSet}; +use std::collections::HashMap; +use std::mem; +use wasmparser::{ + names::{KebabName, KebabNameKind}, + types, ComponentExport, ComponentExternName, ComponentExternalKind, ComponentImport, Parser, + Payload, PrimitiveValType, ValidPayload, Validator, WasmFeatures, +}; +use wit_parser::*; + +use crate::encoding::docs::{PackageDocs, PACKAGE_DOCS_SECTION_NAME}; + +/// Represents information about a decoded WebAssembly component. +struct ComponentInfo<'a> { + /// Wasmparser-defined type information learned after a component is fully + /// validated. + types: types::Types, + /// List of all imports and exports from this component. + externs: Vec<(ComponentExternName<'a>, Extern<'a>)>, + /// Decoded package docs + package_docs: Option, +} + +enum Extern<'a> { + Import(ComponentImport<'a>), + Export(ComponentExport<'a>), +} + +impl<'a> ComponentInfo<'a> { + /// Creates a new component info by parsing the given WebAssembly component bytes. + fn new(bytes: &'a [u8]) -> Result { + let mut validator = Validator::new_with_features(WasmFeatures::all()); + let mut externs = Vec::new(); + let mut depth = 1; + let mut types = None; + let mut package_docs = None; + + for payload in Parser::new(0).parse_all(bytes) { + let payload = payload?; + match validator.payload(&payload)? { + ValidPayload::Ok => {} + ValidPayload::Parser(_) => depth += 1, + ValidPayload::End(t) => { + depth -= 1; + if depth == 0 { + types = Some(t); + } + } + ValidPayload::Func(..) => {} + } + + match payload { + Payload::ComponentImportSection(s) if depth == 1 => { + for import in s { + let import = import?; + externs.push((import.name, Extern::Import(import))); + } + } + Payload::ComponentExportSection(s) if depth == 1 => { + for export in s { + let export = export?; + externs.push((export.name, Extern::Export(export))); + } + } + Payload::CustomSection(s) if s.name() == PACKAGE_DOCS_SECTION_NAME => { + if package_docs.is_some() { + bail!("multiple {PACKAGE_DOCS_SECTION_NAME:?} sections"); + } + package_docs = Some(PackageDocs::decode(s.data())?); + } + _ => {} + } + } + Ok(Self { + types: types.unwrap(), + externs, + package_docs, + }) + } + + fn is_wit_package(&self) -> bool { + // all wit package exports must be component types, and there must be at + // least one + !self.externs.is_empty() + && self.externs.iter().all(|(_, item)| { + let export = match item { + Extern::Export(e) => e, + _ => return false, + }; + match export.kind { + ComponentExternalKind::Type => matches!( + &self.types[self.types.component_type_at(export.index)], + types::Type::Component(_) + ), + _ => false, + } + }) + } + + fn decode_wit_package(&self) -> Result<(Resolve, PackageId)> { + assert!(self.is_wit_package()); + let resolve = Resolve::default(); + let mut decoder = WitPackageDecoder { + resolve, + info: self, + type_map: HashMap::new(), + foreign_packages: Default::default(), + iface_to_package_index: Default::default(), + named_interfaces: Default::default(), + resources: Default::default(), + }; + + let mut pkg = None; + for (name, item) in self.externs.iter() { + let export = match item { + Extern::Export(e) => e, + _ => unreachable!(), + }; + let id = self.types.component_type_at(export.index); + let ty = self.types[id].unwrap_component(); + if pkg.is_some() { + bail!("more than one top-level exported component type found"); + } + let name = KebabName::new(*name, 0).unwrap(); + pkg = Some( + decoder + .decode_package(&name, ty) + .with_context(|| format!("failed to decode document `{name}`"))?, + ); + } + + let pkg = pkg.ok_or_else(|| anyhow!("no exported component type found"))?; + let (mut resolve, package) = decoder.finish(pkg); + if let Some(package_docs) = &self.package_docs { + package_docs.inject(&mut resolve, package)?; + } + Ok((resolve, package)) + } + + fn decode_component(&self) -> Result<(Resolve, WorldId)> { + assert!(!self.is_wit_package()); + let mut resolve = Resolve::default(); + // Note that this name is arbitrarily chosen. We may one day perhaps + // want to encode this in the component binary format itself, but for + // now it shouldn't be an issue to have a defaulted name here. + let world_name = "root"; + let world = resolve.worlds.alloc(World { + name: world_name.to_string(), + docs: Default::default(), + imports: Default::default(), + exports: Default::default(), + package: None, + includes: Default::default(), + include_names: Default::default(), + }); + let mut decoder = WitPackageDecoder { + resolve, + info: self, + type_map: HashMap::new(), + foreign_packages: Default::default(), + iface_to_package_index: Default::default(), + named_interfaces: Default::default(), + resources: Default::default(), + }; + let mut package = Package { + // Similar to `world_name` above this is arbitrarily chosen as it's + // not otherwise encoded in a binary component. This theoretically + // shouldn't cause issues, however. + name: PackageName { + namespace: "root".to_string(), + version: None, + name: "component".to_string(), + }, + docs: Default::default(), + worlds: [(world_name.to_string(), world)].into_iter().collect(), + interfaces: Default::default(), + }; + + for (_name, item) in self.externs.iter() { + match item { + Extern::Import(import) => { + decoder.decode_component_import(import, world, &mut package)? + } + Extern::Export(export) => { + decoder.decode_component_export(export, world, &mut package)? + } + } + } + + let (resolve, _) = decoder.finish(package); + Ok((resolve, world)) + } +} + +/// Result of the [`decode`] function. +pub enum DecodedWasm { + /// The input to [`decode`] was a binary-encoded WIT package. + /// + /// The full resolve graph is here plus the identifier of the package that + /// was encoded. Note that other packages may be within the resolve if this + /// package refers to foreign packages. + WitPackage(Resolve, PackageId), + + /// The input to [`decode`] was a component and its interface is specified + /// by the world here. + Component(Resolve, WorldId), +} + +impl DecodedWasm { + /// Returns the [`Resolve`] for WIT types contained. + pub fn resolve(&self) -> &Resolve { + match self { + DecodedWasm::WitPackage(resolve, _) => resolve, + DecodedWasm::Component(resolve, _) => resolve, + } + } + + /// Returns the main package of what was decoded. + pub fn package(&self) -> PackageId { + match self { + DecodedWasm::WitPackage(_, id) => *id, + DecodedWasm::Component(resolve, world) => resolve.worlds[*world].package.unwrap(), + } + } +} + +/// Decodes an in-memory WebAssembly binary into a WIT [`Resolve`] and +/// associated metadata. +/// +/// The WebAssembly binary provided here can either be a +/// WIT-package-encoded-as-binary or an actual component itself. A [`Resolve`] +/// is always created and the return value indicates which was detected. +pub fn decode(bytes: &[u8]) -> Result { + let info = ComponentInfo::new(bytes)?; + + if info.is_wit_package() { + log::debug!("decoding a WIT package encoded as wasm"); + let (resolve, pkg) = info.decode_wit_package()?; + Ok(DecodedWasm::WitPackage(resolve, pkg)) + } else { + log::debug!("inferring the WIT of a concrete component"); + let (resolve, world) = info.decode_component()?; + Ok(DecodedWasm::Component(resolve, world)) + } +} + +struct WitPackageDecoder<'a> { + resolve: Resolve, + info: &'a ComponentInfo<'a>, + foreign_packages: IndexMap, + iface_to_package_index: HashMap, + named_interfaces: HashMap, + + /// A map which tracks named resources to what their corresponding `TypeId` + /// is. This first layer of key in this map is the owner scope of a + /// resource, more-or-less the `world` or `interface` that it's defined + /// within. The second layer of this map is keyed by name of the resource + /// and points to the actual ID of the resource. + /// + /// This map is populated in `register_type_export`. + resources: HashMap>, + + /// A map from a type id to what it's been translated to. + type_map: HashMap, +} + +impl WitPackageDecoder<'_> { + fn decode_package(&mut self, name: &KebabName, ty: &types::ComponentType) -> Result { + // Process all imports for this package first, where imports are + // importing from remote packages. + for (name, ty) in ty.imports.iter() { + let ty = match ty { + types::ComponentEntityType::Instance(idx) => { + self.info.types[*idx].unwrap_component_instance() + } + _ => bail!("import `{name}` is not an instance"), + }; + self.register_import(name, ty) + .with_context(|| format!("failed to process import `{name}`"))?; + } + + let mut package = Package { + // The name encoded for packages must be of the form `foo:bar/wit` + // where "wit" is just a placeholder for now. The package name in + // this case would be `foo:bar`. + name: match name.kind() { + KebabNameKind::Id { + namespace, + package, + version, + interface, + } if interface.as_str() == "wit" => PackageName { + namespace: namespace.to_string(), + name: package.to_string(), + version, + }, + _ => bail!("package name is not a valid id: {name}"), + }, + docs: Default::default(), + interfaces: Default::default(), + worlds: Default::default(), + }; + + for (name, ty) in ty.exports.iter() { + match ty { + types::ComponentEntityType::Instance(idx) => { + let ty = self.info.types[*idx].unwrap_component_instance(); + self.register_interface(name.as_str(), ty, &mut package) + .with_context(|| format!("failed to process export `{name}`"))?; + } + types::ComponentEntityType::Component(idx) => { + let ty = self.info.types[*idx].unwrap_component(); + self.register_world(name.as_str(), ty, &mut package) + .with_context(|| format!("failed to process export `{name}`"))?; + } + _ => bail!("component export `{name}` is not an instance or component"), + } + } + Ok(package) + } + + fn decode_component_import( + &mut self, + import: &ComponentImport<'_>, + world: WorldId, + package: &mut Package, + ) -> Result<()> { + let name = import.name.as_str(); + log::debug!("decoding component import `{name}`"); + let ty = self + .info + .types + .component_entity_type_of_import(import.name.as_str()) + .unwrap(); + let owner = TypeOwner::World(world); + let (name, item) = match ty { + types::ComponentEntityType::Instance(i) => { + let ty = self.info.types[i].unwrap_component_instance(); + let (name, id) = if name.contains('/') { + let id = self.register_import(name, ty)?; + (WorldKey::Interface(id), id) + } else { + self.register_interface(name, ty, package) + .with_context(|| format!("failed to decode WIT from import `{name}`"))? + }; + (name, WorldItem::Interface(id)) + } + types::ComponentEntityType::Func(i) => { + let ty = self.info.types[i].unwrap_component_func(); + let func = self + .convert_function(name, ty, owner) + .with_context(|| format!("failed to decode function from import `{name}`"))?; + (WorldKey::Name(name.to_string()), WorldItem::Function(func)) + } + types::ComponentEntityType::Type { + referenced, + created, + } => { + let id = self + .register_type_export(name, owner, referenced, created) + .with_context(|| format!("failed to decode type from export `{name}`"))?; + (WorldKey::Name(name.to_string()), WorldItem::Type(id)) + } + // All other imports do not form part of the component's world + _ => return Ok(()), + }; + self.resolve.worlds[world].imports.insert(name, item); + Ok(()) + } + + fn decode_component_export( + &mut self, + export: &ComponentExport<'_>, + world: WorldId, + package: &mut Package, + ) -> Result<()> { + let name = export.name.as_str(); + log::debug!("decoding component export `{name}`"); + let types = &self.info.types; + let ty = types.component_entity_type_of_export(name).unwrap(); + let (name, item) = match ty { + types::ComponentEntityType::Func(i) => { + let ty = types[i].unwrap_component_func(); + let func = self + .convert_function(name, ty, TypeOwner::World(world)) + .with_context(|| format!("failed to decode function from export `{name}`"))?; + + (WorldKey::Name(name.to_string()), WorldItem::Function(func)) + } + types::ComponentEntityType::Instance(i) => { + let ty = types[i].unwrap_component_instance(); + let (name, id) = if name.contains('/') { + let id = self.register_import(name, ty)?; + (WorldKey::Interface(id), id) + } else { + self.register_interface(name, ty, package) + .with_context(|| format!("failed to decode WIT from export `{name}`"))? + }; + (name, WorldItem::Interface(id)) + } + _ => { + bail!("component export `{name}` was not a function or instance") + } + }; + self.resolve.worlds[world].exports.insert(name, item); + Ok(()) + } + + /// Registers that the `name` provided is either imported interface from a + /// foreign package or referencing a previously defined interface in this + /// package. + /// + /// This function will internally ensure that `name` is well-structured and + /// will fill in any information as necessary. For example with a foreign + /// dependency the foreign package structure, types, etc, all need to be + /// created. For a local dependency it's instead ensured that all the types + /// line up with the previous definitions. + fn register_import( + &mut self, + name: &str, + ty: &types::ComponentInstanceType, + ) -> Result { + let (is_local, interface) = match self.named_interfaces.get(name) { + Some(id) => (true, *id), + None => (false, self.extract_dep_interface(name)?), + }; + let owner = TypeOwner::Interface(interface); + for (name, ty) in ty.exports.iter() { + log::debug!("decoding import instance export `{name}`"); + match *ty { + types::ComponentEntityType::Type { + referenced, + created, + } => { + match self.resolve.interfaces[interface] + .types + .get(name.as_str()) + .copied() + { + // If this name is already defined as a type in the + // specified interface then that's ok. For package-local + // interfaces that's expected since the interface was + // fully defined. For remote interfaces it means we're + // using something that was already used elsewhere. In + // both cases continue along. + // + // Notably for the remotely defined case this will also + // walk over the structure of the type and register + // internal wasmparser ids with wit-parser ids. This is + // necessary to ensure that anonymous types like + // `list` defined in original definitions are + // unified with anonymous types when duplicated inside + // of worlds. Overall this prevents, for example, extra + // `list` types from popping up when decoding. This + // is not strictly necessary but assists with + // roundtripping assertions during fuzzing. + Some(id) => { + log::debug!("type already exist"); + match &self.info.types[referenced] { + types::Type::Defined(ty) => self.register_defined(id, ty)?, + types::Type::Resource(_) => {} + _ => unreachable!(), + } + let prev = self.type_map.insert(created, id); + assert!(prev.is_none()); + } + + // If the name is not defined, however, then there's two + // possibilities: + // + // * For package-local interfaces this is an error + // because the package-local interface defined + // everything already and this is referencing + // something that isn't defined. + // + // * For remote interfaces they're never fully declared + // so it's lazily filled in here. This means that the + // view of remote interfaces ends up being the minimal + // slice needed for this resolve, which is what's + // intended. + None => { + if is_local { + bail!("instance type export `{name}` not defined in interface"); + } + let id = self.register_type_export( + name.as_str(), + owner, + referenced, + created, + )?; + let prev = self.resolve.interfaces[interface] + .types + .insert(name.to_string(), id); + assert!(prev.is_none()); + } + } + } + + // This has similar logic to types above where we lazily fill in + // functions for remote dependencies and otherwise assert + // they're already defined for local dependencies. + types::ComponentEntityType::Func(ty) => { + let def = self.info.types[ty].unwrap_component_func(); + if self.resolve.interfaces[interface] + .functions + .contains_key(name.as_str()) + { + // TODO: should ideally verify that function signatures + // match. + continue; + } + if is_local { + bail!("instance function export `{name}` not defined in interface"); + } + let func = self.convert_function(name.as_str(), def, owner)?; + let prev = self.resolve.interfaces[interface] + .functions + .insert(name.to_string(), func); + assert!(prev.is_none()); + } + + _ => bail!("instance type export `{name}` is not a type"), + } + } + + Ok(interface) + } + + fn find_alias(&self, id: types::TypeId) -> Option { + // Consult `type_map` for `referenced` or anything in its + // chain of aliases to determine what it maps to. This may + // bottom out in `None` in the case that this type is + // just now being defined, but this should otherwise follow + // chains of aliases to determine what exactly this was a + // `use` of if it exists. + let mut prev = None; + let mut cur = id; + while prev.is_none() { + prev = self.type_map.get(&cur).copied(); + cur = match self.info.types.peel_alias(cur) { + Some(next) => next, + None => break, + }; + } + prev + } + + /// This will parse the `name_string` as a component model ID string and + /// ensure that there's an `InterfaceId` corresponding to its components. + fn extract_dep_interface(&mut self, name_string: &str) -> Result { + let import_name = if name_string.contains('/') { + ComponentExternName::Interface(name_string) + } else { + ComponentExternName::Kebab(name_string) + }; + let name = KebabName::new(import_name, 0).unwrap(); + let (namespace, name, version, interface) = match name.kind() { + KebabNameKind::Id { + namespace, + package, + version, + interface, + } => (namespace, package, version, interface), + _ => bail!("package name is not a valid id: {name_string}"), + }; + let package_name = PackageName { + name: name.to_string(), + namespace: namespace.to_string(), + version, + }; + // Lazily create a `Package` as necessary, along with the interface. + let package = self + .foreign_packages + .entry(package_name.to_string()) + .or_insert_with(|| Package { + name: package_name.clone(), + docs: Default::default(), + interfaces: Default::default(), + worlds: Default::default(), + }); + let interface = *package + .interfaces + .entry(interface.to_string()) + .or_insert_with(|| { + self.resolve.interfaces.alloc(Interface { + name: Some(interface.to_string()), + docs: Default::default(), + types: IndexMap::default(), + functions: IndexMap::new(), + package: None, + }) + }); + + // Record a mapping of which foreign package this interface belongs to + self.iface_to_package_index.insert( + interface, + self.foreign_packages + .get_full(&package_name.to_string()) + .unwrap() + .0, + ); + Ok(interface) + } + + /// A general-purpose helper function to translate a component instance + /// into a WIT interface. + /// + /// This is one of the main workhorses of this module. This handles + /// interfaces both at the type level, for concrete components, and + /// internally within worlds as well. + /// + /// The `name` provided is the contextual ID or name of the interface. This + /// could be a kebab-name in the case of a world import or export or it can + /// also be an ID. This is used to guide insertion into various maps. + /// + /// The `ty` provided is the actual component type being decoded. + /// + /// The `package` is where to insert the final interface if `name` is an ID + /// meaning it's registered as a named standalone item within the package. + fn register_interface( + &mut self, + name: &str, + ty: &types::ComponentInstanceType, + package: &mut Package, + ) -> Result<(WorldKey, InterfaceId)> { + // If this interface's name is already known then that means this is an + // interface that's both imported and exported. Use `register_import` + // to draw connections between types and this interface's types. + if self.named_interfaces.contains_key(name) { + let id = self.register_import(name, ty)?; + return Ok((WorldKey::Interface(id), id)); + } + + // If this is a bare kebab-name for an interface then the interface's + // listed name is `None` and the name goes out through the key. + // Otherwise this name is extracted from `name` interpreted as an ID. + let interface_name = self.extract_interface_name_from_kebab_name(name)?; + + let mut interface = Interface { + name: interface_name.clone(), + docs: Default::default(), + types: IndexMap::default(), + functions: IndexMap::new(), + package: None, + }; + + let owner = TypeOwner::Interface(self.resolve.interfaces.next_id()); + for (name, ty) in ty.exports.iter() { + match *ty { + types::ComponentEntityType::Type { + referenced, + created, + } => { + let ty = self + .register_type_export(name.as_str(), owner, referenced, created) + .with_context(|| format!("failed to register type export '{name}'"))?; + let prev = interface.types.insert(name.to_string(), ty); + assert!(prev.is_none()); + } + + types::ComponentEntityType::Func(ty) => { + let ty = self.info.types[ty].unwrap_component_func(); + let func = self + .convert_function(name.as_str(), ty, owner) + .with_context(|| format!("failed to convert function '{name}'"))?; + let prev = interface.functions.insert(name.to_string(), func); + assert!(prev.is_none()); + } + _ => bail!("instance type export `{name}` is not a type or function"), + }; + } + let id = self.resolve.interfaces.alloc(interface); + let key = match interface_name { + // If this interface is named then it's part of the package, so + // insert it. Additionally register it in `named_interfaces` so + // further use comes back to this original definition. + Some(interface_name) => { + let prev = package.interfaces.insert(interface_name, id); + assert!(prev.is_none(), "duplicate interface added for {name:?}"); + let prev = self.named_interfaces.insert(name.to_string(), id); + assert!(prev.is_none()); + WorldKey::Interface(id) + } + + // If this interface isn't named then its key is always a + // kebab-name. + None => WorldKey::Name(name.to_string()), + }; + Ok((key, id)) + } + + fn extract_interface_name_from_kebab_name(&self, name: &str) -> Result> { + let import_name = if name.contains('/') { + ComponentExternName::Interface(name) + } else { + ComponentExternName::Kebab(name) + }; + let kebab_name = KebabName::new(import_name, 0); + match kebab_name.as_ref().map(|k| k.kind()) { + Ok(KebabNameKind::Id { interface, .. }) => Ok(Some(interface.to_string())), + Ok(KebabNameKind::Normal(_name)) => Ok(None), + _ => bail!("cannot extract item name from: {name}"), + } + } + + fn register_type_export( + &mut self, + name: &str, + owner: TypeOwner, + referenced: types::TypeId, + created: types::TypeId, + ) -> Result { + let kind = match self.find_alias(referenced) { + // If this `TypeId` points to a type which has + // previously been defined, meaning we're aliasing a + // prior definition. + Some(prev) => { + log::debug!("type export for `{name}` is an alias"); + TypeDefKind::Type(Type::Id(prev)) + } + + // ... or this `TypeId`'s source definition has never + // been seen before, so declare the full type. + None => { + log::debug!("type export for `{name}` is a new type"); + match &self.info.types[referenced] { + types::Type::Defined(ty) => self + .convert_defined(ty) + .context("failed to convert unaliased type")?, + types::Type::Resource(_) => TypeDefKind::Resource, + _ => unreachable!(), + } + } + }; + let ty = self.resolve.types.alloc(TypeDef { + name: Some(name.to_string()), + kind, + docs: Default::default(), + owner, + }); + + // If this is a resource then doubly-register it in `self.resources` so + // the ID allocated here can be looked up via name later on during + // `convert_function`. + if let TypeDefKind::Resource = self.resolve.types[ty].kind { + let prev = self + .resources + .entry(owner) + .or_insert(HashMap::new()) + .insert(name.to_string(), ty); + assert!(prev.is_none()); + } + + let prev = self.type_map.insert(created, ty); + assert!(prev.is_none()); + Ok(ty) + } + + fn register_world( + &mut self, + name: &str, + ty: &types::ComponentType, + package: &mut Package, + ) -> Result { + let name = self + .extract_interface_name_from_kebab_name(name)? + .context("expected world name to have an ID form")?; + let mut world = World { + name: name.clone(), + docs: Default::default(), + imports: Default::default(), + exports: Default::default(), + includes: Default::default(), + include_names: Default::default(), + package: None, + }; + + let owner = TypeOwner::World(self.resolve.worlds.next_id()); + for (name, ty) in ty.imports.iter() { + let (name, item) = match ty { + types::ComponentEntityType::Instance(idx) => { + let ty = self.info.types[*idx].unwrap_component_instance(); + let (name, id) = if name.contains('/') { + // If a name is an interface import then it is either to + // a package-local or foreign interface, and both + // situations are handled in `register_import`. + let id = self.register_import(name, ty)?; + (WorldKey::Interface(id), id) + } else { + // A plain kebab-name indicates an inline interface that + // wasn't declared explicitly elsewhere with a name, and + // `register_interface` will create a new `Interface` + // with no name. + self.register_interface(name, ty, package)? + }; + (name, WorldItem::Interface(id)) + } + types::ComponentEntityType::Type { + created, + referenced, + } => { + let ty = + self.register_type_export(name.as_str(), owner, *referenced, *created)?; + (WorldKey::Name(name.to_string()), WorldItem::Type(ty)) + } + types::ComponentEntityType::Func(idx) => { + let ty = self.info.types[*idx].unwrap_component_func(); + let func = self.convert_function(name.as_str(), ty, owner)?; + (WorldKey::Name(name.to_string()), WorldItem::Function(func)) + } + _ => bail!("component import `{name}` is not an instance, func, or type"), + }; + world.imports.insert(name, item); + } + + for (name, ty) in ty.exports.iter() { + let (name, item) = match ty { + types::ComponentEntityType::Instance(idx) => { + let ty = self.info.types[*idx].unwrap_component_instance(); + let (name, id) = if name.contains('/') { + // Note that despite this being an export this is + // calling `register_import`. With a URL this interface + // must have been previously defined so this will + // trigger the logic of either filling in a remotely + // defined interface or connecting items to local + // definitions of our own interface. + let id = self.register_import(name, ty)?; + (WorldKey::Interface(id), id) + } else { + self.register_interface(name, ty, package)? + }; + (name, WorldItem::Interface(id)) + } + + types::ComponentEntityType::Func(idx) => { + let ty = self.info.types[*idx].unwrap_component_func(); + let func = self.convert_function(name.as_str(), ty, owner)?; + (WorldKey::Name(name.to_string()), WorldItem::Function(func)) + } + + _ => bail!("component export `{name}` is not an instance or function"), + }; + world.exports.insert(name, item); + } + let id = self.resolve.worlds.alloc(world); + let prev = package.worlds.insert(name, id); + assert!(prev.is_none()); + Ok(id) + } + + fn convert_function( + &mut self, + name: &str, + ty: &types::ComponentFuncType, + owner: TypeOwner, + ) -> Result { + let name = KebabName::new(ComponentExternName::Kebab(name), 0).unwrap(); + let params = ty + .params + .iter() + .map(|(name, ty)| Ok((name.to_string(), self.convert_valtype(ty)?))) + .collect::>>() + .context("failed to convert params")?; + let results = if ty.results.len() == 1 && ty.results[0].0.is_none() { + Results::Anon( + self.convert_valtype(&ty.results[0].1) + .context("failed to convert anonymous result type")?, + ) + } else { + Results::Named( + ty.results + .iter() + .map(|(name, ty)| { + Ok(( + name.as_ref().unwrap().to_string(), + self.convert_valtype(ty)?, + )) + }) + .collect::>>() + .context("failed to convert named result types")?, + ) + }; + Ok(Function { + docs: Default::default(), + kind: match name.kind() { + KebabNameKind::Normal(_) => FunctionKind::Freestanding, + KebabNameKind::Constructor(resource) => { + FunctionKind::Constructor(self.resources[&owner][resource.as_str()]) + } + KebabNameKind::Method { resource, .. } => { + FunctionKind::Method(self.resources[&owner][resource.as_str()]) + } + KebabNameKind::Static { resource, .. } => { + FunctionKind::Static(self.resources[&owner][resource.as_str()]) + } + + // Functions shouldn't have ID-based names at this time. + KebabNameKind::Id { .. } => unreachable!(), + }, + + // Note that this name includes "name mangling" such as + // `[method]foo.bar` which is intentional. The `FunctionKind` + // discriminant calculated above indicates how to interpret this + // name. + name: name.to_string(), + params, + results, + }) + } + + fn convert_valtype(&mut self, ty: &types::ComponentValType) -> Result { + let id = match ty { + types::ComponentValType::Primitive(ty) => return Ok(self.convert_primitive(*ty)), + types::ComponentValType::Type(id) => *id, + }; + + // Don't create duplicate types for anything previously created. + if let Some(ret) = self.type_map.get(&id) { + return Ok(Type::Id(*ret)); + } + + // Otherwise create a new `TypeDef` without a name since this is an + // anonymous valtype. Note that this is invalid for some types so return + // errors on those types, but eventually the `bail!` here is + // more-or-less unreachable due to expected validation to be added to + // the component model binary format itself. + let def = self.info.types[id].unwrap_defined(); + let kind = self.convert_defined(def)?; + match &kind { + TypeDefKind::Type(_) + | TypeDefKind::List(_) + | TypeDefKind::Tuple(_) + | TypeDefKind::Option(_) + | TypeDefKind::Result(_) + | TypeDefKind::Handle(_) => {} + + TypeDefKind::Resource + | TypeDefKind::Record(_) + | TypeDefKind::Enum(_) + | TypeDefKind::Variant(_) + | TypeDefKind::Flags(_) + | TypeDefKind::Future(_) + | TypeDefKind::Stream(_) => { + bail!("unexpected unnamed type of kind '{}'", kind.as_str()); + } + TypeDefKind::Unknown => unreachable!(), + } + let ty = self.resolve.types.alloc(TypeDef { + name: None, + docs: Default::default(), + owner: TypeOwner::None, + kind, + }); + let prev = self.type_map.insert(id, ty); + assert!(prev.is_none()); + Ok(Type::Id(ty)) + } + + /// Converts a wasmparser `ComponentDefinedType`, the definition of a type + /// in the component model, to a WIT `TypeDefKind` to get inserted into the + /// types arena by the caller. + fn convert_defined(&mut self, ty: &types::ComponentDefinedType) -> Result { + match ty { + types::ComponentDefinedType::Primitive(t) => { + Ok(TypeDefKind::Type(self.convert_primitive(*t))) + } + + types::ComponentDefinedType::List(t) => { + let t = self.convert_valtype(t)?; + Ok(TypeDefKind::List(t)) + } + + types::ComponentDefinedType::Tuple(t) => { + let types = t + .types + .iter() + .map(|t| self.convert_valtype(t)) + .collect::>()?; + Ok(TypeDefKind::Tuple(Tuple { types })) + } + + types::ComponentDefinedType::Option(t) => { + let t = self.convert_valtype(t)?; + Ok(TypeDefKind::Option(t)) + } + + types::ComponentDefinedType::Result { ok, err } => { + let ok = match ok { + Some(t) => Some(self.convert_valtype(t)?), + None => None, + }; + let err = match err { + Some(t) => Some(self.convert_valtype(t)?), + None => None, + }; + Ok(TypeDefKind::Result(Result_ { ok, err })) + } + + types::ComponentDefinedType::Record(r) => { + let fields = r + .fields + .iter() + .map(|(name, ty)| { + Ok(Field { + name: name.to_string(), + ty: self.convert_valtype(ty).with_context(|| { + format!("failed to convert record field '{name}'") + })?, + docs: Default::default(), + }) + }) + .collect::>()?; + Ok(TypeDefKind::Record(Record { fields })) + } + + types::ComponentDefinedType::Variant(v) => { + let cases = v + .cases + .iter() + .map(|(name, case)| { + if case.refines.is_some() { + bail!("unimplemented support for `refines`"); + } + Ok(Case { + name: name.to_string(), + ty: match &case.ty { + Some(ty) => Some(self.convert_valtype(ty)?), + None => None, + }, + docs: Default::default(), + }) + }) + .collect::>()?; + Ok(TypeDefKind::Variant(Variant { cases })) + } + + types::ComponentDefinedType::Flags(f) => { + let flags = f + .iter() + .map(|name| Flag { + name: name.to_string(), + docs: Default::default(), + }) + .collect(); + Ok(TypeDefKind::Flags(Flags { flags })) + } + + types::ComponentDefinedType::Enum(e) => { + let cases = e + .iter() + .cloned() + .map(|name| EnumCase { + name: name.into(), + docs: Default::default(), + }) + .collect(); + Ok(TypeDefKind::Enum(Enum { cases })) + } + + types::ComponentDefinedType::Own(id) => { + let id = self.type_map[id]; + Ok(TypeDefKind::Handle(Handle::Own(id))) + } + + types::ComponentDefinedType::Borrow(id) => { + let id = self.type_map[id]; + Ok(TypeDefKind::Handle(Handle::Borrow(id))) + } + } + } + + fn convert_primitive(&self, ty: PrimitiveValType) -> Type { + match ty { + PrimitiveValType::U8 => Type::U8, + PrimitiveValType::S8 => Type::S8, + PrimitiveValType::U16 => Type::U16, + PrimitiveValType::S16 => Type::S16, + PrimitiveValType::U32 => Type::U32, + PrimitiveValType::S32 => Type::S32, + PrimitiveValType::U64 => Type::U64, + PrimitiveValType::S64 => Type::S64, + PrimitiveValType::Bool => Type::Bool, + PrimitiveValType::Char => Type::Char, + PrimitiveValType::String => Type::String, + PrimitiveValType::Float32 => Type::Float32, + PrimitiveValType::Float64 => Type::Float64, + } + } + + fn register_defined(&mut self, id: TypeId, def: &types::ComponentDefinedType) -> Result<()> { + Registrar { + types: &self.info.types, + type_map: &mut self.type_map, + resolve: &self.resolve, + } + .defined(id, def) + } + + /// Completes the decoding of this resolve by finalizing all packages into + /// their topological ordering within the returned `Resolve`. + /// + /// Takes the root package as an argument to insert. + fn finish(mut self, package: Package) -> (Resolve, PackageId) { + // Build a topological ordering is then calculated by visiting all the + // transitive dependencies of packages. + let mut order = IndexSet::new(); + for i in 0..self.foreign_packages.len() { + self.visit_package(i, &mut order); + } + + // Using the topological ordering create a temporary map from + // index-in-`foreign_packages` to index-in-`order` + let mut idx_to_pos = vec![0; self.foreign_packages.len()]; + for (pos, idx) in order.iter().enumerate() { + idx_to_pos[*idx] = pos; + } + // .. and then using `idx_to_pos` sort the `foreign_packages` array based + // on the position it's at in the topological ordering + let mut deps = mem::take(&mut self.foreign_packages) + .into_iter() + .enumerate() + .collect::>(); + deps.sort_by_key(|(idx, _)| idx_to_pos[*idx]); + + // .. and finally insert the packages, in their final topological + // ordering, into the returned array. + for (_idx, (_url, pkg)) in deps { + self.insert_package(pkg); + } + + let id = self.insert_package(package); + assert!(self.resolve.worlds.iter().all(|(_, w)| w.package.is_some())); + assert!(self + .resolve + .interfaces + .iter() + .all(|(_, i)| i.package.is_some())); + (self.resolve, id) + } + + fn insert_package(&mut self, package: Package) -> PackageId { + let name = package.name.clone(); + let id = self.resolve.packages.alloc(package); + let prev = self.resolve.package_names.insert(name, id); + assert!(prev.is_none()); + for (_, iface) in self.resolve.packages[id].interfaces.iter() { + self.resolve.interfaces[*iface].package = Some(id); + } + for (_, world) in self.resolve.packages[id].worlds.iter() { + self.resolve.worlds[*world].package = Some(id); + let world = &self.resolve.worlds[*world]; + for (name, item) in world.imports.iter().chain(world.exports.iter()) { + if let WorldKey::Name(_) = name { + if let WorldItem::Interface(iface) = item { + self.resolve.interfaces[*iface].package = Some(id); + } + } + } + } + id + } + + fn visit_package(&self, idx: usize, order: &mut IndexSet) { + if order.contains(&idx) { + return; + } + + let (_name, pkg) = self.foreign_packages.get_index(idx).unwrap(); + let interfaces = pkg.interfaces.values().copied().chain( + pkg.worlds + .values() + .flat_map(|w| { + let world = &self.resolve.worlds[*w]; + world.imports.values().chain(world.exports.values()) + }) + .filter_map(|item| match item { + WorldItem::Interface(id) => Some(*id), + WorldItem::Function(_) | WorldItem::Type(_) => None, + }), + ); + for iface in interfaces { + for dep in self.resolve.interface_direct_deps(iface) { + let dep_idx = self.iface_to_package_index[&dep]; + if dep_idx != idx { + self.visit_package(dep_idx, order); + } + } + } + + assert!(order.insert(idx)); + } +} + +/// Helper type to register the structure of a wasm-defined type against a +/// wit-defined type. +struct Registrar<'a> { + types: &'a types::Types, + type_map: &'a mut HashMap, + resolve: &'a Resolve, +} + +impl Registrar<'_> { + /// Verifies that the wasm structure of `def` matches the wit structure of + /// `id` and recursively registers types. + fn defined(&mut self, id: TypeId, def: &types::ComponentDefinedType) -> Result<()> { + match def { + types::ComponentDefinedType::Primitive(_) => Ok(()), + + types::ComponentDefinedType::List(t) => { + let ty = match &self.resolve.types[id].kind { + TypeDefKind::List(r) => r, + // Note that all cases below have this match and the general + // idea is that once a type is named or otherwise identified + // here there's no need to recurse. The purpose of this + // registrar is to build connections for anonymous types + // that don't otherwise have a name to ensure that they're + // decoded to reuse the same constructs consistently. For + // that reason once something is named we can bail out. + TypeDefKind::Type(Type::Id(_)) => return Ok(()), + _ => bail!("expected a list"), + }; + self.valtype(t, ty) + } + + types::ComponentDefinedType::Tuple(t) => { + let ty = match &self.resolve.types[id].kind { + TypeDefKind::Tuple(r) => r, + TypeDefKind::Type(Type::Id(_)) => return Ok(()), + _ => bail!("expected a tuple"), + }; + if ty.types.len() != t.types.len() { + bail!("mismatched number of tuple fields"); + } + for (a, b) in t.types.iter().zip(ty.types.iter()) { + self.valtype(a, b)?; + } + Ok(()) + } + + types::ComponentDefinedType::Option(t) => { + let ty = match &self.resolve.types[id].kind { + TypeDefKind::Option(r) => r, + TypeDefKind::Type(Type::Id(_)) => return Ok(()), + _ => bail!("expected an option"), + }; + self.valtype(t, ty) + } + + types::ComponentDefinedType::Result { ok, err } => { + let ty = match &self.resolve.types[id].kind { + TypeDefKind::Result(r) => r, + TypeDefKind::Type(Type::Id(_)) => return Ok(()), + _ => bail!("expected a result"), + }; + match (ok, &ty.ok) { + (Some(a), Some(b)) => self.valtype(a, b)?, + (None, None) => {} + _ => bail!("disagreement on result structure"), + } + match (err, &ty.err) { + (Some(a), Some(b)) => self.valtype(a, b)?, + (None, None) => {} + _ => bail!("disagreement on result structure"), + } + Ok(()) + } + + types::ComponentDefinedType::Record(def) => { + let ty = match &self.resolve.types[id].kind { + TypeDefKind::Record(r) => r, + TypeDefKind::Type(Type::Id(_)) => return Ok(()), + _ => bail!("expected a record"), + }; + if def.fields.len() != ty.fields.len() { + bail!("mismatched number of record fields"); + } + for ((name, ty), field) in def.fields.iter().zip(&ty.fields) { + if name.as_str() != field.name { + bail!("mismatched field order"); + } + self.valtype(ty, &field.ty)?; + } + Ok(()) + } + + types::ComponentDefinedType::Variant(def) => { + let ty = match &self.resolve.types[id].kind { + TypeDefKind::Variant(r) => r, + TypeDefKind::Type(Type::Id(_)) => return Ok(()), + _ => bail!("expected a variant"), + }; + if def.cases.len() != ty.cases.len() { + bail!("mismatched number of variant cases"); + } + for ((name, ty), case) in def.cases.iter().zip(&ty.cases) { + if name.as_str() != case.name { + bail!("mismatched case order"); + } + match (&ty.ty, &case.ty) { + (Some(a), Some(b)) => self.valtype(a, b)?, + (None, None) => {} + _ => bail!("disagreement on case type"), + } + } + Ok(()) + } + + // These have no recursive structure so they can bail out. + types::ComponentDefinedType::Flags(_) + | types::ComponentDefinedType::Enum(_) + | types::ComponentDefinedType::Own(_) + | types::ComponentDefinedType::Borrow(_) => Ok(()), + } + } + + fn valtype(&mut self, wasm: &types::ComponentValType, wit: &Type) -> Result<()> { + let wasm = match wasm { + types::ComponentValType::Type(wasm) => *wasm, + types::ComponentValType::Primitive(_wasm) => { + assert!(!matches!(wit, Type::Id(_))); + return Ok(()); + } + }; + let wit = match wit { + Type::Id(id) => *id, + _ => bail!("expected id-based type"), + }; + let prev = match self.type_map.insert(wasm, wit) { + Some(prev) => prev, + None => { + let wasm = self.types[wasm].unwrap_defined(); + return self.defined(wit, wasm); + } + }; + // If `wit` matches `prev` then we've just rediscovered what we already + // knew which is that the `wasm` id maps to the `wit` id. + // + // If, however, `wit` is not equal to `prev` then that's more + // interesting. Consider a component such as: + // + // ```wasm + // (component + // (import (interface "a:b/name") (instance + // (type $l (list string)) + // (type $foo (variant (case "l" $l))) + // (export "foo" (type (eq $foo))) + // )) + // (component $c + // (type $l (list string)) + // (type $bar (variant (case "n" u16) (case "l" $l))) + // (export "bar" (type $bar)) + // (type $foo (variant (case "l" $l))) + // (export "foo" (type $foo)) + // ) + // (instance $i (instantiate $c)) + // (export (interface "a:b/name") (instance $i)) + // ) + // ``` + // + // This roughly corresponds to: + // + // ```wit + // package a:b + // + // interface name { + // variant bar { + // n(u16), + // l(list), + // } + // + // variant foo { + // l(list), + // } + // } + // + // world module { + // import name + // export name + // } + // ``` + // + // In this situation first we'll see the `import` which records type + // information for the `foo` type in `interface name`. Later on the full + // picture of `interface name` becomes apparent with the export of a + // component which has full type information. When walking over this + // first `bar` is seen and its recursive structure. + // + // The problem arises when walking over the `foo` type. In this + // situation the code path we're currently on will be hit because + // there's a preexisting definition of `foo` from the import and it's + // now going to be unified with what we've seen in the export. When + // visiting the `list` case of the `foo` variant this ends up + // being different than the `list` used by the `bar` variant. The + // reason for this is that when visiting `bar` the wasm-defined `(list + // string)` hasn't been seen before so a new type is allocated. Later + // though this same wasm type is unified with the first `(list string)` + // type in the `import`. + // + // All-in-all this ends up meaning that it's possible for `prev` to not + // match `wit`. In this situation it means the decoded WIT interface + // will have duplicate definitions of `list`. This is, + // theoretically, not that big of a problem because the same underlying + // definition is still there and the meaning of the type is the same. + // This can, however, perhaps be a problem for consumers where it's + // assumed that all `list` are equal and there's only one. For + // example a bindings generator for C may assume that `list` + // will only appear once and generate a single name for it, but with two + // different types in play here it may generate two types of the same + // name (or something like that). + // + // For now though this is left for a future refactoring. Fixing this + // issue would require tracking anonymous types during type translation + // so the decoding process for the `bar` export would reuse the + // `list` type created from decoding the `foo` import. That's + // somewhat nontrivial at this time, so it's left for a future + // refactoring. + let _ = prev; + Ok(()) + } +} diff --git a/crates/wit-component/src/dummy.rs b/crates/wit-component/src/dummy.rs new file mode 100644 index 0000000000..25f6d2b706 --- /dev/null +++ b/crates/wit-component/src/dummy.rs @@ -0,0 +1,135 @@ +use wit_parser::abi::{AbiVariant, WasmType}; +use wit_parser::{Function, Resolve, TypeDefKind, TypeId, WorldId, WorldItem}; + +/// Generate a dummy implementation core Wasm module for a given WIT document +pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec { + let world = &resolve.worlds[world]; + let mut wat = String::new(); + wat.push_str("(module\n"); + for (name, import) in world.imports.iter() { + match import { + WorldItem::Function(func) => { + let sig = resolve.wasm_signature(AbiVariant::GuestImport, func); + + wat.push_str(&format!("(import \"$root\" \"{}\" (func", func.name)); + push_tys(&mut wat, "param", &sig.params); + push_tys(&mut wat, "result", &sig.results); + wat.push_str("))\n"); + } + WorldItem::Interface(import) => { + let name = resolve.name_world_key(name); + for (_, func) in resolve.interfaces[*import].functions.iter() { + let sig = resolve.wasm_signature(AbiVariant::GuestImport, func); + + wat.push_str(&format!("(import \"{name}\" \"{}\" (func", func.name)); + push_tys(&mut wat, "param", &sig.params); + push_tys(&mut wat, "result", &sig.results); + wat.push_str("))\n"); + } + for (_, ty) in resolve.interfaces[*import].types.iter() { + push_resource_func_imports(&mut wat, resolve, &name, *ty); + } + } + WorldItem::Type(id) => { + push_resource_func_imports(&mut wat, resolve, "$root", *id); + } + } + } + + // Import any resource-related functions for exports. + for (name, export) in world.exports.iter() { + let export = match export { + WorldItem::Interface(export) => *export, + _ => continue, + }; + let module = format!("[export]{}", resolve.name_world_key(name)); + for (name, ty) in resolve.interfaces[export].types.iter() { + let ty = &resolve.types[*ty]; + match ty.kind { + TypeDefKind::Resource => {} + _ => continue, + } + wat.push_str(&format!( + "\ +(import \"{module}\" \"[resource-drop]{name}\" (func (param i32))) +(import \"{module}\" \"[resource-new]{name}\" (func (param i32) (result i32))) +(import \"{module}\" \"[resource-rep]{name}\" (func (param i32) (result i32))) + " + )); + } + } + + for (name, export) in world.exports.iter() { + match export { + WorldItem::Function(func) => { + push_func(&mut wat, &func.name, resolve, func); + } + WorldItem::Interface(export) => { + let name = resolve.name_world_key(name); + for (_, func) in resolve.interfaces[*export].functions.iter() { + let name = func.core_export_name(Some(&name)); + push_func(&mut wat, &name, resolve, func); + } + + // Feign destructors for any resource that this interface + // exports + for (resource_name, ty) in resolve.interfaces[*export].types.iter() { + let ty = &resolve.types[*ty]; + match ty.kind { + TypeDefKind::Resource => {} + _ => continue, + } + wat.push_str(&format!( + "(func (export \"{name}#[dtor]{resource_name}\") (param i32))" + )); + } + } + WorldItem::Type(_) => {} + } + } + + wat.push_str("(memory (export \"memory\") 0)\n"); + wat.push_str( + "(func (export \"cabi_realloc\") (param i32 i32 i32 i32) (result i32) unreachable)\n", + ); + wat.push_str(")\n"); + + return wat::parse_str(&wat).unwrap(); + + fn push_resource_func_imports(wat: &mut String, resolve: &Resolve, module: &str, ty: TypeId) { + let ty = &resolve.types[ty]; + match ty.kind { + TypeDefKind::Resource => {} + _ => return, + } + let name = ty.name.as_ref().unwrap(); + wat.push_str(&format!("(import \"{module}\" \"[resource-drop]{name}\"")); + wat.push_str(" (func (param i32)))\n"); + } + + fn push_func(wat: &mut String, name: &str, resolve: &Resolve, func: &Function) { + let sig = resolve.wasm_signature(AbiVariant::GuestExport, func); + wat.push_str(&format!("(func (export \"{name}\")")); + push_tys(wat, "param", &sig.params); + push_tys(wat, "result", &sig.results); + wat.push_str(" unreachable)\n"); + } + + fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) { + if params.is_empty() { + return; + } + dst.push_str(" ("); + dst.push_str(desc); + for ty in params { + dst.push(' '); + match ty { + WasmType::I32 => dst.push_str("i32"), + WasmType::I64 => dst.push_str("i64"), + WasmType::F32 => dst.push_str("f32"), + WasmType::F64 => dst.push_str("f64"), + } + } + dst.push(')'); + } +} diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs new file mode 100644 index 0000000000..6a596087bb --- /dev/null +++ b/crates/wit-component/src/encoding.rs @@ -0,0 +1,2097 @@ +//! Support for encoding a core wasm module into a component. +//! +//! This module, at a high level, is tasked with transforming a core wasm +//! module into a component. This will process the imports/exports of the core +//! wasm module and translate between the `wit-parser` AST and the component +//! model binary format, producing a final component which will import +//! `*.wit` defined interfaces and export `*.wit` defined interfaces as well +//! with everything wired up internally according to the canonical ABI and such. +//! +//! This doc block here is not currently 100% complete and doesn't cover the +//! full functionality of this module. +//! +//! # Adapter Modules +//! +//! One feature of this encoding process which is non-obvious is the support for +//! "adapter modules". The general idea here is that historical host API +//! definitions have been around for quite some time, such as +//! `wasi_snapshot_preview1`, but these host API definitions are not compatible +//! with the canonical ABI or component model exactly. These APIs, however, can +//! in most situations be roughly adapted to component-model equivalents. This +//! is where adapter modules come into play, they're converting from some +//! arbitrary API/ABI into a component-model using API. +//! +//! An adapter module is a separately compiled `*.wasm` blob which will export +//! functions matching the desired ABI (e.g. exporting functions matching the +//! `wasi_snapshot_preview1` ABI). The `*.wasm` blob will then import functions +//! in the canonical ABI and internally adapt the exported functions to the +//! imported functions. The encoding support in this module is what wires +//! everything up and makes sure that everything is imported and exported to the +//! right place. Adapter modules currently always use "indirect lowerings" +//! meaning that a shim module is created and provided as the imports to the +//! main core wasm module, and the shim module is "filled in" at a later time +//! during the instantiation process. +//! +//! Adapter modules are not intended to be general purpose and are currently +//! very restrictive, namely: +//! +//! * They must import a linear memory and not define their own linear memory +//! otherwise. In other words they import memory and cannot use multi-memory. +//! * They cannot define any `elem` or `data` segments since otherwise there's +//! no knowledge ahead-of-time of where their data or element segments could +//! go. This means things like no panics, no indirect calls, etc. +//! * If the adapter uses a shadow stack, the global that points to it must be a +//! mutable `i32` named `__stack_pointer`. This stack is automatically +//! allocated with an injected `allocate_stack` function that will either use +//! the main module's `cabi_realloc` export (if present) or `memory.grow`. It +//! allocates only 64KB of stack space, and there is no protection if that +//! overflows. +//! * If the adapter has a global, mutable `i32` named `allocation_state`, it +//! will be used to keep track of stack allocation status and avoid infinite +//! recursion if the main module's `cabi_realloc` function calls back into the +//! adapter. `allocate_stack` will check this global on entry; if it is zero, +//! it will set it to one, then allocate the stack, and finally set it to two. +//! If it is non-zero, `allocate_stack` will do nothing and return immediately +//! (because either the stack has already been allocated or is in the process +//! of being allocated). If the adapter does not have an `allocation_state`, +//! `allocate_stack` will use `memory.grow` to allocate the stack; it will +//! _not_ use the main module's `cabi_realloc` even if it's available. +//! * If the adapter imports a `cabi_realloc` function, and the main module +//! exports one, they'll be linked together via an alias. If the adapter +//! imports such a function but the main module does _not_ export one, we'll +//! synthesize one based on `memory.grow` (which will trap for any size other +//! than 64KB). Note that the main module's `cabi_realloc` function may call +//! back into the adapter before the shadow stack has been allocated. In this +//! case (when `allocation_state` is zero or one), the adapter should return +//! whatever dummy value(s) it can immediately without touching the stack. +//! +//! This means that adapter modules are not meant to be written by everyone. +//! It's assumed that these will be relatively few and far between yet still a +//! crucial part of the transition process from to the component model since +//! otherwise there's no way to run a `wasi_snapshot_preview1` module within the +//! component model. + +use crate::encoding::world::WorldAdapter; +use crate::metadata::{self, Bindgen, ModuleMetadata}; +use crate::validation::{ + ResourceInfo, ValidatedModule, BARE_FUNC_MODULE_NAME, MAIN_MODULE_IMPORT_NAME, + POST_RETURN_PREFIX, +}; +use crate::StringEncoding; +use anyhow::{anyhow, bail, Context, Result}; +use indexmap::{IndexMap, IndexSet}; +use std::collections::HashMap; +use std::hash::Hash; +use wasm_encoder::*; +use wasmparser::{Validator, WasmFeatures}; +use wit_parser::{ + abi::{AbiVariant, WasmSignature, WasmType}, + Function, FunctionKind, InterfaceId, LiveTypes, Resolve, Type, TypeDefKind, TypeId, TypeOwner, + WorldItem, WorldKey, +}; + +const INDIRECT_TABLE_NAME: &str = "$imports"; + +pub mod docs; +mod wit; +pub use wit::{encode, encode_component, encode_world}; + +mod types; +use types::{InstanceTypeEncoder, RootTypeEncoder, ValtypeEncoder}; +mod world; +use world::{ComponentWorld, ImportedInterface, Lowering}; + +fn to_val_type(ty: &WasmType) -> ValType { + match ty { + WasmType::I32 => ValType::I32, + WasmType::I64 => ValType::I64, + WasmType::F32 => ValType::F32, + WasmType::F64 => ValType::F64, + } +} + +bitflags::bitflags! { + /// Options in the `canon lower` or `canon lift` required for a particular + /// function. + #[derive(Copy, Clone, Debug)] + pub struct RequiredOptions: u8 { + /// A memory must be specified, typically the "main module"'s memory + /// export. + const MEMORY = 1 << 0; + /// A `realloc` function must be specified, typically named + /// `cabi_realloc`. + const REALLOC = 1 << 1; + /// A string encoding must be specified, which is always utf-8 for now + /// today. + const STRING_ENCODING = 1 << 2; + } +} + +impl RequiredOptions { + fn for_import(resolve: &Resolve, func: &Function) -> RequiredOptions { + let sig = resolve.wasm_signature(AbiVariant::GuestImport, func); + let mut ret = RequiredOptions::empty(); + // Lift the params and lower the results for imports + ret.add_lift(TypeContents::for_types( + resolve, + func.params.iter().map(|(_, t)| t), + )); + ret.add_lower(TypeContents::for_types(resolve, func.results.iter_types())); + + // If anything is indirect then `memory` will be required to read the + // indirect values. + if sig.retptr || sig.indirect_params { + ret |= RequiredOptions::MEMORY; + } + ret + } + + fn for_export(resolve: &Resolve, func: &Function) -> RequiredOptions { + let sig = resolve.wasm_signature(AbiVariant::GuestExport, func); + let mut ret = RequiredOptions::empty(); + // Lower the params and lift the results for exports + ret.add_lower(TypeContents::for_types( + resolve, + func.params.iter().map(|(_, t)| t), + )); + ret.add_lift(TypeContents::for_types(resolve, func.results.iter_types())); + + // If anything is indirect then `memory` will be required to read the + // indirect values, but if the arguments are indirect then `realloc` is + // additionally required to allocate space for the parameters. + if sig.retptr || sig.indirect_params { + ret |= RequiredOptions::MEMORY; + if sig.indirect_params { + ret |= RequiredOptions::REALLOC; + } + } + ret + } + + fn add_lower(&mut self, types: TypeContents) { + // If lists/strings are lowered into wasm then memory is required as + // usual but `realloc` is also required to allow the external caller to + // allocate space in the destination for the list/string. + if types.contains(TypeContents::LIST) { + *self |= RequiredOptions::MEMORY | RequiredOptions::REALLOC; + } + if types.contains(TypeContents::STRING) { + *self |= RequiredOptions::MEMORY + | RequiredOptions::STRING_ENCODING + | RequiredOptions::REALLOC; + } + } + + fn add_lift(&mut self, types: TypeContents) { + // Unlike for `lower` when lifting a string/list all that's needed is + // memory, since the string/list already resides in memory `realloc` + // isn't needed. + if types.contains(TypeContents::LIST) { + *self |= RequiredOptions::MEMORY; + } + if types.contains(TypeContents::STRING) { + *self |= RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING; + } + } + + fn into_iter( + self, + encoding: StringEncoding, + memory_index: Option, + realloc_index: Option, + ) -> Result> { + #[derive(Default)] + struct Iter { + options: [Option; 3], + current: usize, + count: usize, + } + + impl Iter { + fn push(&mut self, option: CanonicalOption) { + assert!(self.count < self.options.len()); + self.options[self.count] = Some(option); + self.count += 1; + } + } + + impl Iterator for Iter { + type Item = CanonicalOption; + + fn next(&mut self) -> Option { + if self.current == self.count { + return None; + } + let option = self.options[self.current]; + self.current += 1; + option + } + + fn size_hint(&self) -> (usize, Option) { + (self.count - self.current, Some(self.count - self.current)) + } + } + + impl ExactSizeIterator for Iter {} + + let mut iter = Iter::default(); + + if self.contains(RequiredOptions::MEMORY) { + iter.push(CanonicalOption::Memory(memory_index.ok_or_else(|| { + anyhow!("module does not export a memory named `memory`") + })?)); + } + + if self.contains(RequiredOptions::REALLOC) { + iter.push(CanonicalOption::Realloc(realloc_index.ok_or_else( + || anyhow!("module does not export a function named `cabi_realloc`"), + )?)); + } + + if self.contains(RequiredOptions::STRING_ENCODING) { + iter.push(encoding.into()); + } + + Ok(iter) + } +} + +bitflags::bitflags! { + /// Flags about what kinds of types are present within the recursive + /// structure of a type. + struct TypeContents: u8 { + const STRING = 1 << 0; + const LIST = 1 << 1; + } +} + +impl TypeContents { + fn for_types<'a>(resolve: &Resolve, types: impl Iterator) -> Self { + let mut cur = TypeContents::empty(); + for ty in types { + cur |= Self::for_type(resolve, ty); + } + cur + } + + fn for_optional_types<'a>( + resolve: &Resolve, + types: impl Iterator>, + ) -> Self { + Self::for_types(resolve, types.flatten()) + } + + fn for_optional_type(resolve: &Resolve, ty: Option<&Type>) -> Self { + match ty { + Some(ty) => Self::for_type(resolve, ty), + None => Self::empty(), + } + } + + fn for_type(resolve: &Resolve, ty: &Type) -> Self { + match ty { + Type::Id(id) => match &resolve.types[*id].kind { + TypeDefKind::Handle(h) => match h { + wit_parser::Handle::Own(_) => Self::empty(), + wit_parser::Handle::Borrow(_) => Self::empty(), + }, + TypeDefKind::Resource => Self::empty(), + TypeDefKind::Record(r) => Self::for_types(resolve, r.fields.iter().map(|f| &f.ty)), + TypeDefKind::Tuple(t) => Self::for_types(resolve, t.types.iter()), + TypeDefKind::Flags(_) => Self::empty(), + TypeDefKind::Option(t) => Self::for_type(resolve, t), + TypeDefKind::Result(r) => { + Self::for_optional_type(resolve, r.ok.as_ref()) + | Self::for_optional_type(resolve, r.err.as_ref()) + } + TypeDefKind::Variant(v) => { + Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref())) + } + TypeDefKind::Enum(_) => Self::empty(), + TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST, + TypeDefKind::Type(t) => Self::for_type(resolve, t), + TypeDefKind::Future(_) => todo!("encoding for future"), + TypeDefKind::Stream(_) => todo!("encoding for stream"), + TypeDefKind::Unknown => unreachable!(), + }, + Type::String => Self::STRING, + _ => Self::empty(), + } + } +} + +/// State relating to encoding a component. +pub struct EncodingState<'a> { + /// The component being encoded. + component: ComponentBuilder, + /// The index into the core module index space for the inner core module. + /// + /// If `None`, the core module has not been encoded. + module_index: Option, + /// The index into the core instance index space for the inner core module. + /// + /// If `None`, the core module has not been instantiated. + instance_index: Option, + /// The index in the core memory index space for the exported memory. + /// + /// If `None`, then the memory has not yet been aliased. + memory_index: Option, + /// The index in the core function index space for the realloc function. + /// + /// If `None`, then the realloc function has not yet been aliased. + realloc_index: Option, + /// The index of the shim instance used for lowering imports into the core instance. + /// + /// If `None`, then the shim instance how not yet been encoded. + shim_instance_index: Option, + /// The index of the fixups module to instantiate to fill in the lowered imports. + /// + /// If `None`, then a fixup module has not yet been encoded. + fixups_module_index: Option, + + /// A map of named adapter modules and the index that the module was defined + /// at. + adapter_modules: IndexMap<&'a str, u32>, + /// A map of adapter module instances and the index of their instance. + adapter_instances: IndexMap<&'a str, u32>, + /// A map of the index of the aliased realloc function for each adapter + /// module. Note that adapters have two realloc functions, one for imports + /// and one for exports. + adapter_import_reallocs: IndexMap<&'a str, Option>, + adapter_export_reallocs: IndexMap<&'a str, Option>, + + /// Imported instances and what index they were imported as. + imported_instances: IndexMap, + imported_funcs: IndexMap, + exported_instances: IndexMap, + + /// Maps used when translating types to the component model binary format. + /// Note that imports and exports are stored in separate maps since they + /// need fresh hierarchies of types in case the same interface is both + /// imported and exported. + import_type_map: HashMap, + import_func_type_map: HashMap, u32>, + export_type_map: HashMap, + export_func_type_map: HashMap, u32>, + + /// Metadata about the world inferred from the input to `ComponentEncoder`. + info: &'a ComponentWorld<'a>, +} + +impl<'a> EncodingState<'a> { + fn encode_core_modules(&mut self) { + assert!(self.module_index.is_none()); + let idx = self.component.core_module_raw(&self.info.encoder.module); + self.module_index = Some(idx); + + for (name, adapter) in self.info.adapters.iter() { + let add_meta = wasm_metadata::AddMetadata { + name: Some(if adapter.library_info.is_some() { + name.to_string() + } else { + format!("wit-component:adapter:{name}") + }), + ..Default::default() + }; + let wasm = add_meta + .to_wasm(&adapter.wasm) + .expect("core wasm can get name added"); + let idx = self.component.core_module_raw(&wasm); + let prev = self.adapter_modules.insert(name, idx); + assert!(prev.is_none()); + } + } + + fn root_import_type_encoder( + &mut self, + interface: Option, + ) -> RootTypeEncoder<'_, 'a> { + RootTypeEncoder { + state: self, + interface, + import_types: true, + } + } + + fn root_export_type_encoder( + &mut self, + interface: Option, + ) -> RootTypeEncoder<'_, 'a> { + RootTypeEncoder { + state: self, + interface, + import_types: false, + } + } + + fn instance_type_encoder(&mut self, interface: InterfaceId) -> InstanceTypeEncoder<'_, 'a> { + InstanceTypeEncoder { + state: self, + interface, + type_map: Default::default(), + func_type_map: Default::default(), + ty: Default::default(), + } + } + + fn encode_imports(&mut self) -> Result<()> { + let mut has_funcs = false; + for (name, info) in self.info.import_map.iter() { + match name { + Some(name) => self.encode_interface_import(name, info)?, + None => has_funcs = true, + } + } + + let resolve = &self.info.encoder.metadata.resolve; + let world = &resolve.worlds[self.info.encoder.metadata.world]; + for (_name, item) in world.imports.iter() { + if let WorldItem::Type(ty) = item { + self.root_import_type_encoder(None) + .encode_valtype(resolve, &Type::Id(*ty))?; + } + } + + if has_funcs { + let info = &self.info.import_map[&None]; + self.encode_root_import_funcs(info)?; + } + Ok(()) + } + + fn encode_interface_import(&mut self, name: &str, info: &ImportedInterface) -> Result<()> { + let resolve = &self.info.encoder.metadata.resolve; + let interface_id = info.interface.as_ref().unwrap(); + let interface_id = *interface_id; + let interface = &resolve.interfaces[interface_id]; + log::trace!("encoding imports for `{name}` as {:?}", interface_id); + let mut encoder = self.instance_type_encoder(interface_id); + + // First encode all type information + if let Some(live) = encoder.state.info.live_type_imports.get(&interface_id) { + for ty in live { + log::trace!( + "encoding extra type {ty:?} name={:?}", + resolve.types[*ty].name + ); + encoder.encode_valtype(resolve, &Type::Id(*ty))?; + } + } + + // Next encode all required functions from this imported interface + // into the instance type. + for (_, func) in interface.functions.iter() { + if !info.lowerings.contains_key(&func.name) { + continue; + } + log::trace!("encoding function type for `{}`", func.name); + let idx = encoder.encode_func_type(resolve, func)?; + + encoder.ty.export(&func.name, ComponentTypeRef::Func(idx)); + } + + let ty = encoder.ty; + // Don't encode empty instance types since they're not + // meaningful to the runtime of the component anyway. + if ty.is_empty() { + return Ok(()); + } + let instance_type_idx = self.component.type_instance(&ty); + let instance_idx = self + .component + .import(name, ComponentTypeRef::Instance(instance_type_idx)); + let prev = self.imported_instances.insert(interface_id, instance_idx); + assert!(prev.is_none()); + Ok(()) + } + + fn encode_root_import_funcs(&mut self, info: &ImportedInterface) -> Result<()> { + let resolve = &self.info.encoder.metadata.resolve; + let world = self.info.encoder.metadata.world; + for (name, item) in resolve.worlds[world].imports.iter() { + let func = match item { + WorldItem::Function(f) => f, + WorldItem::Interface(_) | WorldItem::Type(_) => continue, + }; + let name = resolve.name_world_key(name); + if !info.lowerings.contains_key(&name) { + continue; + } + log::trace!("encoding function type for `{}`", func.name); + let idx = self + .root_import_type_encoder(None) + .encode_func_type(resolve, func)?; + let func_idx = self.component.import(&name, ComponentTypeRef::Func(idx)); + let prev = self.imported_funcs.insert(name, func_idx); + assert!(prev.is_none()); + } + Ok(()) + } + + fn alias_imported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 { + let ty = &self.info.encoder.metadata.resolve.types[id]; + let name = ty.name.as_ref().expect("type must have a name"); + let instance = self.imported_instances[&interface]; + self.component + .alias_export(instance, name, ComponentExportKind::Type) + } + + fn alias_exported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 { + let ty = &self.info.encoder.metadata.resolve.types[id]; + let name = ty.name.as_ref().expect("type must have a name"); + let instance = self.exported_instances[&interface]; + self.component + .alias_export(instance, name, ComponentExportKind::Type) + } + + fn encode_core_instantiation(&mut self) -> Result<()> { + let info = &self.info.info; + + // Encode a shim instantiation if needed + let shims = self.encode_shim_instantiation(); + + // For each instance import into the main module create a + // pseudo-core-wasm-module via a bag-of-exports. + let mut args = Vec::new(); + for core_wasm_name in info.required_imports.keys() { + let index = self.import_instance_to_lowered_core_instance( + CustomModule::Main, + core_wasm_name, + &shims, + info.metadata, + ); + args.push((*core_wasm_name, ModuleArg::Instance(index))); + } + + // For each adapter module instance imported into the core wasm module + // the appropriate shim is packaged up into a bag-of-exports instance. + // Note that adapter modules currently don't deal with + // indirect-vs-direct lowerings, everything is indirect. + for (adapter, funcs) in info.adapters_required.iter() { + let shim_instance = self + .shim_instance_index + .expect("shim should be instantiated"); + let mut exports = Vec::new(); + + for (func, _ty) in funcs { + let index = self.component.core_alias_export( + shim_instance, + &shims.shim_names[&ShimKind::Adapter { adapter, func }], + ExportKind::Func, + ); + exports.push((*func, ExportKind::Func, index)); + } + + let index = self.component.core_instantiate_exports(exports); + args.push((*adapter, ModuleArg::Instance(index))); + } + + self.add_resource_funcs( + CustomModule::Main, + &info.required_resource_funcs, + &shims, + &mut args, + ); + + // Instantiate the main module now that all of its arguments have been + // prepared. With this we now have the main linear memory for + // liftings/lowerings later on as well as the adapter modules, if any, + // instantiated after the core wasm module. + self.instantiate_core_module(args, info); + + // Separate the adapters according which should be instantiated before + // and after indirect lowerings are encoded. + let (before, after) = self + .info + .adapters + .iter() + .partition::, _>(|(_, adapter)| { + !matches!( + adapter.library_info, + Some(LibraryInfo { + instantiate_after_shims: true, + .. + }) + ) + }); + + for (name, adapter) in before { + self.instantiate_adapter_module(&shims, name, adapter); + } + + // With all the relevant core wasm instances in play now the original shim + // module, if present, can be filled in with lowerings/adapters/etc. + self.encode_indirect_lowerings(&shims)?; + + for (name, adapter) in after { + self.instantiate_adapter_module(&shims, name, adapter); + } + + Ok(()) + } + + /// Lowers a named imported interface a core wasm instances suitable to + /// provide as an instantiation argument to another core wasm module. + /// + /// * `for_module` the module that this instance is being created for, or + /// otherwise which `realloc` option is used for the lowerings. + /// * `name` - the name of the imported interface that's being lowered. + /// * `imports` - the list of all imports known for this encoding. + /// * `shims` - the indirect/adapter shims created prior, if any. + fn import_instance_to_lowered_core_instance( + &mut self, + for_module: CustomModule<'_>, + core_wasm_name: &str, + shims: &Shims<'_>, + metadata: &ModuleMetadata, + ) -> u32 { + let interface = if core_wasm_name == BARE_FUNC_MODULE_NAME { + None + } else { + Some(core_wasm_name.to_string()) + }; + let import = &self.info.import_map[&interface]; + let required_imports = match for_module { + CustomModule::Main => &self.info.info.required_imports[core_wasm_name], + CustomModule::Adapter(name) => { + &self.info.adapters[name].info.required_imports[core_wasm_name] + } + }; + let mut exports = Vec::with_capacity(import.lowerings.len()); + + for (index, (name, lowering)) in import.lowerings.iter().enumerate() { + if !required_imports.funcs.contains(name.as_str()) { + continue; + } + let index = match lowering { + // All direct lowerings can be `canon lower`'d here immediately + // and passed as arguments. + Lowering::Direct => { + let func_index = match &import.interface { + Some(interface) => { + let instance_index = self.imported_instances[interface]; + self.component.alias_export( + instance_index, + name, + ComponentExportKind::Func, + ) + } + None => self.imported_funcs[name], + }; + self.component.lower_func(func_index, []) + } + + // Add an entry for all indirect lowerings which come as an + // export of the shim module. + Lowering::Indirect { .. } => { + let encoding = + metadata.import_encodings[&(core_wasm_name.to_string(), name.clone())]; + self.component.core_alias_export( + self.shim_instance_index + .expect("shim should be instantiated"), + &shims.shim_names[&ShimKind::IndirectLowering { + interface: interface.clone(), + index, + realloc: for_module, + encoding, + }], + ExportKind::Func, + ) + } + + Lowering::ResourceDrop(id) => { + let resource_idx = self.lookup_resource_index(*id); + self.component.resource_drop(resource_idx) + } + }; + exports.push((name.as_str(), ExportKind::Func, index)); + } + + self.component.core_instantiate_exports(exports) + } + + fn lookup_resource_index(&mut self, id: TypeId) -> u32 { + let resolve = &self.info.encoder.metadata.resolve; + let ty = &resolve.types[id]; + match ty.owner { + // If this resource is owned by a world then it's a top-level + // resource which means it must have already been translated so + // it's available for lookup in `import_type_map`. + TypeOwner::World(_) => self.import_type_map[&id], + TypeOwner::Interface(i) => { + let instance = self.imported_instances[&i]; + let name = ty.name.as_ref().expect("resources must be named"); + self.component + .alias_export(instance, name, ComponentExportKind::Type) + } + TypeOwner::None => panic!("resources must have an owner"), + } + } + + fn encode_exports(&mut self, module: CustomModule) -> Result<()> { + let resolve = &self.info.encoder.metadata.resolve; + let exports = match module { + CustomModule::Main => &self.info.encoder.main_module_exports, + CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports, + }; + let world = &resolve.worlds[self.info.encoder.metadata.world]; + for export_name in exports { + let export_string = resolve.name_world_key(export_name); + match &world.exports[export_name] { + WorldItem::Function(func) => { + let ty = self + .root_import_type_encoder(None) + .encode_func_type(resolve, func)?; + let core_name = func.core_export_name(None); + let idx = self.encode_lift(module, &core_name, func, ty)?; + self.component + .export(&export_string, ComponentExportKind::Func, idx, None); + } + WorldItem::Interface(export) => { + self.encode_interface_export(&export_string, module, *export)?; + } + WorldItem::Type(_) => unreachable!(), + } + } + + Ok(()) + } + + fn encode_interface_export( + &mut self, + export_name: &str, + module: CustomModule<'_>, + export: InterfaceId, + ) -> Result<()> { + log::trace!("encode interface export `{export_name}`"); + let resolve = &self.info.encoder.metadata.resolve; + + // First execute a `canon lift` for all the functions in this interface + // from the core wasm export. This requires type information but notably + // not exported type information since we don't want to export this + // interface's types from the root of the component. Each lifted + // function is saved off into an `imports` array to get imported into + // the nested component synthesized below. + let mut imports = Vec::new(); + let mut root = self.root_export_type_encoder(Some(export)); + for (_, func) in &resolve.interfaces[export].functions { + let core_name = func.core_export_name(Some(export_name)); + let ty = root.encode_func_type(resolve, func)?; + let func_index = root.state.encode_lift(module, &core_name, func, ty)?; + imports.push(( + import_func_name(func), + ComponentExportKind::Func, + func_index, + )); + } + + // Next a nested component is created which will import the functions + // above and then reexport them. The purpose of them is to "re-type" the + // functions through type ascription on each `func` item. + let mut nested = NestedComponentTypeEncoder { + component: ComponentBuilder::default(), + type_map: Default::default(), + func_type_map: Default::default(), + export_types: false, + interface: export, + state: self, + imports: IndexMap::new(), + }; + + // Import all transitively-referenced types from other interfaces into + // this component. This temporarily switches the `interface` listed to + // the interface of the referred-to-type to generate the import. After + // this loop `interface` is rewritten to `export`. + // + // Each component is a standalone "island" so the necessary type + // information needs to be rebuilt within this component. This ensures + // that we're able to build a valid component and additionally connect + // all the type information to the outer context. + let mut types_to_import = LiveTypes::default(); + types_to_import.add_interface(resolve, export); + let exports_used = &nested.state.info.exports_used[&export]; + for ty in types_to_import.iter() { + if let TypeOwner::Interface(owner) = resolve.types[ty].owner { + if owner == export { + // Here this deals with the current exported interface which + // is handled below. + continue; + } + + // Ensure that `self` has encoded this type before. If so this + // is a noop but otherwise it generates the type here. + let mut encoder = if exports_used.contains(&owner) { + nested.state.root_export_type_encoder(Some(export)) + } else { + nested.state.root_import_type_encoder(Some(export)) + }; + encoder.encode_valtype(resolve, &Type::Id(ty))?; + + // Next generate the same type but this time within the + // component itself. The type generated above (or prior) will be + // used to satisfy this type import. + nested.interface = owner; + nested.encode_valtype(resolve, &Type::Id(ty))?; + } + } + nested.interface = export; + + // Record the map of types imported to their index at where they were + // imported. This is used after imports are encoded as exported types + // will refer to these. + let imported_types = nested.type_map.clone(); + + // Handle resource types for this instance specially, namely importing + // them into the nested component. This models how the resource is + // imported from its definition in the outer component to get reexported + // internally. This chiefly avoids creating a second resource which is + // not desired in this situation. + let mut resources = HashMap::new(); + for (_name, ty) in resolve.interfaces[export].types.iter() { + if !matches!(resolve.types[*ty].kind, TypeDefKind::Resource) { + continue; + } + let idx = match nested.encode_valtype(resolve, &Type::Id(*ty))? { + ComponentValType::Type(idx) => idx, + _ => unreachable!(), + }; + resources.insert(*ty, idx); + } + + // Next import each function of this interface. This will end up + // defining local types as necessary or using the types as imported + // above. + for (_, func) in resolve.interfaces[export].functions.iter() { + let ty = nested.encode_func_type(resolve, func)?; + nested + .component + .import(&import_func_name(func), ComponentTypeRef::Func(ty)); + } + + // Swap the `nested.type_map` which was previously from `TypeId` to + // `u32` to instead being from `u32` to `TypeId`. This reverse map is + // then used in conjunction with `self.type_map` to satisfy all type + // imports of the nested component generated. The type import's index in + // the inner component is translated to a `TypeId` via `reverse_map` + // which is then translated back to our own index space via `type_map`. + let reverse_map = nested + .type_map + .drain() + .map(|p| (p.1, p.0)) + .collect::>(); + for (name, idx) in nested.imports.drain(..) { + let id = reverse_map[&idx]; + let owner = match resolve.types[id].owner { + TypeOwner::Interface(id) => id, + _ => unreachable!(), + }; + let idx = if owner == export || exports_used.contains(&owner) { + log::trace!("consulting exports for {id:?}"); + nested.state.export_type_map[&id] + } else { + log::trace!("consulting imports for {id:?}"); + nested.state.import_type_map[&id] + }; + imports.push((name, ComponentExportKind::Type, idx)) + } + + // Before encoding exports reset the type map to what all was imported + // from foreign interfaces. This will enable any encoded types below to + // refer to imports which, after type substitution, will point to the + // correct type in the outer component context. + nested.type_map = imported_types; + + // Next the component reexports all of its imports, but notably uses the + // type ascription feature to change the type of the function. Note that + // no structural change is happening to the types here but instead types + // are getting proper names and such now that this nested component is a + // new type index space. Hence the `export_types = true` flag here which + // flows through the type encoding and when types are emitted. + nested.export_types = true; + nested.func_type_map.clear(); + + // To start off all type information is encoded. This will be used by + // functions below but notably this also has special handling for + // resources. Resources reexport their imported resource type under + // the final name which achieves the desired goal of threading through + // the original resource without creating a new one. + for (_, id) in resolve.interfaces[export].types.iter() { + let ty = &resolve.types[*id]; + match ty.kind { + TypeDefKind::Resource => { + let idx = nested.component.export( + ty.name.as_ref().expect("resources must be named"), + ComponentExportKind::Type, + resources[id], + None, + ); + nested.type_map.insert(*id, idx); + } + _ => { + nested.encode_valtype(resolve, &Type::Id(*id))?; + } + } + } + + for (i, (_, func)) in resolve.interfaces[export].functions.iter().enumerate() { + let ty = nested.encode_func_type(resolve, func)?; + nested.component.export( + &func.name, + ComponentExportKind::Func, + i as u32, + Some(ComponentTypeRef::Func(ty)), + ); + } + + // Embed the component within our component and then instantiate it with + // the lifted functions. That final instance is then exported under the + // appropriate name as the final typed export of this component. + let component = nested.component; + let component_index = self.component.component(component); + let instance_index = self.component.instantiate(component_index, imports); + let idx = self.component.export( + export_name, + ComponentExportKind::Instance, + instance_index, + None, + ); + let prev = self.exported_instances.insert(export, idx); + assert!(prev.is_none()); + + // After everything is all said and done remove all the type information + // about type exports of this interface. Any entries in the map + // currently were used to create the instance above but aren't the + // actual copy of the exported type since that comes from the exported + // instance itself. Entries will be re-inserted into this map as + // necessary via aliases from the exported instance which is the new + // source of truth for all these types. + for (_name, id) in resolve.interfaces[export].types.iter() { + self.export_type_map.remove(id); + } + + return Ok(()); + + struct NestedComponentTypeEncoder<'state, 'a> { + component: ComponentBuilder, + type_map: HashMap, + func_type_map: HashMap, u32>, + export_types: bool, + interface: InterfaceId, + state: &'state mut EncodingState<'a>, + imports: IndexMap, + } + + impl<'a> ValtypeEncoder<'a> for NestedComponentTypeEncoder<'_, 'a> { + fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { + self.component.type_defined() + } + fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { + self.component.type_function() + } + fn export_type(&mut self, idx: u32, name: &'a str) -> Option { + if self.export_types { + Some( + self.component + .export(name, ComponentExportKind::Type, idx, None), + ) + } else { + let name = self.unique_import_name(name); + let ret = self + .component + .import(&name, ComponentTypeRef::Type(TypeBounds::Eq(idx))); + self.imports.insert(name, ret); + Some(ret) + } + } + fn export_resource(&mut self, name: &'a str) -> u32 { + if self.export_types { + panic!("resources should already be exported") + } else { + let name = self.unique_import_name(name); + let ret = self + .component + .import(&name, ComponentTypeRef::Type(TypeBounds::SubResource)); + self.imports.insert(name, ret); + ret + } + } + fn import_type(&mut self, _: InterfaceId, _id: TypeId) -> u32 { + unreachable!() + } + fn type_map(&mut self) -> &mut HashMap { + &mut self.type_map + } + fn func_type_map(&mut self) -> &mut HashMap, u32> { + &mut self.func_type_map + } + fn interface(&self) -> Option { + Some(self.interface) + } + } + + impl NestedComponentTypeEncoder<'_, '_> { + fn unique_import_name(&mut self, name: &str) -> String { + let mut name = format!("import-type-{name}"); + let mut n = 0; + while self.imports.contains_key(&name) { + name = format!("{name}{n}"); + n += 1; + } + name + } + } + + fn import_func_name(f: &Function) -> String { + match f.kind { + FunctionKind::Freestanding => { + format!("import-func-{}", f.name) + } + + // transform `[method]foo.bar` into `import-method-foo-bar` to + // have it be a valid kebab-name which can't conflict with + // anything else. + // + // There's probably a better and more "formal" way to do this + // but quick-and-dirty string manipulation should work well + // enough for now hopefully. + FunctionKind::Method(_) + | FunctionKind::Static(_) + | FunctionKind::Constructor(_) => { + format!( + "import-{}", + f.name.replace('[', "").replace([']', '.'], "-") + ) + } + } + } + } + + fn encode_lift( + &mut self, + module: CustomModule<'_>, + core_name: &str, + func: &Function, + ty: u32, + ) -> Result { + let resolve = &self.info.encoder.metadata.resolve; + let metadata = match module { + CustomModule::Main => &self.info.encoder.metadata.metadata, + CustomModule::Adapter(name) => &self.info.encoder.adapters[name].metadata, + }; + let post_returns = match module { + CustomModule::Main => &self.info.info.post_returns, + CustomModule::Adapter(name) => &self.info.adapters[name].info.post_returns, + }; + let instance_index = match module { + CustomModule::Main => self.instance_index.expect("instantiated by now"), + CustomModule::Adapter(name) => self.adapter_instances[name], + }; + let core_func_index = + self.component + .core_alias_export(instance_index, core_name, ExportKind::Func); + + let options = RequiredOptions::for_export(resolve, func); + + let encoding = metadata.export_encodings[core_name]; + // TODO: This realloc detection should probably be improved with + // some sort of scheme to have per-function reallocs like + // `cabi_realloc_{name}` or something like that. + let realloc_index = match module { + CustomModule::Main => self.realloc_index, + CustomModule::Adapter(name) => self.adapter_export_reallocs[name], + }; + let mut options = options + .into_iter(encoding, self.memory_index, realloc_index)? + .collect::>(); + + let post_return = format!("{POST_RETURN_PREFIX}{core_name}"); + if post_returns.contains(&post_return[..]) { + let post_return = + self.component + .core_alias_export(instance_index, &post_return, ExportKind::Func); + options.push(CanonicalOption::PostReturn(post_return)); + } + let func_index = self.component.lift_func(core_func_index, ty, options); + Ok(func_index) + } + + fn encode_shim_instantiation(&mut self) -> Shims<'a> { + let mut signatures = Vec::new(); + let mut ret = Shims::default(); + let info = &self.info.info; + + // For all interfaces imported into the main module record all of their + // indirect lowerings into `Shims`. + for (core_wasm_name, required) in info.required_imports.iter() { + let import_name = if *core_wasm_name == BARE_FUNC_MODULE_NAME { + None + } else { + Some(core_wasm_name.to_string()) + }; + let import = &self.info.import_map[&import_name]; + ret.append_indirect( + core_wasm_name, + CustomModule::Main, + import, + &required.funcs, + info.metadata, + &mut signatures, + ); + } + + // For all required adapter modules a shim is created for each required + // function and additionally a set of shims are created for the + // interface imported into the shim module itself. + for (adapter_name, adapter) in self.info.adapters.iter() { + for (name, required) in adapter.info.required_imports.iter() { + let import_name = if *name == BARE_FUNC_MODULE_NAME { + None + } else { + Some(name.to_string()) + }; + let import = &self.info.import_map[&import_name]; + ret.append_indirect( + name, + CustomModule::Adapter(adapter_name), + import, + &required.funcs, + adapter.info.metadata, + &mut signatures, + ); + } + + self.encode_resource_dtors( + CustomModule::Adapter(adapter_name), + &adapter.info.required_resource_funcs, + &mut signatures, + &mut ret, + ); + + let funcs = match self.info.info.adapters_required.get(adapter_name) { + Some(funcs) => funcs, + None => continue, + }; + for (func, ty) in funcs { + let name = ret.list.len().to_string(); + log::debug!("shim {name} is adapter `{adapter_name}::{func}`"); + signatures.push(WasmSignature { + params: ty.params().iter().map(to_wasm_type).collect(), + results: ty.results().iter().map(to_wasm_type).collect(), + indirect_params: false, + retptr: false, + }); + ret.list.push(Shim { + name, + debug_name: format!("adapt-{adapter_name}-{func}"), + // Pessimistically assume that all adapters require memory + // in one form or another. While this isn't technically true + // it's true enough for WASI. + options: RequiredOptions::MEMORY, + kind: ShimKind::Adapter { + adapter: adapter_name, + func, + }, + }); + } + } + + self.encode_resource_dtors( + CustomModule::Main, + &self.info.info.required_resource_funcs, + &mut signatures, + &mut ret, + ); + + if ret.list.is_empty() { + return ret; + } + + for shim in ret.list.iter() { + let prev = ret.shim_names.insert(shim.kind.clone(), shim.name.clone()); + assert!(prev.is_none()); + } + + assert!(self.shim_instance_index.is_none()); + assert!(self.fixups_module_index.is_none()); + + // This function encodes two modules: + // - A shim module that defines a table and exports functions + // that indirectly call through the table. + // - A fixup module that imports that table and a set of functions + // and populates the imported table via active element segments. The + // fixup module is used to populate the shim's table once the + // imported functions have been lowered. + + let mut types = TypeSection::new(); + let mut tables = TableSection::new(); + let mut functions = FunctionSection::new(); + let mut exports = ExportSection::new(); + let mut code = CodeSection::new(); + let mut sigs = IndexMap::new(); + let mut imports_section = ImportSection::new(); + let mut elements = ElementSection::new(); + let mut func_indexes = Vec::new(); + let mut func_names = NameMap::new(); + + for (i, (sig, shim)) in signatures.iter().zip(&ret.list).enumerate() { + let i = i as u32; + let type_index = *sigs.entry(sig).or_insert_with(|| { + let index = types.len(); + types.function( + sig.params.iter().map(to_val_type), + sig.results.iter().map(to_val_type), + ); + index + }); + + functions.function(type_index); + Self::encode_shim_function(type_index, i, &mut code, sig.params.len() as u32); + exports.export(&shim.name, ExportKind::Func, i); + + imports_section.import("", &shim.name, EntityType::Function(type_index)); + func_indexes.push(i); + func_names.append(i, &shim.debug_name); + } + let mut names = NameSection::new(); + names.module("wit-component:shim"); + names.functions(&func_names); + + let table_type = TableType { + element_type: RefType::FUNCREF, + minimum: signatures.len() as u32, + maximum: Some(signatures.len() as u32), + }; + + tables.table(table_type); + + exports.export(INDIRECT_TABLE_NAME, ExportKind::Table, 0); + imports_section.import("", INDIRECT_TABLE_NAME, table_type); + + elements.active( + None, + &ConstExpr::i32_const(0), + Elements::Functions(&func_indexes), + ); + + let mut shim = Module::new(); + shim.section(&types); + shim.section(&functions); + shim.section(&tables); + shim.section(&exports); + shim.section(&code); + shim.section(&RawCustomSection( + &crate::base_producers().raw_custom_section(), + )); + shim.section(&names); + + let mut fixups = Module::default(); + fixups.section(&types); + fixups.section(&imports_section); + fixups.section(&elements); + fixups.section(&RawCustomSection( + &crate::base_producers().raw_custom_section(), + )); + + let mut names = NameSection::new(); + names.module("wit-component:fixups"); + fixups.section(&names); + + let shim_module_index = self.component.core_module(&shim); + self.fixups_module_index = Some(self.component.core_module(&fixups)); + self.shim_instance_index = Some(self.component.core_instantiate(shim_module_index, [])); + + return ret; + + fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType { + match ty { + wasmparser::ValType::I32 => WasmType::I32, + wasmparser::ValType::I64 => WasmType::I64, + wasmparser::ValType::F32 => WasmType::F32, + wasmparser::ValType::F64 => WasmType::F64, + _ => unreachable!(), + } + } + } + + fn encode_shim_function( + type_index: u32, + func_index: u32, + code: &mut CodeSection, + param_count: u32, + ) { + let mut func = wasm_encoder::Function::new(std::iter::empty()); + for i in 0..param_count { + func.instruction(&Instruction::LocalGet(i)); + } + func.instruction(&Instruction::I32Const(func_index as i32)); + func.instruction(&Instruction::CallIndirect { + ty: type_index, + table: 0, + }); + func.instruction(&Instruction::End); + code.function(&func); + } + + fn encode_indirect_lowerings(&mut self, shims: &Shims<'_>) -> Result<()> { + if shims.list.is_empty() { + return Ok(()); + } + + let shim_instance_index = self + .shim_instance_index + .expect("must have an instantiated shim"); + + let table_index = self.component.core_alias_export( + shim_instance_index, + INDIRECT_TABLE_NAME, + ExportKind::Table, + ); + + let mut exports = Vec::new(); + exports.push((INDIRECT_TABLE_NAME, ExportKind::Table, table_index)); + + for shim in shims.list.iter() { + let core_func_index = match &shim.kind { + // Indirect lowerings are a `canon lower`'d function with + // options specified from a previously instantiated instance. + // This previous instance could either be the main module or an + // adapter module, which affects the `realloc` option here. + // Currently only one linear memory is supported so the linear + // memory always comes from the main module. + ShimKind::IndirectLowering { + interface, + index, + realloc, + encoding, + } => { + let interface = &self.info.import_map[interface]; + let (name, _) = interface.lowerings.get_index(*index).unwrap(); + let func_index = match &interface.interface { + Some(interface_id) => { + let instance_index = self.imported_instances[interface_id]; + self.component.alias_export( + instance_index, + name, + ComponentExportKind::Func, + ) + } + None => self.imported_funcs[name], + }; + + let realloc = match realloc { + CustomModule::Main => self.realloc_index, + CustomModule::Adapter(name) => self.adapter_import_reallocs[name], + }; + + self.component.lower_func( + func_index, + shim.options + .into_iter(*encoding, self.memory_index, realloc)?, + ) + } + + // Adapter shims are defined by an export from an adapter + // instance, so use the specified name here and the previously + // created instances to get the core item that represents the + // shim. + ShimKind::Adapter { adapter, func } => self.component.core_alias_export( + self.adapter_instances[adapter], + func, + ExportKind::Func, + ), + + // Resources are required for a module to be instantiated + // meaning that any destructor for the resource must be called + // indirectly due to the otherwise circular dependency between + // the module and the resource itself. + ShimKind::ResourceDtor { + module, + import, + resource, + } => { + let funcs = match module { + CustomModule::Main => &self.info.info.required_resource_funcs, + CustomModule::Adapter(name) => { + &self.info.adapters[name].info.required_resource_funcs + } + }; + + self.component.core_alias_export( + self.instance_index.unwrap(), + funcs[*import][*resource].dtor_export.as_deref().unwrap(), + ExportKind::Func, + ) + } + }; + + exports.push((shim.name.as_str(), ExportKind::Func, core_func_index)); + } + + let instance_index = self.component.core_instantiate_exports(exports); + self.component.core_instantiate( + self.fixups_module_index.expect("must have fixup module"), + [("", ModuleArg::Instance(instance_index))], + ); + Ok(()) + } + + fn instantiate_core_module<'b, A>(&mut self, args: A, info: &ValidatedModule<'_>) + where + A: IntoIterator, + A::IntoIter: ExactSizeIterator, + { + assert!(self.instance_index.is_none()); + + let instance_index = self + .component + .core_instantiate(self.module_index.expect("core module encoded"), args); + + if info.has_memory { + self.memory_index = Some(self.component.core_alias_export( + instance_index, + "memory", + ExportKind::Memory, + )); + } + + if let Some(name) = &info.realloc { + self.realloc_index = Some(self.component.core_alias_export( + instance_index, + name, + ExportKind::Func, + )); + } + + self.instance_index = Some(instance_index); + } + + fn encode_resource_dtors<'b>( + &mut self, + module: CustomModule<'b>, + funcs: &'b IndexMap>, + signatures: &mut Vec, + shims: &mut Shims<'b>, + ) { + // Any resource destructors are encoded through the shim module. The + // core wasm probably imports resource intrinsics which requires the + // resource definition, but the resource definition requires + // the destructor to be available. The shim module breaks this + // circular dependency. + for (import, info) in funcs.iter() { + for (resource, info) in info { + if info.dtor_export.is_none() { + continue; + } + signatures.push(WasmSignature { + params: vec![WasmType::I32], + results: Vec::new(), + indirect_params: false, + retptr: false, + }); + let name = shims.list.len().to_string(); + shims.list.push(Shim { + name, + debug_name: format!("dtor-{import}-{resource}"), + options: RequiredOptions::empty(), + kind: ShimKind::ResourceDtor { + module, + import, + resource, + }, + }); + } + } + } + + fn add_resource_funcs<'b>( + &mut self, + module: CustomModule<'b>, + funcs: &'b IndexMap>, + shims: &Shims, + args: &mut Vec<(&'b str, ModuleArg)>, + ) { + for (import, info) in funcs { + let mut exports = Vec::new(); + for (resource, info) in info { + // Destructors for resources live on the shim module previously + // created, so if one is specified create the resource with + // the shim module that currently exists. The shim will get + // filled in later with the actual destructor after the main + // module is instantiated. + let dtor = info.dtor_export.as_deref().map(|_| { + self.component.core_alias_export( + self.shim_instance_index.unwrap(), + &shims.shim_names[&ShimKind::ResourceDtor { + module, + import, + resource, + }], + ExportKind::Func, + ) + }); + let resource_idx = self.component.type_resource(ValType::I32, dtor); + let prev = self.export_type_map.insert(info.id, resource_idx); + assert!(prev.is_none()); + + if let Some(name) = info.drop_import.as_deref() { + let index = self.component.resource_drop(resource_idx); + exports.push((name, ExportKind::Func, index)); + } + if let Some(name) = info.rep_import.as_deref() { + let index = self.component.resource_rep(resource_idx); + exports.push((name, ExportKind::Func, index)); + } + if let Some(name) = info.new_import.as_deref() { + let index = self.component.resource_new(resource_idx); + exports.push((name, ExportKind::Func, index)); + } + } + if !exports.is_empty() { + let index = self.component.core_instantiate_exports(exports); + args.push((import.as_str(), ModuleArg::Instance(index))); + } + } + } + + /// This function will instantiate the specified adapter module, which may + /// depend on previously-instantiated modules. + fn instantiate_adapter_module( + &mut self, + shims: &Shims<'_>, + name: &'a str, + adapter: &WorldAdapter, + ) { + let mut args = Vec::new(); + + let mut core_exports = Vec::new(); + for export_name in adapter.info.needs_core_exports.iter() { + let mut core_export_name = export_name.as_str(); + // provide cabi_realloc_adapter as cabi_realloc to adapters + // if it exists + if export_name == "cabi_realloc" { + if let Some(adapter_realloc) = self.info.info.adapter_realloc { + core_export_name = adapter_realloc; + } + } + let index = self.component.core_alias_export( + self.instance_index + .expect("adaptee index set at this point"), + core_export_name, + ExportKind::Func, + ); + core_exports.push((export_name.as_str(), ExportKind::Func, index)); + } + if !core_exports.is_empty() { + let instance = self.component.core_instantiate_exports(core_exports); + args.push((MAIN_MODULE_IMPORT_NAME, ModuleArg::Instance(instance))); + } + // The adapter may either be a library or a "minimal" adapter. If it's + // the former, we use `LibraryInfo::arguments` to populate inter-module + // instantiation arguments. + if let Some(library_info) = adapter.library_info { + for (import_name, instance) in &library_info.arguments { + let resolve = |which: &_| match which { + MainOrAdapter::Main => self.instance_index.unwrap(), + MainOrAdapter::Adapter(adapter_name) => *self + .adapter_instances + .get(adapter_name.as_str()) + .unwrap_or_else(|| { + panic!( + "adapter {name} needs {adapter_name}, \ + which has not yet been instantiated" + ) + }), + }; + + args.push(( + import_name, + ModuleArg::Instance(match instance { + Instance::MainOrAdapter(which) => resolve(which), + Instance::Items(items) => { + let exports = items + .iter() + .map(|item| { + ( + item.alias.as_str(), + item.kind, + self.component.core_alias_export( + resolve(&item.which), + &item.name, + item.kind, + ), + ) + }) + .collect::>(); + self.component.core_instantiate_exports(exports) + } + }), + )); + } + } else { + // If the adapter module requires a `memory` import then specify + // that here. For now assume that the module name of the memory is + // different from the imported interface. That's true enough for now + // since it's `env::memory`. + if let Some((module, name)) = &adapter.info.needs_memory { + for (import_name, _) in adapter.info.required_imports.iter() { + assert!(module != import_name); + } + assert!(module != name); + let memory = self.memory_index.unwrap(); + let instance = self.component.core_instantiate_exports([( + name.as_str(), + ExportKind::Memory, + memory, + )]); + args.push((module.as_str(), ModuleArg::Instance(instance))); + } + } + for (import_name, _) in adapter.info.required_imports.iter() { + let instance = self.import_instance_to_lowered_core_instance( + CustomModule::Adapter(name), + import_name, + shims, + adapter.info.metadata, + ); + args.push((import_name, ModuleArg::Instance(instance))); + } + + self.add_resource_funcs( + CustomModule::Adapter(name), + &adapter.info.required_resource_funcs, + shims, + &mut args, + ); + + let instance = self + .component + .core_instantiate(self.adapter_modules[name], args); + self.adapter_instances.insert(name, instance); + + let realloc = adapter.info.export_realloc.as_ref().map(|name| { + self.component + .core_alias_export(instance, name, ExportKind::Func) + }); + self.adapter_export_reallocs.insert(name, realloc); + let realloc = adapter.info.import_realloc.as_ref().map(|name| { + self.component + .core_alias_export(instance, name, ExportKind::Func) + }); + self.adapter_import_reallocs.insert(name, realloc); + } +} + +/// A list of "shims" which start out during the component instantiation process +/// as functions which immediately trap due to a `call_indirect`-to-`null` but +/// will get filled in by the time the component instantiation process +/// completes. +/// +/// Shims currently include: +/// +/// * "Indirect functions" lowered from imported instances where the lowering +/// requires an item exported from the main module. These are indirect due to +/// the circular dependency between the module needing an import and the +/// import needing the module. +/// +/// * Adapter modules which convert from a historical ABI to the component +/// model's ABI (e.g. wasi preview1 to preview2) get a shim since the adapters +/// are currently indicated as always requiring the memory of the main module. +/// +/// This structure is created by `encode_shim_instantiation`. +#[derive(Default)] +struct Shims<'a> { + /// The list of all shims that a module will require. + list: Vec>, + + /// A map from a shim to the name of the shim in the shim instance. + shim_names: IndexMap, String>, +} + +struct Shim<'a> { + /// Canonical ABI options required by this shim, used during `canon lower` + /// operations. + options: RequiredOptions, + + /// The name, in the shim instance, of this shim. + /// + /// Currently this is `"0"`, `"1"`, ... + name: String, + + /// A human-readable debugging name for this shim, used in a core wasm + /// `name` section. + debug_name: String, + + /// Precise information about what this shim is a lowering of. + kind: ShimKind<'a>, +} + +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +enum ShimKind<'a> { + /// This shim is a late indirect lowering of an imported function in a + /// component which is only possible after prior core wasm modules are + /// instantiated so their memories and functions are available. + IndirectLowering { + /// The name of the interface that's being lowered. + interface: Option, + /// The index within the `lowerings` array of the function being lowered. + index: usize, + /// Which instance to pull the `realloc` function from, if necessary. + realloc: CustomModule<'a>, + /// The string encoding that this lowering is going to use. + encoding: StringEncoding, + }, + /// This shim is a core wasm function defined in an adapter module but isn't + /// available until the adapter module is itself instantiated. + Adapter { + /// The name of the adapter module this shim comes from. + adapter: &'a str, + /// The name of the export in the adapter module this shim points to. + func: &'a str, + }, + /// A shim used as the destructor for a resource which allows defining the + /// resource before the core module being instantiated. + ResourceDtor { + /// Which instance to pull the destructor function from. + module: CustomModule<'a>, + /// The import that the resource was defined for. + import: &'a str, + /// The name of the resource being destroyed. + resource: &'a str, + }, +} + +/// Indicator for which module is being used for a lowering or where options +/// like `realloc` are drawn from. +/// +/// This is necessary for situations such as an imported function being lowered +/// into the main module and additionally into an adapter module. For example an +/// adapter might adapt from preview1 to preview2 for the standard library of a +/// programming language but the main module's custom application code may also +/// explicitly import from preview2. These two different lowerings of a preview2 +/// function are parameterized by this enumeration. +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +enum CustomModule<'a> { + /// This points to the "main module" which is generally the "output of LLVM" + /// or what a user wrote. + Main, + /// This is selecting an adapter module, identified by name here, where + /// something is being lowered into. + Adapter(&'a str), +} + +impl<'a> Shims<'a> { + /// Adds all shims necessary for the `import` provided, namely iterating + /// over its indirect lowerings and appending a shim per lowering. + fn append_indirect( + &mut self, + core_wasm_module: &'a str, + for_module: CustomModule<'a>, + import: &ImportedInterface, + required: &IndexSet, + metadata: &ModuleMetadata, + sigs: &mut Vec, + ) { + let interface = if core_wasm_module == BARE_FUNC_MODULE_NAME { + None + } else { + Some(core_wasm_module.to_string()) + }; + for (index, (name, lowering)) in import.lowerings.iter().enumerate() { + if !required.contains(name.as_str()) { + continue; + } + let shim_name = self.list.len().to_string(); + log::debug!( + "shim {shim_name} is import `{core_wasm_module}` lowering {index} `{name}`", + ); + match lowering { + Lowering::Direct | Lowering::ResourceDrop(_) => {} + + Lowering::Indirect { sig, options } => { + sigs.push(sig.clone()); + let encoding = + metadata.import_encodings[&(core_wasm_module.to_string(), name.clone())]; + self.list.push(Shim { + name: shim_name, + debug_name: format!("indirect-{core_wasm_module}-{name}"), + options: *options, + kind: ShimKind::IndirectLowering { + interface: interface.clone(), + index, + realloc: for_module, + encoding, + }, + }); + } + } + } + } +} + +/// Alias argument to an instantiation +#[derive(Clone)] +pub struct Item { + pub alias: String, + pub kind: ExportKind, + pub which: MainOrAdapter, + pub name: String, +} + +/// Module argument to an instantiation +#[derive(Clone)] +pub enum MainOrAdapter { + Main, + Adapter(String), +} + +/// Module instantiation argument +#[derive(Clone)] +pub enum Instance { + /// Module argument + MainOrAdapter(MainOrAdapter), + + /// Alias argument + Items(Vec), +} + +/// Provides fine-grained control of how a library module is instantiated +/// relative to other module instances +#[derive(Clone)] +pub struct LibraryInfo { + /// If true, instantiate any shims prior to this module + pub instantiate_after_shims: bool, + + /// Instantiation arguments + pub arguments: Vec<(String, Instance)>, +} + +/// Represents an adapter or library to be instansiated as part of the component +struct Adapter { + /// The wasm of the module itself, with `component-type` sections stripped + wasm: Vec, + + /// The metadata for the adapter + metadata: ModuleMetadata, + + /// The set of exports from the final world which are defined by this + /// adapter or library + required_exports: IndexSet, + + /// If present, treat this module as a library rather than a "minimal" adapter + /// + /// TODO: We should refactor how various flavors of module are represented + /// and differentiated to avoid mistaking one for another. + library_info: Option, +} + +/// An encoder of components based on `wit` interface definitions. +#[derive(Default)] +pub struct ComponentEncoder { + module: Vec, + metadata: Bindgen, + validate: bool, + main_module_exports: IndexSet, + adapters: IndexMap, + + realloc_via_memory_grow: bool, +} + +impl ComponentEncoder { + /// Set the core module to encode as a component. + /// This method will also parse any component type information stored in custom sections + /// inside the module, and add them as the interface, imports, and exports. + /// It will also add any producers information inside the component type information to the + /// core module. + pub fn module(mut self, module: &[u8]) -> Result { + let (wasm, metadata) = metadata::decode(module)?; + let world = self + .metadata + .merge(metadata) + .context("failed merge WIT package sets together")?; + self.main_module_exports + .extend(self.metadata.resolve.worlds[world].exports.keys().cloned()); + self.module = if let Some(producers) = &self.metadata.producers { + producers.add_to_wasm(&wasm)? + } else { + wasm + }; + Ok(self) + } + + /// Sets whether or not the encoder will validate its output. + pub fn validate(mut self, validate: bool) -> Self { + self.validate = validate; + self + } + + /// Specifies a new adapter which is used to translate from a historical + /// wasm ABI to the canonical ABI and the `interface` provided. + /// + /// This is primarily used to polyfill, for example, + /// `wasi_snapshot_preview1` with a component-model using interface. The + /// `name` provided is the module name of the adapter that is being + /// polyfilled, for example `"wasi_snapshot_preview1"`. + /// + /// The `bytes` provided is a core wasm module which implements the `name` + /// interface in terms of the `interface` interface. This core wasm module + /// is severely restricted in its shape, for example it cannot have any data + /// segments or element segments. + /// + /// The `interface` provided is the component-model-using-interface that the + /// wasm module specified by `bytes` imports. The `bytes` will then import + /// `interface` and export functions to get imported from the module `name` + /// in the core wasm that's being wrapped. + pub fn adapter(self, name: &str, bytes: &[u8]) -> Result { + self.library_or_adapter(name, bytes, None) + } + + /// Specifies a shared-everything library to link into the component. + /// + /// Unlike adapters, libraries _may_ have data and/or element segments, but + /// they must operate on an imported memory and table, respectively. In + /// this case, the correct amount of space is presumed to have been + /// statically allocated in the main module's memory and table at the + /// offsets which the segments target, e.g. as arranged by + /// [super::linking::Linker]. + /// + /// Libraries are treated similarly to adapters, except that they are not + /// "minified" the way adapters are, and instantiation is controlled + /// declaratively via the `library_info` parameter. + pub fn library(self, name: &str, bytes: &[u8], library_info: LibraryInfo) -> Result { + self.library_or_adapter(name, bytes, Some(library_info)) + } + + fn library_or_adapter( + mut self, + name: &str, + bytes: &[u8], + library_info: Option, + ) -> Result { + let (wasm, metadata) = metadata::decode(bytes)?; + // Merge the adapter's document into our own document to have one large + // document, and then afterwards merge worlds as well. + // + // The first `merge` operation will interleave equivalent packages from + // each adapter into packages that are stored within our own resolve. + // The second `merge_worlds` operation will then ensure that both the + // adapter and the main module have compatible worlds, meaning that they + // either import the same items or they import disjoint items, for + // example. + let world = self + .metadata + .resolve + .merge(metadata.resolve) + .with_context(|| { + format!("failed to merge WIT packages of adapter `{name}` into main packages") + })? + .worlds[metadata.world.index()]; + self.metadata + .resolve + .merge_worlds(world, self.metadata.world) + .with_context(|| { + format!("failed to merge WIT world of adapter `{name}` into main package") + })?; + let exports = self.metadata.resolve.worlds[world] + .exports + .keys() + .cloned() + .collect(); + if let Some(library_info) = &library_info { + // Validate that all referenced modules can be resolved. + for (_, instance) in &library_info.arguments { + let resolve = |which: &_| match which { + MainOrAdapter::Main => Ok(()), + MainOrAdapter::Adapter(name) => { + if self.adapters.contains_key(name.as_str()) { + Ok(()) + } else { + Err(anyhow!("instance refers to unknown adapter `{name}`")) + } + } + }; + + match instance { + Instance::MainOrAdapter(which) => resolve(which)?, + Instance::Items(items) => { + for item in items { + resolve(&item.which)?; + } + } + } + } + } + self.adapters.insert( + name.to_string(), + Adapter { + wasm, + metadata: metadata.metadata, + required_exports: exports, + library_info, + }, + ); + Ok(self) + } + + /// True if the realloc and stack alloction should use ememory.grow + /// The default is to use the main module realloc + /// Can be useful if cabi_realloc cannot be called before the host + /// runtime is initialised. + pub fn realloc_via_memory_grow(mut self, value: bool) -> Self { + self.realloc_via_memory_grow = value; + self + } + + /// Encode the component and return the bytes. + pub fn encode(&self) -> Result> { + if self.module.is_empty() { + bail!("a module is required when encoding a component"); + } + + let world = ComponentWorld::new(self)?; + let mut state = EncodingState { + component: ComponentBuilder::default(), + module_index: None, + instance_index: None, + memory_index: None, + realloc_index: None, + shim_instance_index: None, + fixups_module_index: None, + adapter_modules: IndexMap::new(), + adapter_instances: IndexMap::new(), + adapter_import_reallocs: IndexMap::new(), + adapter_export_reallocs: IndexMap::new(), + import_type_map: HashMap::new(), + import_func_type_map: HashMap::new(), + export_type_map: HashMap::new(), + export_func_type_map: HashMap::new(), + imported_instances: Default::default(), + imported_funcs: Default::default(), + exported_instances: Default::default(), + info: &world, + }; + state.encode_imports()?; + state.encode_core_modules(); + state.encode_core_instantiation()?; + state.encode_exports(CustomModule::Main)?; + for name in self.adapters.keys() { + state.encode_exports(CustomModule::Adapter(name))?; + } + state + .component + .raw_custom_section(&crate::base_producers().raw_custom_section()); + let bytes = state.component.finish(); + + if self.validate { + let mut validator = Validator::new_with_features(WasmFeatures { + component_model: true, + ..Default::default() + }); + + validator + .validate_all(&bytes) + .context("failed to validate component output")?; + } + + Ok(bytes) + } +} diff --git a/crates/wit-component/src/encoding/docs.rs b/crates/wit-component/src/encoding/docs.rs new file mode 100644 index 0000000000..accdbc2db3 --- /dev/null +++ b/crates/wit-component/src/encoding/docs.rs @@ -0,0 +1,354 @@ +use anyhow::{bail, Result}; +use indexmap::IndexMap; +use serde_derive::{Deserialize, Serialize}; +use wasm_encoder::{CustomSection, Encode}; +use wit_parser::{Docs, InterfaceId, PackageId, Resolve, TypeId, WorldId, WorldItem, WorldKey}; + +type StringMap = IndexMap; + +pub const PACKAGE_DOCS_SECTION_NAME: &str = "package-docs"; +const PACKAGE_DOCS_SECTION_VERSION: u8 = 0; + +/// Represents serializable doc comments parsed from a WIT package. +#[derive(Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PackageDocs { + #[serde(default, skip_serializing_if = "Option::is_none")] + docs: Option, + #[serde(default, skip_serializing_if = "StringMap::is_empty")] + worlds: StringMap, + #[serde(default, skip_serializing_if = "StringMap::is_empty")] + interfaces: StringMap, +} + +impl PackageDocs { + /// Extract package docs for the given package. + pub fn extract(resolve: &Resolve, package: PackageId) -> Self { + let package = &resolve.packages[package]; + + let worlds = package + .worlds + .iter() + .map(|(name, id)| (name.to_string(), WorldDocs::extract(resolve, *id))) + .filter(|(_, item)| !item.is_empty()) + .collect(); + let interfaces = package + .interfaces + .iter() + .map(|(name, id)| (name.to_string(), InterfaceDocs::extract(resolve, *id))) + .filter(|(_, item)| !item.is_empty()) + .collect(); + + Self { + docs: package.docs.contents.as_deref().map(Into::into), + worlds, + interfaces, + } + } + + /// Inject package docs for the given package. + /// + /// This will override any existing docs in the [`Resolve`]. + pub fn inject(&self, resolve: &mut Resolve, package: PackageId) -> Result<()> { + for (name, docs) in &self.worlds { + let Some(&id) = resolve.packages[package].worlds.get(name) else { + bail!("missing world {name:?}"); + }; + docs.inject(resolve, id)?; + } + for (name, docs) in &self.interfaces { + let Some(&id) = resolve.packages[package].interfaces.get(name) else { + bail!("missing interface {name:?}"); + }; + docs.inject(resolve, id)?; + } + if let Some(docs) = &self.docs { + resolve.packages[package].docs.contents = Some(docs.to_string()); + } + Ok(()) + } + + /// Encode package docs as a package-docs custom section. + pub fn raw_custom_section(&self) -> Result> { + // Version byte (0), followed by JSON encoding of docs + let mut data = vec![PACKAGE_DOCS_SECTION_VERSION]; + serde_json::to_writer(&mut data, self)?; + + let mut raw_section = vec![]; + CustomSection { + name: PACKAGE_DOCS_SECTION_NAME.into(), + data: data.into(), + } + .encode(&mut raw_section); + Ok(raw_section) + } + + /// Decode package docs from package-docs custom section content. + pub fn decode(data: &[u8]) -> Result { + let version = data.first(); + if version != Some(&PACKAGE_DOCS_SECTION_VERSION) { + bail!("expected package-docs version {PACKAGE_DOCS_SECTION_VERSION}, got {version:?}"); + } + Ok(serde_json::from_slice(&data[1..])?) + } +} + +#[derive(Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct WorldDocs { + #[serde(default, skip_serializing_if = "Option::is_none")] + docs: Option, + #[serde(default, skip_serializing_if = "StringMap::is_empty")] + interfaces: StringMap, + #[serde(default, skip_serializing_if = "StringMap::is_empty")] + types: StringMap, + #[serde(default, skip_serializing_if = "StringMap::is_empty")] + funcs: StringMap, +} + +impl WorldDocs { + fn extract(resolve: &Resolve, id: WorldId) -> Self { + let world = &resolve.worlds[id]; + + let mut interfaces = StringMap::default(); + let mut types = StringMap::default(); + let mut funcs = StringMap::default(); + + // Iterate over all imports and exports, extracting documented items + for (key, item) in world.imports.iter().chain(&world.exports) { + if let WorldKey::Name(name) = key { + match item { + WorldItem::Interface(id) => { + let docs = InterfaceDocs::extract(resolve, *id); + if !docs.is_empty() { + interfaces.insert(name.to_string(), docs); + } + } + WorldItem::Type(id) => { + let docs = TypeDocs::extract(resolve, *id); + if !docs.is_empty() { + types.insert(name.to_string(), docs); + } + } + WorldItem::Function(f) => { + if let Some(docs) = f.docs.contents.as_deref() { + funcs.insert(name.to_string(), docs.to_string()); + } + } + } + } + } + + Self { + docs: world.docs.contents.clone(), + interfaces, + types, + funcs, + } + } + + fn inject(&self, resolve: &mut Resolve, id: WorldId) -> Result<()> { + for (name, docs) in &self.interfaces { + let key = WorldKey::Name(name.to_string()); + let Some(WorldItem::Interface(id)) = resolve.worlds[id] + .imports + .get(&key) + .or_else(|| resolve.worlds[id].exports.get(&key)) + else { + bail!("missing interface {name:?}"); + }; + docs.inject(resolve, *id)?; + } + for (name, docs) in &self.types { + let key = WorldKey::Name(name.to_string()); + let Some(WorldItem::Type(id)) = resolve.worlds[id] + .imports + .get(&key) + .or_else(|| resolve.worlds[id].exports.get(&key)) + else { + bail!("missing type {name:?}"); + }; + docs.inject(resolve, *id)?; + } + let world = &mut resolve.worlds[id]; + for (name, docs) in &self.funcs { + let key = WorldKey::Name(name.to_string()); + if let Some(WorldItem::Function(f)) = world.exports.get_mut(&key) { + f.docs.contents = Some(docs.to_string()) + } else if let Some(WorldItem::Function(f)) = world.imports.get_mut(&key) { + f.docs.contents = Some(docs.to_string()) + } else { + bail!("missing func {name:?}"); + }; + } + if let Some(docs) = &self.docs { + world.docs.contents = Some(docs.to_string()); + } + Ok(()) + } + + fn is_empty(&self) -> bool { + self.docs.is_none() + && self.interfaces.is_empty() + && self.types.is_empty() + && self.funcs.is_empty() + } +} + +#[derive(Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct InterfaceDocs { + #[serde(default, skip_serializing_if = "Option::is_none")] + docs: Option, + #[serde(default, skip_serializing_if = "StringMap::is_empty")] + funcs: StringMap, + #[serde(default, skip_serializing_if = "StringMap::is_empty")] + types: StringMap, +} + +impl InterfaceDocs { + fn extract(resolve: &Resolve, id: InterfaceId) -> Self { + let interface = &resolve.interfaces[id]; + + let funcs = interface + .functions + .iter() + .flat_map(|(name, func)| Some((name.to_string(), func.docs.contents.clone()?))) + .collect(); + let types = interface + .types + .iter() + .map(|(name, id)| (name.to_string(), TypeDocs::extract(resolve, *id))) + .filter(|(_, item)| !item.is_empty()) + .collect(); + + Self { + docs: interface.docs.contents.clone(), + funcs, + types, + } + } + + fn inject(&self, resolve: &mut Resolve, id: InterfaceId) -> Result<()> { + for (name, docs) in &self.types { + let Some(&id) = resolve.interfaces[id].types.get(name) else { + bail!("missing type {name:?}"); + }; + docs.inject(resolve, id)?; + } + let interface = &mut resolve.interfaces[id]; + for (name, docs) in &self.funcs { + let Some(f) = interface.functions.get_mut(name) else { + bail!("missing func {name:?}"); + }; + f.docs.contents = Some(docs.to_string()); + } + if let Some(docs) = &self.docs { + interface.docs.contents = Some(docs.to_string()); + } + Ok(()) + } + + fn is_empty(&self) -> bool { + self.docs.is_none() && self.funcs.is_empty() && self.types.is_empty() + } +} + +#[derive(Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TypeDocs { + #[serde(default, skip_serializing_if = "Option::is_none")] + docs: Option, + // record fields, variant cases, etc. + #[serde(default, skip_serializing_if = "StringMap::is_empty")] + items: StringMap, +} + +impl TypeDocs { + fn extract(resolve: &Resolve, id: TypeId) -> Self { + fn extract_items(items: &[T], f: impl Fn(&T) -> (&String, &Docs)) -> StringMap { + items + .iter() + .flat_map(|item| { + let (name, docs) = f(item); + Some((name.to_string(), docs.contents.clone()?)) + }) + .collect() + } + let ty = &resolve.types[id]; + let items = match &ty.kind { + wit_parser::TypeDefKind::Record(record) => { + extract_items(&record.fields, |item| (&item.name, &item.docs)) + } + wit_parser::TypeDefKind::Flags(flags) => { + extract_items(&flags.flags, |item| (&item.name, &item.docs)) + } + wit_parser::TypeDefKind::Variant(variant) => { + extract_items(&variant.cases, |item| (&item.name, &item.docs)) + } + wit_parser::TypeDefKind::Enum(enum_) => { + extract_items(&enum_.cases, |item| (&item.name, &item.docs)) + } + // other types don't have inner items + _ => IndexMap::default(), + }; + + Self { + docs: ty.docs.contents.clone(), + items, + } + } + + fn inject(&self, resolve: &mut Resolve, id: TypeId) -> Result<()> { + let ty = &mut resolve.types[id]; + if !self.items.is_empty() { + match &mut ty.kind { + wit_parser::TypeDefKind::Record(record) => { + self.inject_items(&mut record.fields, |item| (&item.name, &mut item.docs))? + } + wit_parser::TypeDefKind::Flags(flags) => { + self.inject_items(&mut flags.flags, |item| (&item.name, &mut item.docs))? + } + wit_parser::TypeDefKind::Variant(variant) => { + self.inject_items(&mut variant.cases, |item| (&item.name, &mut item.docs))? + } + wit_parser::TypeDefKind::Enum(enum_) => { + self.inject_items(&mut enum_.cases, |item| (&item.name, &mut item.docs))? + } + _ => { + bail!("got 'items' for unexpected type {ty:?}"); + } + } + } + if let Some(docs) = &self.docs { + ty.docs.contents = Some(docs.to_string()); + } + Ok(()) + } + + fn inject_items( + &self, + items: &mut [T], + f: impl Fn(&mut T) -> (&String, &mut Docs), + ) -> Result<()> { + let mut unused_docs = self.items.len(); + for item in items.iter_mut() { + let (name, item_docs) = f(item); + if let Some(docs) = self.items.get(name.as_str()) { + item_docs.contents = Some(docs.to_string()); + unused_docs -= 1; + } + } + if unused_docs > 0 { + bail!( + "not all 'items' match type items; {item_docs:?} vs {items:?}", + item_docs = self.items + ); + } + Ok(()) + } + + fn is_empty(&self) -> bool { + self.docs.is_none() && self.items.is_empty() + } +} diff --git a/crates/wit-component/src/encoding/types.rs b/crates/wit-component/src/encoding/types.rs new file mode 100644 index 0000000000..d660612e93 --- /dev/null +++ b/crates/wit-component/src/encoding/types.rs @@ -0,0 +1,429 @@ +use super::EncodingState; +use anyhow::Result; +use std::collections::HashMap; +use wasm_encoder::*; +use wit_parser::{ + Enum, Flags, Function, Handle, InterfaceId, Params, Record, Resolve, Result_, Results, Tuple, + Type, TypeDefKind, TypeId, TypeOwner, Variant, +}; + +/// Represents a key type for interface function definitions. +#[derive(Hash, PartialEq, Eq)] +pub struct FunctionKey<'a> { + params: &'a Params, + results: &'a Results, +} + +/// Support for encoding a wit-parser type into a component. +/// +/// This is a `trait` to enable different implementations which define types +/// slightly differently in different contexts. For example types might be +/// defined within an instance type's index space or might be defined in the +/// component's root index space in a type section. The default trait methods +/// here are intended to assist in multiplexing over this difference. +pub trait ValtypeEncoder<'a> { + /// Returns a new type encoder used to define a new type in this type + /// section. + /// + /// The `u32` returned is the index of the type being defined in this type + /// index space and the encoder returned must be used to define a type. + fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>); + + /// Returns the index of a new function type and the encoder of where to + /// place its results. + fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>); + + /// Creates an export item for the specified type index. + fn export_type(&mut self, index: u32, name: &'a str) -> Option; + + /// Creates a new `(type (sub resource))` export with the given name, + /// returning the type index that refers to the fresh type created. + fn export_resource(&mut self, name: &'a str) -> u32; + + /// Returns a map of all types previously defined in this type index space. + fn type_map(&mut self) -> &mut HashMap; + + /// Imports `id` from a different interface, returning the index of the + /// imported type into this index space. + fn import_type(&mut self, interface: InterfaceId, id: TypeId) -> u32; + + /// Returns the identifier of the interface that generation is for. + fn interface(&self) -> Option; + + /// Returns the map of already-defined function types in this type index + /// space. + fn func_type_map(&mut self) -> &mut HashMap, u32>; + + /// Encodes a new function type which is defined within the provided + /// document. + fn encode_func_type(&mut self, resolve: &'a Resolve, func: &'a Function) -> Result { + let key = FunctionKey { + params: &func.params, + results: &func.results, + }; + if let Some(index) = self.func_type_map().get(&key) { + return Ok(*index); + } + + // Encode all referenced parameter types from this function. + let params: Vec<_> = self.encode_params(resolve, &func.params)?; + + enum EncodedResults<'a> { + Named(Vec<(&'a str, ComponentValType)>), + Anon(ComponentValType), + } + + let results = match &func.results { + Results::Named(rs) => EncodedResults::Named(self.encode_params(resolve, rs)?), + Results::Anon(ty) => EncodedResults::Anon(self.encode_valtype(resolve, ty)?), + }; + + // Encode the function type + let (index, mut f) = self.define_function_type(); + f.params(params); + match results { + EncodedResults::Named(rs) => f.results(rs), + EncodedResults::Anon(ty) => f.result(ty), + }; + let prev = self.func_type_map().insert(key, index); + assert!(prev.is_none()); + Ok(index) + } + + fn encode_params( + &mut self, + resolve: &'a Resolve, + params: &'a Params, + ) -> Result> { + params + .iter() + .map(|(name, ty)| Ok((name.as_str(), self.encode_valtype(resolve, ty)?))) + .collect::>() + } + + /// Encodes the `ty`, defined within `resolve`, into this encoder and returns + /// the corresponding `ComponentValType` that it represents. + /// + /// This will recursively define the entire structure of `ty` within `self` + /// if necessary. + fn encode_valtype(&mut self, resolve: &'a Resolve, ty: &Type) -> Result { + Ok(match *ty { + Type::Bool => ComponentValType::Primitive(PrimitiveValType::Bool), + Type::U8 => ComponentValType::Primitive(PrimitiveValType::U8), + Type::U16 => ComponentValType::Primitive(PrimitiveValType::U16), + Type::U32 => ComponentValType::Primitive(PrimitiveValType::U32), + Type::U64 => ComponentValType::Primitive(PrimitiveValType::U64), + Type::S8 => ComponentValType::Primitive(PrimitiveValType::S8), + Type::S16 => ComponentValType::Primitive(PrimitiveValType::S16), + Type::S32 => ComponentValType::Primitive(PrimitiveValType::S32), + Type::S64 => ComponentValType::Primitive(PrimitiveValType::S64), + Type::Float32 => ComponentValType::Primitive(PrimitiveValType::Float32), + Type::Float64 => ComponentValType::Primitive(PrimitiveValType::Float64), + Type::Char => ComponentValType::Primitive(PrimitiveValType::Char), + Type::String => ComponentValType::Primitive(PrimitiveValType::String), + Type::Id(id) => { + // If this id has already been prior defined into this section + // refer to that definition. + if let Some(index) = self.type_map().get(&id) { + return Ok(ComponentValType::Type(*index)); + } + + // If this type is imported from another interface then return + // it as it was bound here with an alias. + let ty = &resolve.types[id]; + log::trace!("encode type name={:?} {:?}", ty.name, &ty.kind); + if let Some(index) = self.maybe_import_type(resolve, id) { + self.type_map().insert(id, index); + return Ok(ComponentValType::Type(index)); + } + + // ... and failing all that insert the type export. + let mut encoded = match &ty.kind { + TypeDefKind::Record(r) => self.encode_record(resolve, r)?, + TypeDefKind::Tuple(t) => self.encode_tuple(resolve, t)?, + TypeDefKind::Flags(r) => self.encode_flags(r)?, + TypeDefKind::Variant(v) => self.encode_variant(resolve, v)?, + TypeDefKind::Option(t) => self.encode_option(resolve, t)?, + TypeDefKind::Result(r) => self.encode_result(resolve, r)?, + TypeDefKind::Enum(e) => self.encode_enum(e)?, + TypeDefKind::List(ty) => { + let ty = self.encode_valtype(resolve, ty)?; + let (index, encoder) = self.defined_type(); + encoder.list(ty); + ComponentValType::Type(index) + } + TypeDefKind::Type(ty) => self.encode_valtype(resolve, ty)?, + TypeDefKind::Future(_) => todo!("encoding for future type"), + TypeDefKind::Stream(_) => todo!("encoding for stream type"), + TypeDefKind::Unknown => unreachable!(), + TypeDefKind::Resource => { + let name = ty.name.as_ref().expect("resources must be named"); + let index = self.export_resource(name); + self.type_map().insert(id, index); + return Ok(ComponentValType::Type(index)); + } + TypeDefKind::Handle(Handle::Own(id)) => { + let ty = match self.encode_valtype(resolve, &Type::Id(*id))? { + ComponentValType::Type(index) => index, + _ => panic!("must be an indexed type"), + }; + let (index, encoder) = self.defined_type(); + encoder.own(ty); + ComponentValType::Type(index) + } + TypeDefKind::Handle(Handle::Borrow(id)) => { + let ty = match self.encode_valtype(resolve, &Type::Id(*id))? { + ComponentValType::Type(index) => index, + _ => panic!("must be an indexed type"), + }; + let (index, encoder) = self.defined_type(); + encoder.borrow(ty); + ComponentValType::Type(index) + } + }; + + if let Some(name) = &ty.name { + let index = match encoded { + ComponentValType::Type(index) => index, + ComponentValType::Primitive(ty) => { + // Named primitive types need entries in the type + // section, so convert this to a type reference + let (index, encoder) = self.defined_type(); + encoder.primitive(ty); + index + } + }; + let index = self.export_type(index, name).unwrap_or(index); + + encoded = ComponentValType::Type(index); + } + + if let ComponentValType::Type(index) = encoded { + self.type_map().insert(id, index); + } + + encoded + } + }) + } + + /// Optionally imports `id` from a different interface, returning the index + /// of the imported type into this index space. + /// + /// Returns `None` if `id` can't be imported. + fn maybe_import_type(&mut self, resolve: &Resolve, id: TypeId) -> Option { + let ty = &resolve.types[id]; + let owner = match ty.owner { + TypeOwner::Interface(i) => i, + _ => return None, + }; + if Some(owner) == self.interface() { + return None; + } + Some(self.import_type(owner, id)) + } + + fn encode_optional_valtype( + &mut self, + resolve: &'a Resolve, + ty: Option<&Type>, + ) -> Result> { + match ty { + Some(ty) => self.encode_valtype(resolve, ty).map(Some), + None => Ok(None), + } + } + + fn encode_record(&mut self, resolve: &'a Resolve, record: &Record) -> Result { + let fields = record + .fields + .iter() + .map(|f| Ok((f.name.as_str(), self.encode_valtype(resolve, &f.ty)?))) + .collect::>>()?; + + let (index, encoder) = self.defined_type(); + encoder.record(fields); + Ok(ComponentValType::Type(index)) + } + + fn encode_tuple(&mut self, resolve: &'a Resolve, tuple: &Tuple) -> Result { + let tys = tuple + .types + .iter() + .map(|ty| self.encode_valtype(resolve, ty)) + .collect::>>()?; + let (index, encoder) = self.defined_type(); + encoder.tuple(tys); + Ok(ComponentValType::Type(index)) + } + + fn encode_flags(&mut self, flags: &Flags) -> Result { + let (index, encoder) = self.defined_type(); + encoder.flags(flags.flags.iter().map(|f| f.name.as_str())); + Ok(ComponentValType::Type(index)) + } + + fn encode_variant( + &mut self, + resolve: &'a Resolve, + variant: &Variant, + ) -> Result { + let cases = variant + .cases + .iter() + .map(|c| { + Ok(( + c.name.as_str(), + self.encode_optional_valtype(resolve, c.ty.as_ref())?, + None, // TODO: support defaulting case values in the future + )) + }) + .collect::>>()?; + + let (index, encoder) = self.defined_type(); + encoder.variant(cases); + Ok(ComponentValType::Type(index)) + } + + fn encode_option(&mut self, resolve: &'a Resolve, payload: &Type) -> Result { + let ty = self.encode_valtype(resolve, payload)?; + let (index, encoder) = self.defined_type(); + encoder.option(ty); + Ok(ComponentValType::Type(index)) + } + + fn encode_result( + &mut self, + resolve: &'a Resolve, + result: &Result_, + ) -> Result { + let ok = self.encode_optional_valtype(resolve, result.ok.as_ref())?; + let error = self.encode_optional_valtype(resolve, result.err.as_ref())?; + let (index, encoder) = self.defined_type(); + encoder.result(ok, error); + Ok(ComponentValType::Type(index)) + } + + fn encode_enum(&mut self, enum_: &Enum) -> Result { + let (index, encoder) = self.defined_type(); + encoder.enum_type(enum_.cases.iter().map(|c| c.name.as_str())); + Ok(ComponentValType::Type(index)) + } +} + +pub struct RootTypeEncoder<'state, 'a> { + pub state: &'state mut EncodingState<'a>, + pub interface: Option, + pub import_types: bool, +} + +impl<'a> ValtypeEncoder<'a> for RootTypeEncoder<'_, 'a> { + fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { + self.state.component.type_defined() + } + fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { + self.state.component.type_function() + } + fn interface(&self) -> Option { + self.interface + } + fn export_type(&mut self, idx: u32, name: &'a str) -> Option { + // When encoding types for the root the root component will export + // this type, but when encoding types for a targeted interface then we + // can't export types just yet. Interfaces will be created as an + // instance with a bag-of-exports construction which can't refer to its + // own types. + if self.interface.is_none() { + Some(if self.import_types { + self.state + .component + .import(name, ComponentTypeRef::Type(TypeBounds::Eq(idx))) + } else { + self.state + .component + .export(name, ComponentExportKind::Type, idx, None) + }) + } else { + assert!(!self.import_types); + None + } + } + fn export_resource(&mut self, name: &'a str) -> u32 { + assert!(self.interface.is_none()); + assert!(self.import_types); + self.state + .component + .import(name, ComponentTypeRef::Type(TypeBounds::SubResource)) + } + fn import_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 { + if !self.import_types { + if let Some(cur) = self.interface { + let set = &self.state.info.exports_used[&cur]; + if set.contains(&interface) { + return self.state.alias_exported_type(interface, id); + } + } + } + self.state.alias_imported_type(interface, id) + } + fn type_map(&mut self) -> &mut HashMap { + if self.import_types { + &mut self.state.import_type_map + } else { + &mut self.state.export_type_map + } + } + fn func_type_map(&mut self) -> &mut HashMap, u32> { + if self.import_types { + &mut self.state.import_func_type_map + } else { + &mut self.state.export_func_type_map + } + } +} + +pub struct InstanceTypeEncoder<'state, 'a> { + pub state: &'state mut EncodingState<'a>, + pub interface: InterfaceId, + pub type_map: HashMap, + pub func_type_map: HashMap, u32>, + pub ty: InstanceType, +} + +impl<'a> ValtypeEncoder<'a> for InstanceTypeEncoder<'_, 'a> { + fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { + (self.ty.type_count(), self.ty.ty().defined_type()) + } + fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { + (self.ty.type_count(), self.ty.ty().function()) + } + fn export_type(&mut self, idx: u32, name: &str) -> Option { + let ret = self.ty.type_count(); + self.ty + .export(name, ComponentTypeRef::Type(TypeBounds::Eq(idx))); + Some(ret) + } + fn export_resource(&mut self, name: &str) -> u32 { + let ret = self.ty.type_count(); + self.ty + .export(name, ComponentTypeRef::Type(TypeBounds::SubResource)); + ret + } + fn type_map(&mut self) -> &mut HashMap { + &mut self.type_map + } + fn interface(&self) -> Option { + Some(self.interface) + } + fn import_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 { + self.ty.alias(Alias::Outer { + count: 1, + index: self.state.alias_imported_type(interface, id), + kind: ComponentOuterAliasKind::Type, + }); + self.ty.type_count() - 1 + } + fn func_type_map(&mut self) -> &mut HashMap, u32> { + &mut self.func_type_map + } +} diff --git a/crates/wit-component/src/encoding/wit.rs b/crates/wit-component/src/encoding/wit.rs new file mode 100644 index 0000000000..0c90dcc03b --- /dev/null +++ b/crates/wit-component/src/encoding/wit.rs @@ -0,0 +1,404 @@ +use crate::encoding::types::{FunctionKey, ValtypeEncoder}; +use anyhow::Result; +use indexmap::IndexSet; +use std::collections::HashMap; +use std::mem; +use wasm_encoder::*; +use wit_parser::*; + +use super::docs::PackageDocs; + +/// Encodes the given `package` within `resolve` to a binary WebAssembly +/// representation. +/// +/// This function is the root of the implementation of serializing a WIT package +/// into a WebAssembly representation. The wasm representation serves two +/// purposes: +/// +/// * One is to be a binary encoding of a WIT document which is ideally more +/// stable than the WIT textual format itself. +/// * Another is to provide a clear mapping of all WIT features into the +/// component model through use of its binary representation. +/// +/// The `resolve` provided is a set of packages and types and such and the +/// `package` argument is an ID within the world provided. The documents within +/// `package` will all be encoded into the binary returned. +/// +/// The binary returned can be [`decode`d](crate::decode) to recover the WIT +/// package provided. +pub fn encode(resolve: &Resolve, package: PackageId) -> Result> { + let mut component = encode_component(resolve, package)?; + component.raw_custom_section(&crate::base_producers().raw_custom_section()); + Ok(component.finish()) +} + +/// Exactly like `encode`, except gives an unfinished `ComponentBuilder` in case you need +/// to append anything else before finishing. +pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result { + let mut encoder = Encoder { + component: ComponentBuilder::default(), + resolve, + package, + }; + encoder.run()?; + + let package_docs = PackageDocs::extract(resolve, package); + encoder + .component + .raw_custom_section(&package_docs.raw_custom_section()?); + + Ok(encoder.component) +} + +struct Encoder<'a> { + component: ComponentBuilder, + resolve: &'a Resolve, + package: PackageId, +} + +impl Encoder<'_> { + fn run(&mut self) -> Result<()> { + // Build a set of interfaces reachable from this document, including the + // interfaces in the document itself. This is used to import instances + // into the component type we're encoding. Note that entire interfaces + // are imported with all their types as opposed to just the needed types + // in an interface for this document. That's done to assist with the + // decoding process where everyone's view of a foreign document agrees + // notably on the order that types are defined in to assist with + // roundtripping. + let mut interfaces = IndexSet::new(); + for (_, id) in self.resolve.packages[self.package].interfaces.iter() { + self.add_live_interfaces(&mut interfaces, *id); + } + + // Seed the set of used names with all exported interfaces to ensure + // that imported interfaces choose different names as the import names + // aren't used during decoding. + let mut used_names = IndexSet::new(); + for id in interfaces.iter() { + let iface = &self.resolve.interfaces[*id]; + if iface.package == Some(self.package) { + let first = used_names.insert(iface.name.as_ref().unwrap().clone()); + assert!(first); + } + } + for (name, _world) in self.resolve.packages[self.package].worlds.iter() { + let first = used_names.insert(name.clone()); + assert!(first); + } + + // Encode all interfaces, foreign and local, into this component type. + // Local interfaces get their functions defined as well and are + // exported. Foreign interfaces are imported and only have their types + // encoded. + let mut encoder = InterfaceEncoder::new(self.resolve); + for interface in interfaces { + encoder.interface = Some(interface); + let iface = &self.resolve.interfaces[interface]; + let name = self.resolve.id_of(interface).unwrap(); + log::trace!("encoding interface {name}"); + if iface.package == Some(self.package) { + let idx = encoder.encode_instance(interface)?; + encoder.outer.export(&name, ComponentTypeRef::Instance(idx)); + } else { + encoder.push_instance(); + for (_, id) in iface.types.iter() { + encoder.encode_valtype(self.resolve, &Type::Id(*id))?; + } + let instance = encoder.pop_instance(); + let idx = encoder.outer.type_count(); + encoder.outer.ty().instance(&instance); + encoder.import_map.insert(interface, encoder.instances); + encoder.instances += 1; + encoder.outer.import(&name, ComponentTypeRef::Instance(idx)); + } + } + encoder.interface = None; + + for (name, world) in self.resolve.packages[self.package].worlds.iter() { + let component_ty = encode_world(self.resolve, *world)?; + let idx = encoder.outer.type_count(); + encoder.outer.ty().component(&component_ty); + let id = self.resolve.packages[self.package].name.interface_id(name); + encoder.outer.export(&id, ComponentTypeRef::Component(idx)); + } + + let ty = self.component.type_component(&encoder.outer); + let id = self.resolve.packages[self.package].name.interface_id("wit"); + self.component + .export(&id, ComponentExportKind::Type, ty, None); + Ok(()) + } + + /// Recursively add all live interfaces reachable from `id` into the + /// `interfaces` set, and then add `id` to the set. + fn add_live_interfaces(&self, interfaces: &mut IndexSet, id: InterfaceId) { + if interfaces.contains(&id) { + return; + } + for id in self.resolve.interface_direct_deps(id) { + self.add_live_interfaces(interfaces, id); + } + assert!(interfaces.insert(id)); + } +} + +struct InterfaceEncoder<'a> { + resolve: &'a Resolve, + outer: ComponentType, + ty: Option, + func_type_map: HashMap, u32>, + type_map: HashMap, + saved_types: Option<(HashMap, HashMap, u32>)>, + import_map: HashMap, + outer_type_map: HashMap, + instances: u32, + import_types: bool, + interface: Option, +} + +impl InterfaceEncoder<'_> { + fn new(resolve: &Resolve) -> InterfaceEncoder<'_> { + InterfaceEncoder { + resolve, + outer: ComponentType::new(), + ty: None, + type_map: Default::default(), + func_type_map: Default::default(), + import_map: Default::default(), + outer_type_map: Default::default(), + instances: 0, + saved_types: None, + import_types: false, + interface: None, + } + } + + fn encode_instance(&mut self, interface: InterfaceId) -> Result { + self.push_instance(); + let iface = &self.resolve.interfaces[interface]; + let mut type_order = IndexSet::new(); + for (_, id) in iface.types.iter() { + self.encode_valtype(self.resolve, &Type::Id(*id))?; + type_order.insert(*id); + } + + // Sort functions based on whether or not they're associated with + // resources. + // + // This is done here to ensure that when a WIT package is printed as WIT + // then decoded, or if it's printed as Wasm then decoded, the final + // result is the same. When printing via WIT resource methods are + // attached to the resource types themselves meaning that they'll appear + // intermingled with the rest of the types, namely first before all + // other functions. The purpose of this sort is to perform a stable sort + // over all functions by shuffling the resource-related functions first, + // in order of when their associated resource was encoded, and putting + // freestanding functions last. + // + // Note that this is not actually required for correctness, it's + // basically here to make fuzzing happy. + let mut funcs = iface.functions.iter().collect::>(); + funcs.sort_by_key(|(_name, func)| match func.kind { + FunctionKind::Freestanding => type_order.len(), + FunctionKind::Method(id) | FunctionKind::Constructor(id) | FunctionKind::Static(id) => { + type_order.get_index_of(&id).unwrap() + } + }); + + for (name, func) in funcs { + let ty = self.encode_func_type(self.resolve, func)?; + self.ty + .as_mut() + .unwrap() + .export(name, ComponentTypeRef::Func(ty)); + } + let instance = self.pop_instance(); + let idx = self.outer.type_count(); + self.outer.ty().instance(&instance); + self.import_map.insert(interface, self.instances); + self.instances += 1; + Ok(idx) + } + + fn push_instance(&mut self) { + assert!(self.ty.is_none()); + assert!(self.saved_types.is_none()); + self.saved_types = Some(( + mem::take(&mut self.type_map), + mem::take(&mut self.func_type_map), + )); + self.ty = Some(InstanceType::default()); + } + + fn pop_instance(&mut self) -> InstanceType { + let (types, funcs) = self.saved_types.take().unwrap(); + self.type_map = types; + self.func_type_map = funcs; + mem::take(&mut self.ty).unwrap() + } +} + +impl<'a> ValtypeEncoder<'a> for InterfaceEncoder<'a> { + fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { + match &mut self.ty { + Some(ty) => (ty.type_count(), ty.ty().defined_type()), + None => (self.outer.type_count(), self.outer.ty().defined_type()), + } + } + fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { + match &mut self.ty { + Some(ty) => (ty.type_count(), ty.ty().function()), + None => (self.outer.type_count(), self.outer.ty().function()), + } + } + fn export_type(&mut self, index: u32, name: &'a str) -> Option { + match &mut self.ty { + Some(ty) => { + assert!(!self.import_types); + let ret = ty.type_count(); + ty.export(name, ComponentTypeRef::Type(TypeBounds::Eq(index))); + Some(ret) + } + None => { + let ret = self.outer.type_count(); + if self.import_types { + self.outer + .import(name, ComponentTypeRef::Type(TypeBounds::Eq(index))); + } else { + self.outer + .export(name, ComponentTypeRef::Type(TypeBounds::Eq(index))); + } + Some(ret) + } + } + } + fn export_resource(&mut self, name: &'a str) -> u32 { + let type_ref = ComponentTypeRef::Type(TypeBounds::SubResource); + match &mut self.ty { + Some(ty) => { + assert!(!self.import_types); + ty.export(name, type_ref); + ty.type_count() - 1 + } + None => { + if self.import_types { + self.outer.import(name, type_ref); + } else { + self.outer.export(name, type_ref); + } + self.outer.type_count() - 1 + } + } + } + fn type_map(&mut self) -> &mut HashMap { + &mut self.type_map + } + fn interface(&self) -> Option { + self.interface + } + fn import_type(&mut self, owner: InterfaceId, id: TypeId) -> u32 { + let ty = &self.resolve.types[id]; + let instance = self.import_map[&owner]; + let outer_idx = *self.outer_type_map.entry(id).or_insert_with(|| { + let ret = self.outer.type_count(); + self.outer.alias(Alias::InstanceExport { + instance, + name: ty.name.as_ref().unwrap(), + kind: ComponentExportKind::Type, + }); + ret + }); + match &mut self.ty { + Some(ty) => { + let ret = ty.type_count(); + ty.alias(Alias::Outer { + count: 1, + index: outer_idx, + kind: ComponentOuterAliasKind::Type, + }); + ret + } + None => outer_idx, + } + } + fn func_type_map(&mut self) -> &mut HashMap, u32> { + &mut self.func_type_map + } +} + +/// Encodes a `world` as a component type. +pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result { + let mut component = InterfaceEncoder::new(resolve); + let world = &resolve.worlds[world_id]; + log::trace!("encoding world {}", world.name); + + // This sort is similar in purpose to the sort below in + // `encode_instance`, but different in its sort. The purpose here is + // to ensure that when a document is either printed as WIT or + // encoded as wasm that decoding from those artifacts produces the + // same WIT package. Namely both encoding processes should encode + // things in the same order. + // + // When printing worlds in WIT freestanding function imports are + // printed first, then types. Resource functions are attached to + // types which means that they all come last. Sort all + // resource-related functions here to the back of the `imports` list + // while keeping everything else in front, using a stable sort to + // preserve preexisting ordering. + let mut imports = world.imports.iter().collect::>(); + imports.sort_by_key(|(_name, import)| match import { + WorldItem::Function(f) => match f.kind { + FunctionKind::Freestanding => 0, + _ => 1, + }, + _ => 0, + }); + + // Encode the imports + for (name, import) in imports { + let name = resolve.name_world_key(name); + log::trace!("encoding import {name}"); + let ty = match import { + WorldItem::Interface(i) => { + component.interface = Some(*i); + let idx = component.encode_instance(*i)?; + ComponentTypeRef::Instance(idx) + } + WorldItem::Function(f) => { + component.interface = None; + let idx = component.encode_func_type(resolve, f)?; + ComponentTypeRef::Func(idx) + } + WorldItem::Type(t) => { + component.interface = None; + component.import_types = true; + component.encode_valtype(resolve, &Type::Id(*t))?; + component.import_types = false; + continue; + } + }; + component.outer.import(&name, ty); + } + // Encode the exports + for (name, export) in world.exports.iter() { + let name = resolve.name_world_key(name); + log::trace!("encoding export {name}"); + let ty = match export { + WorldItem::Interface(i) => { + component.interface = Some(*i); + let idx = component.encode_instance(*i)?; + ComponentTypeRef::Instance(idx) + } + WorldItem::Function(f) => { + component.interface = None; + let idx = component.encode_func_type(resolve, f)?; + ComponentTypeRef::Func(idx) + } + WorldItem::Type(_) => unreachable!(), + }; + component.outer.export(&name, ty); + } + + Ok(component.outer) +} diff --git a/crates/wit-component/src/encoding/world.rs b/crates/wit-component/src/encoding/world.rs new file mode 100644 index 0000000000..47b9087876 --- /dev/null +++ b/crates/wit-component/src/encoding/world.rs @@ -0,0 +1,489 @@ +use super::{Adapter, ComponentEncoder, LibraryInfo, RequiredOptions}; +use crate::validation::{ + validate_adapter_module, validate_module, RequiredImports, ValidatedAdapter, ValidatedModule, + BARE_FUNC_MODULE_NAME, RESOURCE_DROP, +}; +use anyhow::{Context, Result}; +use indexmap::{IndexMap, IndexSet}; +use std::borrow::{Borrow, Cow}; +use std::collections::{HashMap, HashSet}; +use std::hash::Hash; +use wasmparser::FuncType; +use wit_parser::{ + abi::{AbiVariant, WasmSignature, WasmType}, + Function, InterfaceId, LiveTypes, Resolve, TypeDefKind, TypeId, TypeOwner, WorldId, WorldItem, + WorldKey, +}; + +pub struct WorldAdapter<'a> { + pub wasm: Cow<'a, [u8]>, + pub info: ValidatedAdapter<'a>, + pub library_info: Option<&'a LibraryInfo>, +} + +/// Metadata discovered from the state configured in a `ComponentEncoder`. +/// +/// This is stored separately from `EncodingState` to be stored as a borrow in +/// `EncodingState` as this information doesn't change throughout the encoding +/// process. +pub struct ComponentWorld<'a> { + /// Encoder configuration with modules, the document ,etc. + pub encoder: &'a ComponentEncoder, + /// Validation information of the input module, or `None` in `--types-only` + /// mode. + pub info: ValidatedModule<'a>, + /// Validation information about adapters populated only for required + /// adapters. Additionally stores the gc'd wasm for each adapter. + pub adapters: IndexMap<&'a str, WorldAdapter<'a>>, + /// Map of all imports and descriptions of what they're importing. + pub import_map: IndexMap, ImportedInterface>, + /// Set of all live types which must be exported either because they're + /// directly used or because they're transitively used. + pub live_type_imports: IndexMap>, + /// For each exported interface in the desired world this map lists + /// the set of interfaces that it depends on which are also exported. + /// + /// This set is used to determine when types are imported/used whether they + /// come from imports or exports. + pub exports_used: HashMap>, +} + +#[derive(Debug)] +pub struct ImportedInterface { + pub lowerings: IndexMap, + pub interface: Option, +} + +#[derive(Debug)] +pub enum Lowering { + Direct, + Indirect { + sig: WasmSignature, + options: RequiredOptions, + }, + ResourceDrop(TypeId), +} + +impl<'a> ComponentWorld<'a> { + pub fn new(encoder: &'a ComponentEncoder) -> Result { + let adapters = encoder + .adapters + .keys() + .map(|s| s.as_str()) + .collect::>(); + let info = validate_module( + &encoder.module, + &encoder.metadata, + &encoder.main_module_exports, + &adapters, + )?; + + let mut ret = ComponentWorld { + encoder, + info, + adapters: IndexMap::new(), + import_map: IndexMap::new(), + live_type_imports: Default::default(), + exports_used: HashMap::new(), + }; + + ret.process_adapters()?; + ret.process_imports()?; + ret.process_exports_used(); + ret.process_live_type_imports(); + + Ok(ret) + } + + /// Process adapters which are required here. Iterate over all + /// adapters and figure out what functions are required from the + /// adapter itself, either because the functions are imported by the + /// main module or they're part of the adapter's exports. + fn process_adapters(&mut self) -> Result<()> { + let resolve = &self.encoder.metadata.resolve; + let world = self.encoder.metadata.world; + for ( + name, + Adapter { + wasm, + metadata, + required_exports, + library_info, + }, + ) in self.encoder.adapters.iter() + { + let required_by_import = self.info.adapters_required.get(name.as_str()); + let no_required_by_import = || required_by_import.map(|m| m.is_empty()).unwrap_or(true); + let no_required_exports = || { + required_exports + .iter() + .all(|name| match &resolve.worlds[world].exports[name] { + WorldItem::Function(_) => false, + WorldItem::Interface(id) => resolve.interfaces[*id].functions.is_empty(), + WorldItem::Type(_) => true, + }) + }; + if no_required_by_import() && no_required_exports() && library_info.is_none() { + continue; + } + let wasm = if library_info.is_some() { + Cow::Borrowed(wasm as &[u8]) + } else { + let required = self.required_adapter_exports( + resolve, + world, + required_exports, + required_by_import, + ); + + Cow::Owned( + crate::gc::run( + wasm, + &required, + if self.encoder.realloc_via_memory_grow { + None + } else { + self.info.realloc + }, + ) + .context("failed to reduce input adapter module to its minimal size")?, + ) + }; + let info = validate_adapter_module( + &wasm, + resolve, + world, + metadata, + required_by_import, + required_exports, + library_info.is_some(), + ) + .context("failed to validate the imports of the minimized adapter module")?; + self.adapters.insert( + name, + WorldAdapter { + info, + wasm, + library_info: library_info.as_ref(), + }, + ); + } + Ok(()) + } + + /// Returns the set of functions required to be exported from an adapter, + /// either because they're exported from the adapter's world or because + /// they're required as an import to the main module. + fn required_adapter_exports<'r>( + &self, + resolve: &'r Resolve, + world: WorldId, + required_exports: &IndexSet, + required_by_import: Option<&IndexMap<&str, FuncType>>, + ) -> IndexMap)> { + use wasmparser::ValType; + + let mut required = IndexMap::new(); + if let Some(imports) = required_by_import { + for (name, ty) in imports { + required.insert(name.to_string(), (ty.clone(), None)); + } + } + let mut add_func = |func: &'r Function, name: Option<&str>| { + let name = func.core_export_name(name); + let ty = resolve.wasm_signature(AbiVariant::GuestExport, func); + let prev = required.insert( + name.into_owned(), + ( + wasmparser::FuncType::new( + ty.params.iter().map(to_valty), + ty.results.iter().map(to_valty), + ), + Some(func), + ), + ); + assert!(prev.is_none()); + }; + for name in required_exports { + match &resolve.worlds[world].exports[name] { + WorldItem::Function(func) => add_func(func, None), + WorldItem::Interface(id) => { + let name = resolve.name_world_key(name); + for (_, func) in resolve.interfaces[*id].functions.iter() { + add_func(func, Some(&name)); + } + } + WorldItem::Type(_) => {} + } + } + return required; + + fn to_valty(ty: &WasmType) -> ValType { + match ty { + WasmType::I32 => ValType::I32, + WasmType::I64 => ValType::I64, + WasmType::F32 => ValType::F32, + WasmType::F64 => ValType::F64, + } + } + } + + /// Fills out the `import_map` field of `self` by determining the live + /// functions from all imports. This additionally classifies imported + /// functions into direct or indirect lowerings for managing shims. + fn process_imports(&mut self) -> Result<()> { + let resolve = &self.encoder.metadata.resolve; + let world = self.encoder.metadata.world; + let mut all_required_imports = IndexMap::new(); + for map in self.adapters.values().map(|a| &a.info.required_imports) { + for (k, v) in map { + all_required_imports + .entry(k.as_str()) + .or_insert_with(IndexSet::new) + .extend(v.funcs.iter().map(|v| v.as_str())); + } + } + for (k, v) in self.info.required_imports.iter() { + all_required_imports + .entry(*k) + .or_insert_with(IndexSet::new) + .extend(v.funcs.iter().map(|v| v.as_str())); + } + for (name, item) in resolve.worlds[world].imports.iter() { + add_item( + &mut self.import_map, + resolve, + name, + item, + &all_required_imports, + )?; + } + return Ok(()); + + fn add_item( + import_map: &mut IndexMap, ImportedInterface>, + resolve: &Resolve, + name: &WorldKey, + item: &WorldItem, + required: &IndexMap<&str, IndexSet<&str>>, + ) -> Result<()> { + let name = resolve.name_world_key(name); + log::trace!("register import `{name}`"); + let empty = IndexSet::new(); + let import_map_key = match item { + WorldItem::Function(_) | WorldItem::Type(_) => None, + WorldItem::Interface(_) => Some(name), + }; + let interface_id = match item { + WorldItem::Function(_) | WorldItem::Type(_) => None, + WorldItem::Interface(id) => Some(*id), + }; + let required = required + .get(import_map_key.as_deref().unwrap_or(BARE_FUNC_MODULE_NAME)) + .unwrap_or(&empty); + let interface = import_map + .entry(import_map_key) + .or_insert_with(|| ImportedInterface { + interface: interface_id, + lowerings: Default::default(), + }); + assert_eq!(interface.interface, interface_id); + match item { + WorldItem::Function(func) => { + interface.add_func(required, resolve, func); + } + WorldItem::Type(ty) => { + interface.add_type(required, resolve, *ty); + } + WorldItem::Interface(id) => { + for (_name, ty) in resolve.interfaces[*id].types.iter() { + interface.add_type(required, resolve, *ty); + } + for (_name, func) in resolve.interfaces[*id].functions.iter() { + interface.add_func(required, resolve, func); + } + } + } + Ok(()) + } + } + + /// Determines the set of live imported types which are required to satisfy + /// the imports and exports of the lifted core module. + fn process_live_type_imports(&mut self) { + let mut live = LiveTypes::default(); + let resolve = &self.encoder.metadata.resolve; + let world = self.encoder.metadata.world; + + // First use the previously calculated metadata about live imports to + // determine the set of live types in those imports. + self.add_live_imports(world, &self.info.required_imports, &mut live); + for (adapter_name, adapter) in self.adapters.iter() { + log::trace!("processing adapter `{adapter_name}`"); + self.add_live_imports(world, &adapter.info.required_imports, &mut live); + } + + // Next any imported types used by an export must also be considered + // live. This is a little tricky though because interfaces can be both + // imported and exported, so it's not as simple as registering the + // entire export's set of types and their transitive references + // (otherwise if you only export an interface it would consider those + // types imports live too). + // + // Here if the export is an interface the set of live types for that + // interface is calculated separately. The `exports_used` field + // previously calculated is then consulted to add any types owned by + // interfaces not in the `exports_used` set to the live imported types + // set. This means that only types not defined by referenced exports + // will get added here. + for (name, item) in resolve.worlds[world].exports.iter() { + log::trace!("add live world export `{}`", resolve.name_world_key(name)); + let id = match item { + WorldItem::Interface(id) => id, + WorldItem::Function(_) | WorldItem::Type(_) => { + live.add_world_item(resolve, item); + continue; + } + }; + + let exports_used = &self.exports_used[id]; + let mut live_from_export = LiveTypes::default(); + live_from_export.add_world_item(resolve, item); + for ty in live_from_export.iter() { + let owner = match resolve.types[ty].owner { + TypeOwner::Interface(id) => id, + _ => continue, + }; + if owner != *id && !exports_used.contains(&owner) { + live.add_type_id(resolve, ty); + } + } + } + + for live in live.iter() { + let owner = match resolve.types[live].owner { + TypeOwner::Interface(id) => id, + _ => continue, + }; + self.live_type_imports + .entry(owner) + .or_insert(Default::default()) + .insert(live); + } + } + + fn add_live_imports( + &self, + world: WorldId, + required: &IndexMap, + live: &mut LiveTypes, + ) where + S: Borrow + Hash + Eq, + { + let resolve = &self.encoder.metadata.resolve; + for (name, item) in resolve.worlds[world].imports.iter() { + let name = resolve.name_world_key(name); + match item { + WorldItem::Function(func) => { + let required = match required.get(BARE_FUNC_MODULE_NAME) { + Some(set) => set, + None => continue, + }; + if !required.funcs.contains(name.as_str()) { + continue; + } + log::trace!("add live function import `{name}`"); + live.add_func(resolve, func); + } + WorldItem::Interface(id) => { + let required = match required.get(name.as_str()) { + Some(set) => set, + None => continue, + }; + log::trace!("add live interface import `{name}`"); + for (name, func) in resolve.interfaces[*id].functions.iter() { + if required.funcs.contains(name.as_str()) { + log::trace!("add live func `{name}`"); + live.add_func(resolve, func); + } + } + for (name, ty) in resolve.interfaces[*id].types.iter() { + if required.resources.contains(name.as_str()) { + live.add_type_id(resolve, *ty); + } + } + } + WorldItem::Type(id) => live.add_type_id(resolve, *id), + } + } + } + + fn process_exports_used(&mut self) { + let resolve = &self.encoder.metadata.resolve; + let world = self.encoder.metadata.world; + + let exports = &resolve.worlds[world].exports; + for (_name, item) in exports.iter() { + let id = match item { + WorldItem::Function(_) => continue, + WorldItem::Interface(id) => *id, + WorldItem::Type(_) => unreachable!(), + }; + let mut set = HashSet::new(); + + for other in resolve.interface_direct_deps(id) { + // If this dependency is not exported, then it'll show up + // through an import, so we're not interested in it. + if !exports.contains_key(&WorldKey::Interface(other)) { + continue; + } + + // Otherwise this is a new exported dependency of ours, and + // additionally this interface inherits all the transitive + // dependencies too. + if set.insert(other) { + set.extend(self.exports_used[&other].iter().copied()); + } + } + let prev = self.exports_used.insert(id, set); + assert!(prev.is_none()); + } + } +} + +impl ImportedInterface { + fn add_func(&mut self, required: &IndexSet<&str>, resolve: &Resolve, func: &Function) { + if !required.contains(func.name.as_str()) { + return; + } + log::trace!("add func {}", func.name); + let options = RequiredOptions::for_import(resolve, func); + let lowering = if options.is_empty() { + Lowering::Direct + } else { + let sig = resolve.wasm_signature(AbiVariant::GuestImport, func); + Lowering::Indirect { sig, options } + }; + + let prev = self.lowerings.insert(func.name.clone(), lowering); + assert!(prev.is_none()); + } + + fn add_type(&mut self, required: &IndexSet<&str>, resolve: &Resolve, id: TypeId) { + let ty = &resolve.types[id]; + match &ty.kind { + TypeDefKind::Resource => {} + _ => return, + } + let name = ty.name.as_deref().expect("resources must be named"); + + let mut maybe_add = |name: String, lowering: Lowering| { + if !required.contains(name.as_str()) { + return; + } + let prev = self.lowerings.insert(name, lowering); + assert!(prev.is_none()); + }; + maybe_add(format!("{RESOURCE_DROP}{name}"), Lowering::ResourceDrop(id)); + } +} diff --git a/crates/wit-component/src/gc.rs b/crates/wit-component/src/gc.rs new file mode 100644 index 0000000000..c4e1dff613 --- /dev/null +++ b/crates/wit-component/src/gc.rs @@ -0,0 +1,1302 @@ +use self::bitvec::BitVec; +use anyhow::{bail, Result}; +use indexmap::{IndexMap, IndexSet}; +use std::{ + borrow::Cow, + collections::{HashMap, HashSet}, + mem, + ops::Deref, +}; +use wasm_encoder::{Encode, EntityType, Instruction, RawCustomSection}; +use wasmparser::*; + +const PAGE_SIZE: i32 = 64 * 1024; + +/// This function will reduce the input core `wasm` module to only the set of +/// exports `required`. +/// +/// This internally performs a "gc" pass after removing exports to ensure that +/// the resulting module imports the minimal set of functions necessary. +pub fn run( + wasm: &[u8], + required: &IndexMap, + main_module_realloc: Option<&str>, +) -> Result> { + assert!(!required.is_empty()); + + let mut module = Module::default(); + module.parse(wasm)?; + + // Make sure that all required names are present in the module, and then + // remove all names that are not required. + for (name, _ty) in required { + if !module.exports.contains_key(name.as_str()) { + bail!("adapter module does not have export `{name}`") + } + } + let mut not_required = IndexSet::new(); + for name in module.exports.keys().copied() { + // If we need `name` then we also need cabi_post_`name`: + let name = if let Some(suffix) = name.strip_prefix("cabi_post_") { + suffix + } else { + name + }; + + if !required.contains_key(name) && !always_keep(name) { + not_required.insert(name); + } + } + for name in not_required { + module.exports.remove(name); + } + assert!(!module.exports.is_empty()); + module.liveness()?; + module.encode(main_module_realloc) +} + +fn always_keep(name: &str) -> bool { + match name { + // Explicitly keep `cabi_realloc` if it's there in case an interface + // needs it for a lowering. + "cabi_realloc" | "cabi_import_realloc" | "cabi_export_realloc" => true, + _ => false, + } +} + +/// This function generates a Wasm function body which implements `cabi_realloc` in terms of `memory.grow`. It +/// only accepts new, page-sized allocations. +fn realloc_via_memory_grow() -> wasm_encoder::Function { + use wasm_encoder::Instruction::*; + + let mut func = wasm_encoder::Function::new([(1, wasm_encoder::ValType::I32)]); + + // Assert `old_ptr` is null. + func.instruction(&I32Const(0)); + func.instruction(&LocalGet(0)); + func.instruction(&I32Ne); + func.instruction(&If(wasm_encoder::BlockType::Empty)); + func.instruction(&Unreachable); + func.instruction(&End); + + // Assert `old_len` is zero. + func.instruction(&I32Const(0)); + func.instruction(&LocalGet(1)); + func.instruction(&I32Ne); + func.instruction(&If(wasm_encoder::BlockType::Empty)); + func.instruction(&Unreachable); + func.instruction(&End); + + // Assert `new_len` is equal to the page size (which is the only value we currently support) + // Note: we could easily support arbitrary multiples of PAGE_SIZE here if the need arises. + func.instruction(&I32Const(PAGE_SIZE)); + func.instruction(&LocalGet(3)); + func.instruction(&I32Ne); + func.instruction(&If(wasm_encoder::BlockType::Empty)); + func.instruction(&Unreachable); + func.instruction(&End); + + // Grow the memory by 1 page. + func.instruction(&I32Const(1)); + func.instruction(&MemoryGrow(0)); + func.instruction(&LocalTee(4)); + + // Test if the return value of the growth was -1 and, if so, trap due to a failed allocation. + func.instruction(&I32Const(-1)); + func.instruction(&I32Eq); + func.instruction(&If(wasm_encoder::BlockType::Empty)); + func.instruction(&Unreachable); + func.instruction(&End); + + func.instruction(&LocalGet(4)); + func.instruction(&I32Const(16)); + func.instruction(&I32Shl); + func.instruction(&End); + + func +} + +#[repr(i32)] +#[non_exhaustive] +enum StackAllocationState { + Unallocated, + Allocating, + Allocated, +} + +fn allocate_stack_via_realloc( + realloc_index: u32, + sp: u32, + allocation_state: Option, +) -> wasm_encoder::Function { + use wasm_encoder::Instruction::*; + + let mut func = wasm_encoder::Function::new([]); + + if let Some(allocation_state) = allocation_state { + // This means we're lazily allocating the stack, keeping track of state via `$allocation_state` + func.instruction(&GlobalGet(allocation_state)); + func.instruction(&I32Const(StackAllocationState::Unallocated as _)); + func.instruction(&I32Eq); + func.instruction(&If(wasm_encoder::BlockType::Empty)); + func.instruction(&I32Const(StackAllocationState::Allocating as _)); + func.instruction(&GlobalSet(allocation_state)); + // We could also set `sp` to zero here to ensure the yet-to-be-allocated stack is empty. However, we + // assume it defaults to zero anyway, in which case setting it would be redundant. + } + + func.instruction(&I32Const(0)); + func.instruction(&I32Const(0)); + func.instruction(&I32Const(8)); + func.instruction(&I32Const(PAGE_SIZE)); + func.instruction(&Call(realloc_index)); + func.instruction(&I32Const(PAGE_SIZE)); + func.instruction(&I32Add); + func.instruction(&GlobalSet(sp)); + + if let Some(allocation_state) = allocation_state { + func.instruction(&I32Const(StackAllocationState::Allocated as _)); + func.instruction(&GlobalSet(allocation_state)); + func.instruction(&End); + } + + func.instruction(&End); + + func +} + +// Represents a function called while processing a module work list. +type WorklistFunc<'a> = fn(&mut Module<'a>, u32) -> Result<()>; + +// Representation of a wasm module which is used to GC a module to its minimal +// set of required items necessary to implement the `exports` +// +// Note that this is not a complete representation of a wasm module since it +// doesn't represent everything such as data and element segments. This is only +// used for adapter modules which otherwise have these restrictions and makes +// this gc pass a bit easier to write. +#[derive(Default)] +struct Module<'a> { + // Definitions found when parsing a module + types: Vec, + tables: Vec>, + globals: Vec>, + memories: Vec>, + funcs: Vec>, + exports: IndexMap<&'a str, Export<'a>>, + func_names: HashMap, + global_names: HashMap, + producers: Option, + + // Known-live sets of indices after the `liveness` pass has run. + live_types: BitVec, + live_tables: BitVec, + live_globals: BitVec, + live_memories: BitVec, + live_funcs: BitVec, + + // Helper data structure used during the `liveness` path to avoid recursion. + // When calculating the liveness of an item this `worklist` is pushed to and + // then processed until it's empty. An item pushed onto this list represents + // a new index that has been discovered to be live and the function is what + // walks the item's definition to find other items that it references. + worklist: Vec<(u32, WorklistFunc<'a>)>, +} + +struct Table<'a> { + def: Definition<'a, ()>, + ty: TableType, +} + +struct Memory<'a> { + def: Definition<'a, ()>, + ty: MemoryType, +} + +struct Global<'a> { + def: Definition<'a, ConstExpr<'a>>, + ty: GlobalType, +} + +#[derive(Clone)] +struct Func<'a> { + def: Definition<'a, FunctionBody<'a>>, + ty: u32, +} + +#[derive(Clone)] +enum Definition<'a, T> { + Import(&'a str, &'a str), + Local(T), +} + +impl<'a> Module<'a> { + fn parse(&mut self, wasm: &'a [u8]) -> Result<()> { + let mut next_code_index = 0; + let mut validator = Validator::new(); + for payload in Parser::new(0).parse_all(wasm) { + let payload = payload?; + validator.payload(&payload)?; + match payload { + Payload::Version { encoding, .. } => { + if encoding != Encoding::Module { + bail!("adapter must be a core wasm module, not a component"); + } + } + Payload::End(_) => {} + Payload::TypeSection(s) => { + for ty in s.into_iter_err_on_gc_types() { + self.types.push(ty?); + } + } + Payload::ImportSection(s) => { + for i in s { + let i = i?; + match i.ty { + TypeRef::Func(ty) => self.funcs.push(Func { + def: Definition::Import(i.module, i.name), + ty, + }), + TypeRef::Table(ty) => self.tables.push(Table { + def: Definition::Import(i.module, i.name), + ty, + }), + TypeRef::Global(ty) => self.globals.push(Global { + def: Definition::Import(i.module, i.name), + ty, + }), + TypeRef::Memory(ty) => self.memories.push(Memory { + def: Definition::Import(i.module, i.name), + ty, + }), + TypeRef::Tag(_) => bail!("unsupported `tag` type"), + } + } + } + Payload::TableSection(s) => { + for table in s { + let table = table?; + self.tables.push(Table { + def: Definition::Local(()), + ty: table.ty, + }); + } + } + Payload::MemorySection(s) => { + for ty in s { + let ty = ty?; + self.memories.push(Memory { + def: Definition::Local(()), + ty, + }); + } + } + Payload::GlobalSection(s) => { + for g in s { + let g = g?; + self.globals.push(Global { + def: Definition::Local(g.init_expr), + ty: g.ty, + }); + } + } + + Payload::ExportSection(s) => { + for e in s { + let e = e?; + self.exports.insert(e.name, e); + } + } + + Payload::FunctionSection(s) => { + next_code_index = self.funcs.len(); + for ty in s { + let ty = ty?; + self.funcs.push(Func { + // Specify a dummy definition to get filled in later + // when parsing the code section. + def: Definition::Local(FunctionBody::new(0, &[])), + ty, + }); + } + } + + Payload::CodeSectionStart { .. } => {} + Payload::CodeSectionEntry(body) => { + self.funcs[next_code_index].def = Definition::Local(body); + next_code_index += 1; + } + + // Ignore all custom sections except for the `name` and + // `producers` sections which we parse, but ignore errors within. + Payload::CustomSection(s) => { + if s.name() == "name" { + drop(self.parse_name_section(&s)); + } + if s.name() == "producers" { + drop(self.parse_producers_section(&s)); + } + } + + // sections that shouldn't appear in the specially-crafted core wasm + // adapter self we're processing + Payload::DataCountSection { .. } + | Payload::ElementSection(_) + | Payload::DataSection(_) + | Payload::StartSection { .. } + | Payload::TagSection(_) + | Payload::UnknownSection { .. } => { + bail!("unsupported section found in adapter module") + } + + // component-model related things that shouldn't show up + Payload::ModuleSection { .. } + | Payload::ComponentSection { .. } + | Payload::InstanceSection(_) + | Payload::ComponentInstanceSection(_) + | Payload::ComponentAliasSection(_) + | Payload::ComponentCanonicalSection(_) + | Payload::ComponentStartSection { .. } + | Payload::ComponentImportSection(_) + | Payload::CoreTypeSection(_) + | Payload::ComponentExportSection(_) + | Payload::ComponentTypeSection(_) => { + bail!("component section found in adapter module") + } + } + } + + Ok(()) + } + + fn parse_name_section(&mut self, section: &CustomSectionReader<'a>) -> Result<()> { + let section = NameSectionReader::new(section.data(), section.data_offset()); + for s in section { + match s? { + Name::Function(map) => { + for naming in map { + let naming = naming?; + self.func_names.insert(naming.index, naming.name); + } + } + Name::Global(map) => { + for naming in map { + let naming = naming?; + self.global_names.insert(naming.index, naming.name); + } + } + _ => {} + } + } + Ok(()) + } + + fn parse_producers_section(&mut self, section: &CustomSectionReader<'a>) -> Result<()> { + let producers = + wasm_metadata::Producers::from_bytes(section.data(), section.data_offset())?; + self.producers = Some(producers); + Ok(()) + } + + /// Iteratively calculates the set of live items within this module + /// considering all exports as the root of live functions. + fn liveness(&mut self) -> Result<()> { + let exports = mem::take(&mut self.exports); + for (_, e) in exports.iter() { + match e.kind { + ExternalKind::Func => self.func(e.index), + ExternalKind::Global => self.global(e.index), + ExternalKind::Table => self.table(e.index), + ExternalKind::Memory => self.memory(e.index), + ExternalKind::Tag => bail!("unsupported exported tag"), + } + } + self.exports = exports; + + while let Some((idx, func)) = self.worklist.pop() { + func(self, idx)?; + } + Ok(()) + } + + fn func(&mut self, func: u32) { + if !self.live_funcs.insert(func) { + return; + } + self.worklist.push((func, |me, func| { + let func = me.funcs[func as usize].clone(); + me.ty(func.ty); + let mut body = match &func.def { + Definition::Import(..) => return Ok(()), + Definition::Local(e) => e.get_binary_reader(), + }; + let local_count = body.read_var_u32()?; + for _ in 0..local_count { + body.read_var_u32()?; + body.read::()?; + } + me.operators(body) + })); + } + + fn global(&mut self, global: u32) { + if !self.live_globals.insert(global) { + return; + } + self.worklist.push((global, |me, global| { + let init = match &me.globals[global as usize].def { + Definition::Import(..) => return Ok(()), + Definition::Local(e) => e, + }; + me.operators(init.get_binary_reader()) + })); + } + + fn table(&mut self, table: u32) { + if !self.live_tables.insert(table) { + return; + } + self.worklist.push((table, |me, table| { + let ty = me.tables[table as usize].ty.element_type; + me.valty(ty.into()); + Ok(()) + })); + } + + fn memory(&mut self, memory: u32) { + self.live_memories.insert(memory); + } + + fn blockty(&mut self, ty: BlockType) { + if let BlockType::FuncType(ty) = ty { + self.ty(ty); + } + } + + fn valty(&mut self, ty: ValType) { + match ty { + ValType::Ref(r) => self.heapty(r.heap_type()), + ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {} + } + } + + fn heapty(&mut self, ty: HeapType) { + match ty { + HeapType::Func + | HeapType::Extern + | HeapType::Any + | HeapType::None + | HeapType::NoExtern + | HeapType::NoFunc + | HeapType::Eq + | HeapType::Struct + | HeapType::Array + | HeapType::I31 => {} + HeapType::Indexed(i) => self.ty(i), + } + } + + fn ty(&mut self, ty: u32) { + if !self.live_types.insert(ty) { + return; + } + self.worklist.push((ty, |me, ty| { + let ty = me.types[ty as usize].clone(); + for param in ty.params().iter().chain(ty.results()) { + me.valty(*param); + } + Ok(()) + })); + } + + fn operators(&mut self, mut reader: BinaryReader<'a>) -> Result<()> { + while !reader.eof() { + reader.visit_operator(self)?; + } + Ok(()) + } + + fn live_types(&self) -> impl Iterator + '_ { + live_iter(&self.live_types, self.types.iter()) + } + + fn live_funcs(&self) -> impl Iterator)> + '_ { + live_iter(&self.live_funcs, self.funcs.iter()) + } + + fn live_memories(&self) -> impl Iterator)> + '_ { + live_iter(&self.live_memories, self.memories.iter()) + } + + fn live_globals(&self) -> impl Iterator)> + '_ { + live_iter(&self.live_globals, self.globals.iter()) + } + + fn live_tables(&self) -> impl Iterator)> + '_ { + live_iter(&self.live_tables, self.tables.iter()) + } + + /// Encodes this `Module` to a new wasm module which is gc'd and only + /// contains the items that are live as calculated by the `liveness` pass. + fn encode(&mut self, main_module_realloc: Option<&str>) -> Result> { + // Data structure used to track the mapping of old index to new index + // for all live items. + let mut map = Encoder::default(); + + // Sections that will be assembled into the final module at the end of + // this function. + let mut types = wasm_encoder::TypeSection::new(); + let mut imports = wasm_encoder::ImportSection::new(); + let mut funcs = wasm_encoder::FunctionSection::new(); + let mut tables = wasm_encoder::TableSection::new(); + let mut memories = wasm_encoder::MemorySection::new(); + let mut globals = wasm_encoder::GlobalSection::new(); + let mut code = wasm_encoder::CodeSection::new(); + + let mut empty_type = None; + for (i, ty) in self.live_types() { + map.types.push(i); + + types.function( + ty.params().iter().map(|t| map.valty(*t)), + ty.results().iter().map(|t| map.valty(*t)), + ); + + // Keep track of the "empty type" to see if we can reuse an + // existing one or one needs to be injected if a `start` + // function is calculated at the end. + if ty.params().is_empty() && ty.results().is_empty() { + empty_type = Some(map.types.remap(i)); + } + } + + let mut num_memories = 0; + for (i, mem) in self.live_memories() { + map.memories.push(i); + let ty = wasm_encoder::MemoryType { + minimum: mem.ty.initial, + maximum: mem.ty.maximum, + shared: mem.ty.shared, + memory64: mem.ty.memory64, + }; + match &mem.def { + Definition::Import(m, n) => { + imports.import(m, n, ty); + } + Definition::Local(()) => { + memories.memory(ty); + } + } + num_memories += 1; + } + + for (i, table) in self.live_tables() { + map.tables.push(i); + let ty = wasm_encoder::TableType { + minimum: table.ty.initial, + maximum: table.ty.maximum, + element_type: map.refty(table.ty.element_type), + }; + match &table.def { + Definition::Import(m, n) => { + imports.import(m, n, ty); + } + Definition::Local(()) => { + tables.table(ty); + } + } + } + + for (i, global) in self.live_globals() { + map.globals.push(i); + let ty = wasm_encoder::GlobalType { + mutable: global.ty.mutable, + val_type: map.valty(global.ty.content_type), + }; + match &global.def { + Definition::Import(m, n) => { + imports.import(m, n, ty); + } + Definition::Local(init) => { + let mut bytes = map.operators(init.get_binary_reader())?; + assert_eq!(bytes.pop(), Some(0xb)); + globals.global(ty, &wasm_encoder::ConstExpr::raw(bytes)); + } + } + } + + let mut realloc_index = None; + let mut num_func_imports = 0; + + // For functions first assign a new index to all functions and then + // afterwards actually map the body of all functions so the `map` of all + // index mappings is fully populated before instructions are mapped. + + let is_realloc = + |m, n| m == "__main_module__" && matches!(n, "canonical_abi_realloc" | "cabi_realloc"); + + let (imported, local) = + self.live_funcs() + .partition::, _>(|(_, func)| match &func.def { + Definition::Import(m, n) => { + !is_realloc(*m, *n) || main_module_realloc.is_some() + } + Definition::Local(_) => false, + }); + + for (i, func) in imported { + map.funcs.push(i); + let ty = map.types.remap(func.ty); + match &func.def { + Definition::Import(m, n) => { + let name = if is_realloc(*m, *n) { + // The adapter is importing `cabi_realloc` from the main module, and the main module + // exports that function, but possibly using a different name + // (e.g. `canonical_abi_realloc`). Update the name to match if necessary. + realloc_index = Some(num_func_imports); + main_module_realloc.unwrap_or(n) + } else { + n + }; + imports.import(m, name, EntityType::Function(ty)); + num_func_imports += 1; + } + Definition::Local(_) => unreachable!(), + } + } + + let add_realloc_type = |types: &mut wasm_encoder::TypeSection| { + let type_index = types.len(); + types.function( + [ + wasm_encoder::ValType::I32, + wasm_encoder::ValType::I32, + wasm_encoder::ValType::I32, + wasm_encoder::ValType::I32, + ], + [wasm_encoder::ValType::I32], + ); + type_index + }; + + let add_empty_type = |types: &mut wasm_encoder::TypeSection| { + let type_index = types.len(); + types.function([], []); + type_index + }; + + let sp = self.find_mut_i32_global("__stack_pointer")?; + let allocation_state = self.find_mut_i32_global("allocation_state")?; + + let mut func_names = Vec::new(); + + if let (Some(realloc), Some(_), None) = (main_module_realloc, sp, realloc_index) { + // The main module exports a realloc function, and although the adapter doesn't import it, we're going + // to add a function which calls it to allocate some stack space, so let's add an import now. + + // Tell the function remapper we're reserving a slot for our extra import: + map.funcs.next += 1; + + realloc_index = Some(num_func_imports); + imports.import( + "__main_module__", + realloc, + EntityType::Function(add_realloc_type(&mut types)), + ); + func_names.push((num_func_imports, realloc)); + num_func_imports += 1; + } + + for (i, func) in local { + map.funcs.push(i); + let ty = map.types.remap(func.ty); + match &func.def { + Definition::Import(_, _) => { + // The adapter is importing `cabi_realloc` from the main module, but the main module isn't + // exporting it. In this case, we need to define a local function it can call instead. + realloc_index = Some(num_func_imports + funcs.len()); + funcs.function(ty); + code.function(&realloc_via_memory_grow()); + } + Definition::Local(_) => { + funcs.function(ty); + } + } + } + + let lazy_stack_init_index = + if sp.is_some() && allocation_state.is_some() && main_module_realloc.is_some() { + // We have a stack pointer, a `cabi_realloc` function from the main module, and a global variable for + // keeping track of (and short-circuiting) reentrance. That means we can (and should) do lazy stack + // allocation. + let index = num_func_imports + funcs.len(); + + // Tell the function remapper we're reserving a slot for our extra function: + map.funcs.next += 1; + + funcs.function(add_empty_type(&mut types)); + + Some(index) + } else { + None + }; + + let exported_funcs = self + .exports + .values() + .filter_map(|export| match export.kind { + ExternalKind::Func => Some(export.index), + _ => None, + }) + .collect::>(); + + for (i, func) in self.live_funcs() { + let mut body = match &func.def { + Definition::Import(..) => continue, + Definition::Local(body) => body.get_binary_reader(), + }; + let mut locals = Vec::new(); + for _ in 0..body.read_var_u32()? { + let cnt = body.read_var_u32()?; + let ty = body.read()?; + locals.push((cnt, map.valty(ty))); + } + // Prepend an `allocate_stack` call to all exports if we're lazily allocating the stack. + if let (Some(lazy_stack_init_index), true) = + (lazy_stack_init_index, exported_funcs.contains(&i)) + { + Instruction::Call(lazy_stack_init_index).encode(&mut map.buf); + } + let bytes = map.operators(body)?; + let mut func = wasm_encoder::Function::new(locals); + func.raw(bytes); + code.function(&func); + } + + if lazy_stack_init_index.is_some() { + code.function(&allocate_stack_via_realloc( + realloc_index.unwrap(), + sp.unwrap(), + allocation_state, + )); + } + + if sp.is_some() && (realloc_index.is_none() || allocation_state.is_none()) { + // Either the main module does _not_ export a realloc function, or it is not safe to use for stack + // allocation because we have no way to short-circuit reentrance, so we'll use `memory.grow` instead. + realloc_index = Some(num_func_imports + funcs.len()); + funcs.function(add_realloc_type(&mut types)); + code.function(&realloc_via_memory_grow()); + } + + // Inject a start function to initialize the stack pointer which will be local to this module. This only + // happens if a memory is preserved, a stack pointer global is found, and we're not doing lazy stack + // allocation. + let mut start = None; + if let (Some(sp), None) = (sp, lazy_stack_init_index) { + if num_memories > 0 { + // If there are any memories or any mutable globals there must be + // precisely one of each as otherwise we don't know how to filter + // down to the right one. + if num_memories != 1 { + bail!("adapter modules don't support multi-memory"); + } + + let sp = map.globals.remap(sp); + + let function_index = num_func_imports + funcs.len(); + + // Generate a function type for this start function, adding a new + // function type to the module if necessary. + let empty_type = empty_type.unwrap_or_else(|| { + types.function([], []); + types.len() - 1 + }); + funcs.function(empty_type); + func_names.push((function_index, "allocate_stack")); + code.function(&allocate_stack_via_realloc( + realloc_index.unwrap(), + sp, + allocation_state, + )); + + start = Some(wasm_encoder::StartSection { function_index }); + } + } + + // Sanity-check the shape of the module since some parts won't work if + // this fails. Note that during parsing we've already validated there + // are no data segments or element segments. + + // Shouldn't have any tables if there are no element segments since + // otherwise there's no meaning to a defined or imported table. + if self.live_tables().count() != 0 { + bail!("tables should not be present in the final adapter module"); + } + + // multi-memory should not be enabled and if any memory it should be + // imported. + if self.live_memories().count() > 1 { + bail!("the adapter module should not use multi-memory"); + } + if !memories.is_empty() { + bail!("locally-defined memories are not allowed define a local memory"); + } + + let mut ret = wasm_encoder::Module::default(); + if !types.is_empty() { + ret.section(&types); + } + if !imports.is_empty() { + ret.section(&imports); + } + if !funcs.is_empty() { + ret.section(&funcs); + } + if !tables.is_empty() { + ret.section(&tables); + } + if !memories.is_empty() { + ret.section(&memories); + } + if !globals.is_empty() { + ret.section(&globals); + } + + if !self.exports.is_empty() { + let mut exports = wasm_encoder::ExportSection::new(); + for (_, export) in self.exports.iter() { + let (kind, index) = match export.kind { + ExternalKind::Func => ( + wasm_encoder::ExportKind::Func, + map.funcs.remap(export.index), + ), + ExternalKind::Table => ( + wasm_encoder::ExportKind::Table, + map.tables.remap(export.index), + ), + ExternalKind::Memory => ( + wasm_encoder::ExportKind::Memory, + map.memories.remap(export.index), + ), + ExternalKind::Global => ( + wasm_encoder::ExportKind::Global, + map.globals.remap(export.index), + ), + kind => bail!("unsupported export kind {kind:?}"), + }; + exports.export(export.name, kind, index); + } + ret.section(&exports); + } + + if let Some(start) = &start { + ret.section(start); + } + + if !code.is_empty() { + ret.section(&code); + } + + // Append a custom `name` section using the names of the functions that + // were found prior to the GC pass in the original module. + let mut global_names = Vec::new(); + for (i, _func) in self.live_funcs() { + let name = match self.func_names.get(&i) { + Some(name) => name, + None => continue, + }; + func_names.push((map.funcs.remap(i), *name)); + } + for (i, _global) in self.live_globals() { + let name = match self.global_names.get(&i) { + Some(name) => name, + None => continue, + }; + global_names.push((map.globals.remap(i), *name)); + } + let mut section = Vec::new(); + let mut encode_subsection = |code: u8, names: &[(u32, &str)]| { + if names.is_empty() { + return; + } + let mut subsection = Vec::new(); + names.len().encode(&mut subsection); + for (i, name) in names { + i.encode(&mut subsection); + name.encode(&mut subsection); + } + section.push(code); + subsection.encode(&mut section); + }; + if let (Some(realloc_index), true) = ( + realloc_index, + main_module_realloc.is_none() || allocation_state.is_none(), + ) { + func_names.push((realloc_index, "realloc_via_memory_grow")); + } + if let Some(lazy_stack_init_index) = lazy_stack_init_index { + func_names.push((lazy_stack_init_index, "allocate_stack")); + } + encode_subsection(0x01, &func_names); + encode_subsection(0x07, &global_names); + if !section.is_empty() { + ret.section(&wasm_encoder::CustomSection { + name: "name".into(), + data: Cow::Borrowed(§ion), + }); + } + if let Some(producers) = &self.producers { + ret.section(&RawCustomSection(&producers.raw_custom_section())); + } + + Ok(ret.finish()) + } + + fn find_mut_i32_global(&self, name: &str) -> Result> { + let matches = &self + .live_globals() + .filter_map(|(i, g)| { + if g.ty.mutable + && g.ty.content_type == ValType::I32 + && *self.global_names.get(&i)? == name + { + Some(i) + } else { + None + } + }) + .collect::>(); + + match matches.deref() { + [] => Ok(None), + [i] => Ok(Some(*i)), + _ => bail!( + "found {} mutable i32 globals with name {name}", + matches.len() + ), + } + } +} + +// This helper macro is used to define a visitor of all instructions with +// special handling for all payloads of instructions to mark any referenced +// items live. +// +// Currently item identification happens through the field name of the payload. +// While not exactly the most robust solution this should work well enough for +// now. +macro_rules! define_visit { + ($(@$p:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + $( + fn $visit(&mut self $(, $($arg: $argty),*)?) { + $( + $( + define_visit!(mark_live self $arg $arg); + )* + )? + } + )* + }; + + (mark_live $self:ident $arg:ident type_index) => {$self.ty($arg);}; + (mark_live $self:ident $arg:ident src_table) => {$self.table($arg);}; + (mark_live $self:ident $arg:ident dst_table) => {$self.table($arg);}; + (mark_live $self:ident $arg:ident table_index) => {$self.table($arg);}; + (mark_live $self:ident $arg:ident table) => {$self.table($arg);}; + (mark_live $self:ident $arg:ident table_index) => {$self.table($arg);}; + (mark_live $self:ident $arg:ident global_index) => {$self.global($arg);}; + (mark_live $self:ident $arg:ident function_index) => {$self.func($arg);}; + (mark_live $self:ident $arg:ident mem) => {$self.memory($arg);}; + (mark_live $self:ident $arg:ident src_mem) => {$self.memory($arg);}; + (mark_live $self:ident $arg:ident dst_mem) => {$self.memory($arg);}; + (mark_live $self:ident $arg:ident memarg) => {$self.memory($arg.memory);}; + (mark_live $self:ident $arg:ident blockty) => {$self.blockty($arg);}; + (mark_live $self:ident $arg:ident ty) => {$self.valty($arg)}; + (mark_live $self:ident $arg:ident hty) => {$self.heapty($arg)}; + (mark_live $self:ident $arg:ident lane) => {}; + (mark_live $self:ident $arg:ident lanes) => {}; + (mark_live $self:ident $arg:ident flags) => {}; + (mark_live $self:ident $arg:ident value) => {}; + (mark_live $self:ident $arg:ident mem_byte) => {}; + (mark_live $self:ident $arg:ident table_byte) => {}; + (mark_live $self:ident $arg:ident local_index) => {}; + (mark_live $self:ident $arg:ident relative_depth) => {}; + (mark_live $self:ident $arg:ident tag_index) => {}; + (mark_live $self:ident $arg:ident targets) => {}; + (mark_live $self:ident $arg:ident data_index) => {}; + (mark_live $self:ident $arg:ident elem_index) => {}; +} + +impl<'a> VisitOperator<'a> for Module<'a> { + type Output = (); + + wasmparser::for_each_operator!(define_visit); +} + +/// Helper function to filter `iter` based on the `live` set, yielding an +/// iterator over the index of the item that's live as well as the item itself. +fn live_iter<'a, T>( + live: &'a BitVec, + iter: impl Iterator + 'a, +) -> impl Iterator + 'a { + iter.enumerate().filter_map(|(i, t)| { + let i = i as u32; + if live.contains(i) { + Some((i, t)) + } else { + None + } + }) +} + +#[derive(Default)] +struct Encoder { + types: Remap, + funcs: Remap, + memories: Remap, + globals: Remap, + tables: Remap, + buf: Vec, +} + +impl Encoder { + fn operators(&mut self, mut reader: BinaryReader<'_>) -> Result> { + while !reader.eof() { + reader.visit_operator(self)?; + } + Ok(mem::take(&mut self.buf)) + } + + fn memarg(&self, ty: MemArg) -> wasm_encoder::MemArg { + wasm_encoder::MemArg { + offset: ty.offset, + align: ty.align.into(), + memory_index: self.memories.remap(ty.memory), + } + } + + fn blockty(&self, ty: BlockType) -> wasm_encoder::BlockType { + match ty { + BlockType::Empty => wasm_encoder::BlockType::Empty, + BlockType::Type(ty) => wasm_encoder::BlockType::Result(self.valty(ty)), + BlockType::FuncType(ty) => wasm_encoder::BlockType::FunctionType(self.types.remap(ty)), + } + } + + fn valty(&self, ty: wasmparser::ValType) -> wasm_encoder::ValType { + match ty { + wasmparser::ValType::I32 => wasm_encoder::ValType::I32, + wasmparser::ValType::I64 => wasm_encoder::ValType::I64, + wasmparser::ValType::F32 => wasm_encoder::ValType::F32, + wasmparser::ValType::F64 => wasm_encoder::ValType::F64, + wasmparser::ValType::V128 => wasm_encoder::ValType::V128, + wasmparser::ValType::Ref(rt) => wasm_encoder::ValType::Ref(self.refty(rt)), + } + } + + fn refty(&self, rt: wasmparser::RefType) -> wasm_encoder::RefType { + wasm_encoder::RefType { + nullable: rt.is_nullable(), + heap_type: self.heapty(rt.heap_type()), + } + } + + fn heapty(&self, ht: wasmparser::HeapType) -> wasm_encoder::HeapType { + match ht { + HeapType::Func => wasm_encoder::HeapType::Func, + HeapType::Extern => wasm_encoder::HeapType::Extern, + HeapType::Any => wasm_encoder::HeapType::Any, + HeapType::None => wasm_encoder::HeapType::None, + HeapType::NoExtern => wasm_encoder::HeapType::NoExtern, + HeapType::NoFunc => wasm_encoder::HeapType::NoFunc, + HeapType::Eq => wasm_encoder::HeapType::Eq, + HeapType::Struct => wasm_encoder::HeapType::Struct, + HeapType::Array => wasm_encoder::HeapType::Array, + HeapType::I31 => wasm_encoder::HeapType::I31, + HeapType::Indexed(idx) => wasm_encoder::HeapType::Indexed(self.types.remap(idx)), + } + } +} + +// This is a helper macro to translate all `wasmparser` instructions to +// `wasm-encoder` instructions without having to list out every single +// instruction itself. +// +// The general goal of this macro is to have O(unique instruction payload) +// number of cases while also simultaneously adapting between the styles of +// wasmparser and wasm-encoder. +macro_rules! define_encode { + ($(@$p:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + $( + #[allow(clippy::drop_copy)] + fn $visit(&mut self $(, $($arg: $argty),*)?) { + #[allow(unused_imports)] + use wasm_encoder::Instruction::*; + $( + $( + let $arg = define_encode!(map self $arg $arg); + )* + )? + let insn = define_encode!(mk $op $($($arg)*)?); + insn.encode(&mut self.buf); + } + )* + }; + + // No-payload instructions are named the same in wasmparser as they are in + // wasm-encoder + (mk $op:ident) => ($op); + + // Instructions which need "special care" to map from wasmparser to + // wasm-encoder + (mk BrTable $arg:ident) => ({ + BrTable($arg.0, $arg.1) + }); + (mk CallIndirect $ty:ident $table:ident $table_byte:ident) => ({ + let _ = $table_byte; + CallIndirect { ty: $ty, table: $table } + }); + (mk ReturnCallIndirect $ty:ident $table:ident) => ( + ReturnCallIndirect { ty: $ty, table: $table } + ); + (mk MemorySize $mem:ident $mem_byte:ident) => ({ + let _ = $mem_byte; + MemorySize($mem) + }); + (mk MemoryGrow $mem:ident $mem_byte:ident) => ({ + let _ = $mem_byte; + MemoryGrow($mem) + }); + (mk I32Const $v:ident) => (I32Const($v)); + (mk I64Const $v:ident) => (I64Const($v)); + (mk F32Const $v:ident) => (F32Const(f32::from_bits($v.bits()))); + (mk F64Const $v:ident) => (F64Const(f64::from_bits($v.bits()))); + (mk V128Const $v:ident) => (V128Const($v.i128())); + + // Catch-all for the translation of one payload argument which is typically + // represented as a tuple-enum in wasm-encoder. + (mk $op:ident $arg:ident) => ($op($arg)); + + // Catch-all of everything else where the wasmparser fields are simply + // translated to wasm-encoder fields. + (mk $op:ident $($arg:ident)*) => ($op { $($arg),* }); + + // Individual cases of mapping one argument type to another, similar to the + // `define_visit` macro above. + (map $self:ident $arg:ident memarg) => {$self.memarg($arg)}; + (map $self:ident $arg:ident blockty) => {$self.blockty($arg)}; + (map $self:ident $arg:ident hty) => {$self.heapty($arg)}; + (map $self:ident $arg:ident tag_index) => {$arg}; + (map $self:ident $arg:ident relative_depth) => {$arg}; + (map $self:ident $arg:ident function_index) => {$self.funcs.remap($arg)}; + (map $self:ident $arg:ident global_index) => {$self.globals.remap($arg)}; + (map $self:ident $arg:ident mem) => {$self.memories.remap($arg)}; + (map $self:ident $arg:ident src_mem) => {$self.memories.remap($arg)}; + (map $self:ident $arg:ident dst_mem) => {$self.memories.remap($arg)}; + (map $self:ident $arg:ident table) => {$self.tables.remap($arg)}; + (map $self:ident $arg:ident table_index) => {$self.tables.remap($arg)}; + (map $self:ident $arg:ident src_table) => {$self.tables.remap($arg)}; + (map $self:ident $arg:ident dst_table) => {$self.tables.remap($arg)}; + (map $self:ident $arg:ident type_index) => {$self.types.remap($arg)}; + (map $self:ident $arg:ident ty) => {$self.valty($arg)}; + (map $self:ident $arg:ident local_index) => {$arg}; + (map $self:ident $arg:ident lane) => {$arg}; + (map $self:ident $arg:ident lanes) => {$arg}; + (map $self:ident $arg:ident elem_index) => {$arg}; + (map $self:ident $arg:ident data_index) => {$arg}; + (map $self:ident $arg:ident table_byte) => {$arg}; + (map $self:ident $arg:ident mem_byte) => {$arg}; + (map $self:ident $arg:ident value) => {$arg}; + (map $self:ident $arg:ident targets) => (( + $arg.targets().map(|i| i.unwrap()).collect::>().into(), + $arg.default(), + )); +} + +impl<'a> VisitOperator<'a> for Encoder { + type Output = (); + + wasmparser::for_each_operator!(define_encode); +} + +// Minimal definition of a bit vector necessary for the liveness calculations +// above. +mod bitvec { + use std::mem; + + type T = u64; + + #[derive(Default)] + pub struct BitVec { + bits: Vec, + } + + impl BitVec { + /// Inserts `idx` into this bit vector, returning whether it was not + /// previously present. + pub fn insert(&mut self, idx: u32) -> bool { + let (idx, bit) = idx_bit(idx); + match self.bits.get_mut(idx) { + Some(bits) => { + if *bits & bit != 0 { + return false; + } + *bits |= bit; + } + None => { + self.bits.resize(idx + 1, 0); + self.bits[idx] = bit; + } + } + true + } + + /// Returns whether this bit vector contains the specified `idx`th bit. + pub fn contains(&self, idx: u32) -> bool { + let (idx, bit) = idx_bit(idx); + match self.bits.get(idx) { + Some(bits) => (*bits & bit) != 0, + None => false, + } + } + } + + fn idx_bit(idx: u32) -> (usize, T) { + let idx = idx as usize; + let size = mem::size_of::() * 8; + let index = idx / size; + let bit = 1 << (idx % size); + (index, bit) + } +} + +/// Small data structure used to track index mappings from an old index space to +/// a new. +#[derive(Default)] +struct Remap { + /// Map, indexed by the old index set, to the new index set. + map: HashMap, + /// The next available index in the new index space. + next: u32, +} + +impl Remap { + /// Appends a new live "old index" into this remapping structure. + /// + /// This will assign a new index for the old index provided. + fn push(&mut self, old: u32) { + self.map.insert(old, self.next); + self.next += 1; + } + + /// Returns the new index corresponding to an old index. + /// + /// Panics if the `old` index was not added via `push` above. + fn remap(&self, old: u32) -> u32 { + *self + .map + .get(&old) + .unwrap_or_else(|| panic!("can't map {old} to a new index")) + } +} diff --git a/crates/wit-component/src/lib.rs b/crates/wit-component/src/lib.rs new file mode 100644 index 0000000000..91b1395ba0 --- /dev/null +++ b/crates/wit-component/src/lib.rs @@ -0,0 +1,291 @@ +//! The WebAssembly component tooling. + +#![deny(missing_docs)] + +use std::str::FromStr; +use std::{borrow::Cow, fmt::Display}; + +use anyhow::{bail, Result}; +use wasm_encoder::{CanonicalOption, Encode, Section}; +use wit_parser::{Resolve, WorldId}; + +mod decoding; +mod encoding; +mod gc; +mod linking; +mod printing; +mod targets; +mod validation; + +pub use decoding::{decode, DecodedWasm}; +pub use encoding::{encode, ComponentEncoder}; +pub use linking::Linker; +pub use printing::*; +pub use targets::*; + +pub mod metadata; + +#[cfg(feature = "dummy-module")] +pub use dummy::dummy_module; +#[cfg(feature = "dummy-module")] +mod dummy; + +/// Supported string encoding formats. +#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum StringEncoding { + /// Strings are encoded with UTF-8. + #[default] + UTF8, + /// Strings are encoded with UTF-16. + UTF16, + /// Strings are encoded with compact UTF-16 (i.e. Latin1+UTF-16). + CompactUTF16, +} + +impl Display for StringEncoding { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StringEncoding::UTF8 => write!(f, "utf8"), + StringEncoding::UTF16 => write!(f, "utf16"), + StringEncoding::CompactUTF16 => write!(f, "compact-utf16"), + } + } +} + +impl FromStr for StringEncoding { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s { + "utf8" => Ok(StringEncoding::UTF8), + "utf16" => Ok(StringEncoding::UTF16), + "compact-utf16" => Ok(StringEncoding::CompactUTF16), + _ => bail!("unknown string encoding `{}`", s), + } + } +} + +impl From for wasm_encoder::CanonicalOption { + fn from(e: StringEncoding) -> wasm_encoder::CanonicalOption { + match e { + StringEncoding::UTF8 => CanonicalOption::UTF8, + StringEncoding::UTF16 => CanonicalOption::UTF16, + StringEncoding::CompactUTF16 => CanonicalOption::CompactUTF16, + } + } +} + +/// A producer section to be added to all modules and components synthesized by +/// this crate +pub(crate) fn base_producers() -> wasm_metadata::Producers { + let mut producer = wasm_metadata::Producers::empty(); + producer.add("processed-by", "wit-component", env!("CARGO_PKG_VERSION")); + producer +} + +/// Parse a WIT file from a path that represents a top level 'wit' directory, +/// normally containing a 'deps' folder. +pub fn parse_wit_from_path( + path: impl AsRef, +) -> Result<(Resolve, wit_parser::PackageId)> { + use anyhow::Context; + + let mut resolver = Resolve::default(); + let id = match path.as_ref() { + // Directories can be directly fed into the resolver + p if p.is_dir() => { + resolver + .push_dir(p) + .with_context(|| { + format!( + "failed to resolve directory while parsing WIT for path [{}]", + p.display() + ) + })? + .0 + } + // Non-directory files (including symlinks) can be either: + // - Wasm modules (binary or WAT) that are WIT packages + // - WIT files + #[cfg(not(feature = "wat"))] + p => { + let file_contents = std::fs::read(p) + .with_context(|| format!("failed to parse WIT from path [{}]", p.display()))?; + match decode(&file_contents)? { + DecodedWasm::Component(..) => { + bail!("specified path is a component, not a wit package") + } + DecodedWasm::WitPackage(resolve, pkg) => return Ok((resolve, pkg)), + } + } + #[cfg(feature = "wat")] + p => { + use wit_parser::UnresolvedPackage; + + let file_contents = std::fs::read(p) + .with_context(|| format!("failed to parse WIT from path [{}]", p.display()))?; + + // Check if the bytes represent a Wasm module (either binary or WAT encoded) + if is_wasm_binary_or_wat(&file_contents) { + let bytes = wat::parse_bytes(&file_contents).map_err(|mut e| { + e.set_path(p); + e + })?; + match decode(&bytes)? { + DecodedWasm::Component(..) => { + bail!("specified path is a component, not a wit package") + } + DecodedWasm::WitPackage(resolve, pkg) => return Ok((resolve, pkg)), + } + } else { + // If the bytes are not a WASM module, they should be WIT that can be parsed + // into a package by the resolver + let text = match std::str::from_utf8(&file_contents) { + Ok(s) => s, + Err(_) => bail!("input file is not valid utf-8"), + }; + let pkg = UnresolvedPackage::parse(p, text)?; + resolver.push(pkg)? + } + } + }; + Ok((resolver, id)) +} + +/// Detect quickly if supplied bytes represent a Wasm module, +/// whether binary encoded or in WAT-encoded. +/// +/// This briefly lexes past whitespace and comments as a `*.wat` file to see if +/// we can find a left-paren. If that fails then it's probably `*.wit` instead. +/// +/// +/// Examples +/// ``` +/// # use wit_component::is_wasm_binary_or_wat; +/// assert!(is_wasm_binary_or_wat(r#" +/// (module +/// (type (;0;) (func)) +/// (func (;0;) (type 0) +/// nop +/// ) +/// ) +/// "#)); +/// ``` +#[cfg(feature = "wat")] +pub fn is_wasm_binary_or_wat(bytes: impl AsRef<[u8]>) -> bool { + use wast::lexer::{Lexer, TokenKind}; + + if bytes.as_ref().starts_with(b"\0asm") { + return true; + } + let text = match std::str::from_utf8(bytes.as_ref()) { + Ok(s) => s, + Err(_) => return true, + }; + + let lexer = Lexer::new(text); + let mut iter = lexer.iter(0); + + while let Some(next) = iter.next() { + match next.map(|t| t.kind) { + Ok(TokenKind::Whitespace) + | Ok(TokenKind::BlockComment) + | Ok(TokenKind::LineComment) => {} + Ok(TokenKind::LParen) => return true, + _ => break, + } + } + + false +} + +/// Embed component metadata in a buffer of bytes that contains a Wasm module +pub fn embed_component_metadata( + bytes: &mut Vec, + wit_resolver: &Resolve, + world: WorldId, + encoding: StringEncoding, +) -> Result<()> { + let encoded = metadata::encode(&wit_resolver, world, encoding, None)?; + + let section = wasm_encoder::CustomSection { + name: "component-type".into(), + data: Cow::Borrowed(&encoded), + }; + bytes.push(section.id()); + section.encode(bytes); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use std::path::Path; + + use anyhow::Result; + use wasmparser::Payload; + use wit_parser::{Resolve, UnresolvedPackage}; + + use super::{embed_component_metadata, StringEncoding}; + + const MODULE_WAT: &str = r#" +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + ) +) +"#; + + const COMPONENT_WIT: &str = r#" +package test:foo; +world test-world {} +"#; + + #[test] + fn component_metadata_embedding_works() -> Result<()> { + let mut bytes = wat::parse_str(MODULE_WAT)?; + + // Get original len & custom section count + let original_len = bytes.len(); + let payloads = wasmparser::Parser::new(0).parse_all(&bytes); + let original_custom_section_count = payloads.fold(0, |acc, payload| { + if let Ok(Payload::CustomSection { .. }) = payload { + acc + 1 + } else { + acc + } + }); + + // Parse pre-canned WIT to build resolver + let mut resolver = Resolve::default(); + let pkg = UnresolvedPackage::parse(&Path::new("in-code.wit"), COMPONENT_WIT)?; + let pkg_id = resolver.push(pkg)?; + let world = resolver.select_world(pkg_id, Some("test-world").into())?; + + // Embed component metadata + embed_component_metadata(&mut bytes, &resolver, world, StringEncoding::UTF8)?; + + // Re-retrieve custom section count, and search for the component-type custom section along the way + let mut found_component_section = false; + let new_custom_section_count = + wasmparser::Parser::new(0) + .parse_all(&bytes) + .fold(0, |acc, payload| { + if let Ok(Payload::CustomSection(reader)) = payload { + if reader.name() == "component-type" { + found_component_section = true; + } + acc + 1 + } else { + acc + } + }); + + assert!(original_len < bytes.len()); + assert_eq!(original_custom_section_count + 1, new_custom_section_count); + assert!(found_component_section); + + Ok(()) + } +} diff --git a/crates/wit-component/src/linking.rs b/crates/wit-component/src/linking.rs new file mode 100644 index 0000000000..3af76c6a86 --- /dev/null +++ b/crates/wit-component/src/linking.rs @@ -0,0 +1,1531 @@ +//! Support for "pseudo-dynamic", shared-everything linking of Wasm modules into a component. +//! +//! This implements [shared-everything +//! linking](https://github.com/WebAssembly/component-model/blob/main/design/mvp/examples/SharedEverythingDynamicLinking.md), +//! taking as input one or more [dynamic +//! library](https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md) modules and producing a +//! component whose type is the union of any `component-type*` custom sections found in the input modules. +//! +//! The entry point into this process is `Linker::encode`, which analyzes and topologically sorts the input +//! modules, then sythesizes two additional modules: +//! +//! - `main` AKA `env`: hosts the component's single memory and function table and exports any functions needed to +//! break dependency cycles discovered in the input modules. Those functions use `call.indirect` to invoke the real +//! functions, references to which are placed in the table by the `init` module. +//! +//! - `init`: populates the function table as described above, initializes global variables per the dynamic linking +//! tool convention, and calls any static constructors and/or link-time fixup functions +//! +//! `Linker` also supports synthesizing `dlopen`/`dlsym` lookup tables which allow symbols to be resolved at +//! runtime. Note that this is not true dynamic linking, since all the code is baked into the component ahead of +//! time -- we simply allow runtime resolution of already-resident definitions. This is sufficient to support +//! dynamic language FFI features such as Python native extensions, provided the required libraries are linked +//! ahead-of-time. + +use { + crate::encoding::{ComponentEncoder, Instance, Item, LibraryInfo, MainOrAdapter}, + anyhow::{anyhow, bail, Context, Result}, + indexmap::{map::Entry, IndexMap, IndexSet}, + metadata::{Export, ExportKey, FunctionType, GlobalType, Metadata, Type, ValueType}, + std::{ + collections::{BTreeMap, HashMap, HashSet}, + fmt::Debug, + hash::Hash, + iter, + }, + wasm_encoder::{ + CodeSection, ConstExpr, DataSection, ElementSection, Elements, EntityType, ExportKind, + ExportSection, Function, FunctionSection, GlobalSection, HeapType, ImportSection, + Instruction as Ins, MemArg, MemorySection, MemoryType, Module, RawCustomSection, RefType, + StartSection, TableSection, TableType, TypeSection, ValType, + }, + wasmparser::WASM_SYM_BINDING_WEAK, +}; + +mod metadata; + +const PAGE_SIZE_BYTES: u32 = 65536; +// This matches the default stack size LLVM produces: +pub const DEFAULT_STACK_SIZE_BYTES: u32 = 16 * PAGE_SIZE_BYTES; +const HEAP_ALIGNMENT_BYTES: u32 = 16; + +enum Address<'a> { + Function(u32), + Global(&'a str), +} + +/// Represents a `dlopen`/`dlsym` lookup table enabling runtime symbol resolution +/// +/// The top level of this table is a sorted list of library names and offsets, each pointing to a sorted list of +/// symbol names and offsets. See +/// https://github.com/dicej/wasi-libc/blob/76c7e1e1cfdad577ecd7f61c67ead7a38d62a7c4/libc-top-half/musl/src/misc/dl.c +/// for how this is used. +struct DlOpenables<'a> { + /// Offset into the main module's table where function references will be stored + table_base: u32, + + /// Offset into the main module's memory where the lookup table will be stored + memory_base: u32, + + /// The lookup table itself + buffer: Vec, + + /// Linear memory addresses where global variable addresses will live + /// + /// The init module will fill in the correct values at insantiation time. + global_addresses: Vec<(&'a str, &'a str, u32)>, + + /// Number of function references to be stored in the main module's table + function_count: u32, + + /// Linear memory address where the root of the lookup table will reside + /// + /// This can be different from `memory_base` depending on how the tree of libraries and symbols is laid out in + /// memory. + libraries_address: u32, +} + +impl<'a> DlOpenables<'a> { + /// Construct a lookup table containing all "dlopen-able" libraries and their symbols using the specified table + /// and memory offsets. + fn new(table_base: u32, memory_base: u32, metadata: &'a [Metadata<'a>]) -> Self { + let mut function_count = 0; + let mut buffer = Vec::new(); + let mut global_addresses = Vec::new(); + let mut libraries = metadata + .iter() + .filter(|metadata| metadata.dl_openable) + .map(|metadata| { + let name_address = memory_base + u32::try_from(buffer.len()).unwrap(); + write_bytes_padded(&mut buffer, metadata.name.as_bytes()); + + let mut symbols = metadata + .exports + .iter() + .map(|export| { + let name_address = memory_base + u32::try_from(buffer.len()).unwrap(); + write_bytes_padded(&mut buffer, export.key.name.as_bytes()); + + let address = match &export.key.ty { + Type::Function(_) => Address::Function( + table_base + get_and_increment(&mut function_count), + ), + Type::Global(_) => Address::Global(export.key.name), + }; + + (export.key.name, name_address, address) + }) + .collect::>(); + + symbols.sort_by_key(|(name, ..)| *name); + + let start = buffer.len(); + for (name, name_address, address) in symbols { + write_u32(&mut buffer, u32::try_from(name.len()).unwrap()); + write_u32(&mut buffer, name_address); + match address { + Address::Function(address) => write_u32(&mut buffer, address), + Address::Global(name) => { + global_addresses.push(( + metadata.name, + name, + memory_base + u32::try_from(buffer.len()).unwrap(), + )); + + write_u32(&mut buffer, 0); + } + } + } + + ( + metadata.name, + name_address, + metadata.exports.len(), + memory_base + u32::try_from(start).unwrap(), + ) + }) + .collect::>(); + + libraries.sort_by_key(|(name, ..)| *name); + + let start = buffer.len(); + for (name, name_address, count, symbols) in &libraries { + write_u32(&mut buffer, u32::try_from(name.len()).unwrap()); + write_u32(&mut buffer, *name_address); + write_u32(&mut buffer, u32::try_from(*count).unwrap()); + write_u32(&mut buffer, *symbols); + } + + let libraries_address = memory_base + u32::try_from(buffer.len()).unwrap(); + write_u32(&mut buffer, u32::try_from(libraries.len()).unwrap()); + write_u32(&mut buffer, memory_base + u32::try_from(start).unwrap()); + + Self { + table_base, + memory_base, + buffer, + global_addresses, + function_count, + libraries_address, + } + } +} + +fn write_u32(buffer: &mut Vec, value: u32) { + buffer.extend(value.to_le_bytes()); +} + +fn write_bytes_padded(buffer: &mut Vec, bytes: &[u8]) { + buffer.extend(bytes); + + let len = u32::try_from(bytes.len()).unwrap(); + for _ in len..align(len, 4) { + buffer.push(0); + } +} + +fn align(a: u32, b: u32) -> u32 { + assert!(b.is_power_of_two()); + (a + (b - 1)) & !(b - 1) +} + +fn get_and_increment(n: &mut u32) -> u32 { + let v = *n; + *n += 1; + v +} + +fn const_u32(a: u32) -> ConstExpr { + ConstExpr::i32_const(a as i32) +} + +/// Helper trait for determining the size of a set or map +trait Length { + fn len(&self) -> usize; +} + +impl Length for HashSet { + fn len(&self) -> usize { + HashSet::len(self) + } +} + +impl Length for HashMap { + fn len(&self) -> usize { + HashMap::len(self) + } +} + +impl Length for IndexSet { + fn len(&self) -> usize { + IndexSet::len(self) + } +} + +impl Length for IndexMap { + fn len(&self) -> usize { + IndexMap::len(self) + } +} + +/// Extension trait for collecting into a set or map and asserting that there were no duplicate entries in the +/// source iterator. +trait CollectUnique: Iterator + Sized { + fn collect_unique + Length>(self) -> T { + let tmp = self.collect::>(); + let len = tmp.len(); + let result = tmp.into_iter().collect::(); + assert!( + result.len() == len, + "one or more duplicate items detected when collecting into set or map" + ); + result + } +} + +impl CollectUnique for T {} + +/// Extension trait for inserting into a map and asserting that an entry did not already exist for the key +trait InsertUnique { + type Key; + type Value; + + fn insert_unique(&mut self, k: Self::Key, v: Self::Value); +} + +impl InsertUnique for HashMap { + type Key = K; + type Value = V; + + fn insert_unique(&mut self, k: Self::Key, v: Self::Value) { + if let Some(old_v) = self.get(&k) { + panic!("duplicate item inserted into map for key {k:?} (old value: {old_v:?}; new value: {v:?})"); + } + self.insert(k, v); + } +} + +/// Synthesize the "main" module for the component, responsible for exporting functions which break cyclic +/// dependencies, as well as hosting the memory and function table. +fn make_env_module<'a>( + metadata: &'a [Metadata<'a>], + function_exports: &[(&str, &FunctionType, usize)], + cabi_realloc_exporter: Option<&str>, + stack_size_bytes: u32, +) -> (Vec, DlOpenables<'a>, u32) { + // TODO: deduplicate types + let mut types = TypeSection::new(); + let mut imports = ImportSection::new(); + let mut import_map = IndexMap::new(); + let mut function_count = 0; + let mut global_offset = 0; + for metadata in metadata { + for import in &metadata.imports { + if let Entry::Vacant(entry) = import_map.entry(import) { + imports.import( + import.module, + import.name, + match &import.ty { + Type::Function(ty) => { + let index = get_and_increment(&mut function_count); + entry.insert(index); + types.function( + ty.parameters.iter().copied().map(ValType::from), + ty.results.iter().copied().map(ValType::from), + ); + EntityType::Function(index) + } + Type::Global(ty) => { + entry.insert(get_and_increment(&mut global_offset)); + EntityType::Global(wasm_encoder::GlobalType { + val_type: ty.ty.into(), + mutable: ty.mutable, + }) + } + }, + ); + } + } + } + + let mut memory_offset = stack_size_bytes; + let mut table_offset = 0; + let mut globals = GlobalSection::new(); + let mut exports = ExportSection::new(); + + if let Some(exporter) = cabi_realloc_exporter { + let index = get_and_increment(&mut function_count); + types.function([ValType::I32; 4], [ValType::I32]); + imports.import(exporter, "cabi_realloc", EntityType::Function(index)); + exports.export("cabi_realloc", ExportKind::Func, index); + } + + let dl_openables = DlOpenables::new(table_offset, memory_offset, metadata); + + table_offset += dl_openables.function_count; + memory_offset += u32::try_from(dl_openables.buffer.len()).unwrap(); + + let memory_size = { + let mut add_global_export = |name: &str, value, mutable| { + let index = globals.len(); + globals.global( + wasm_encoder::GlobalType { + val_type: ValType::I32, + mutable, + }, + &const_u32(value), + ); + exports.export(name, ExportKind::Global, index); + }; + + add_global_export("__stack_pointer", stack_size_bytes, true); + + for metadata in metadata { + memory_offset = align(memory_offset, 1 << metadata.mem_info.memory_alignment); + table_offset = align(table_offset, 1 << metadata.mem_info.table_alignment); + + add_global_export( + &format!("{}:memory_base", metadata.name), + memory_offset, + false, + ); + add_global_export( + &format!("{}:table_base", metadata.name), + table_offset, + false, + ); + + memory_offset += metadata.mem_info.memory_size; + table_offset += metadata.mem_info.table_size; + + for import in &metadata.memory_address_imports { + // Note that we initialize this to zero and let the init module compute the real value at + // instantiation time. + add_global_export(&format!("{}:{import}", metadata.name), 0, true); + } + } + + { + let offsets = function_exports + .iter() + .enumerate() + .map(|(offset, (name, ..))| (*name, table_offset + u32::try_from(offset).unwrap())) + .collect_unique::>(); + + for metadata in metadata { + for import in &metadata.table_address_imports { + add_global_export( + &format!("{}:{import}", metadata.name), + *offsets.get(import).unwrap(), + true, + ); + } + } + } + + memory_offset = align(memory_offset, HEAP_ALIGNMENT_BYTES); + add_global_export("__heap_base", memory_offset, true); + + let heap_end = align(memory_offset, PAGE_SIZE_BYTES); + add_global_export("__heap_end", heap_end, true); + heap_end / PAGE_SIZE_BYTES + }; + + let indirection_table_base = table_offset; + + let mut functions = FunctionSection::new(); + let mut code = CodeSection::new(); + for (name, ty, _) in function_exports { + let index = get_and_increment(&mut function_count); + types.function( + ty.parameters.iter().copied().map(ValType::from), + ty.results.iter().copied().map(ValType::from), + ); + functions.function(u32::try_from(index).unwrap()); + let mut function = Function::new([]); + for local in 0..ty.parameters.len() { + function.instruction(&Ins::LocalGet(u32::try_from(local).unwrap())); + } + function.instruction(&Ins::I32Const(i32::try_from(table_offset).unwrap())); + function.instruction(&Ins::CallIndirect { + ty: u32::try_from(index).unwrap(), + table: 0, + }); + function.instruction(&Ins::End); + code.function(&function); + exports.export(name, ExportKind::Func, index); + + table_offset += 1; + } + + for (import, offset) in import_map { + exports.export( + &format!("{}:{}", import.module, import.name), + ExportKind::from(&import.ty), + offset, + ); + } + + let mut module = Module::new(); + + module.section(&types); + module.section(&imports); + module.section(&functions); + + { + let mut tables = TableSection::new(); + tables.table(TableType { + element_type: RefType { + nullable: true, + heap_type: HeapType::Func, + }, + minimum: table_offset, + maximum: None, + }); + exports.export("__indirect_function_table", ExportKind::Table, 0); + module.section(&tables); + } + + { + let mut memories = MemorySection::new(); + memories.memory(MemoryType { + minimum: u64::from(memory_size), + maximum: None, + memory64: false, + shared: false, + }); + exports.export("memory", ExportKind::Memory, 0); + module.section(&memories); + } + + module.section(&globals); + module.section(&exports); + module.section(&code); + module.section(&RawCustomSection( + &crate::base_producers().raw_custom_section(), + )); + + let module = module.finish(); + wasmparser::validate(&module).unwrap(); + + (module, dl_openables, indirection_table_base) +} + +/// Synthesize the "init" module, responsible for initializing global variables per the dynamic linking tool +/// convention and calling any static constructors and/or link-time fixup functions. +/// +/// This module also contains the data segment for the `dlopen`/`dlsym` lookup table. +fn make_init_module( + metadata: &[Metadata], + exporters: &IndexMap<&ExportKey, (&str, &Export)>, + function_exports: &[(&str, &FunctionType, usize)], + dl_openables: DlOpenables, + indirection_table_base: u32, +) -> Result> { + let mut module = Module::new(); + + // TODO: deduplicate types + let mut types = TypeSection::new(); + types.function([], []); + let thunk_ty = 0; + types.function([ValType::I32], []); + let one_i32_param_ty = 1; + let mut type_offset = 2; + + for metadata in metadata { + if metadata.dl_openable { + for export in &metadata.exports { + if let Type::Function(ty) = &export.key.ty { + types.function( + ty.parameters.iter().copied().map(ValType::from), + ty.results.iter().copied().map(ValType::from), + ); + } + } + } + } + for (_, ty, _) in function_exports { + types.function( + ty.parameters.iter().copied().map(ValType::from), + ty.results.iter().copied().map(ValType::from), + ); + } + module.section(&types); + + let mut imports = ImportSection::new(); + imports.import( + "env", + "memory", + MemoryType { + minimum: 0, + maximum: None, + memory64: false, + shared: false, + }, + ); + imports.import( + "env", + "__indirect_function_table", + TableType { + element_type: RefType { + nullable: true, + heap_type: HeapType::Func, + }, + minimum: 0, + maximum: None, + }, + ); + + let mut global_count = 0; + let mut global_map = HashMap::new(); + let mut add_global_import = |imports: &mut ImportSection, module: &str, name: &str, mutable| { + *global_map + .entry((module.to_owned(), name.to_owned())) + .or_insert_with(|| { + imports.import( + module, + name, + wasm_encoder::GlobalType { + val_type: ValType::I32, + mutable, + }, + ); + get_and_increment(&mut global_count) + }) + }; + + let mut function_count = 0; + let mut function_map = HashMap::new(); + let mut add_function_import = |imports: &mut ImportSection, module: &str, name: &str, ty| { + *function_map + .entry((module.to_owned(), name.to_owned())) + .or_insert_with(|| { + imports.import(module, name, EntityType::Function(ty)); + get_and_increment(&mut function_count) + }) + }; + + let mut memory_address_inits = Vec::new(); + let mut reloc_calls = Vec::new(); + let mut ctor_calls = Vec::new(); + let mut names = HashMap::new(); + + for (exporter, export, address) in dl_openables.global_addresses.iter() { + memory_address_inits.push(Ins::I32Const(i32::try_from(*address).unwrap())); + memory_address_inits.push(Ins::GlobalGet(add_global_import( + &mut imports, + "env", + &format!("{exporter}:memory_base"), + false, + ))); + memory_address_inits.push(Ins::GlobalGet(add_global_import( + &mut imports, + exporter, + export, + false, + ))); + memory_address_inits.push(Ins::I32Add); + memory_address_inits.push(Ins::I32Store(MemArg { + offset: 0, + align: 2, + memory_index: 0, + })); + } + + for (index, metadata) in metadata.iter().enumerate() { + names.insert_unique(index, metadata.name); + + if metadata.has_data_relocs { + reloc_calls.push(Ins::Call(add_function_import( + &mut imports, + metadata.name, + "__wasm_apply_data_relocs", + thunk_ty, + ))); + } + + if metadata.has_ctors && metadata.has_initialize { + bail!( + "library {} exports both `__wasm_call_ctors` and `_initialize`; \ + expected at most one of the two", + metadata.name + ); + } + + if metadata.has_ctors { + ctor_calls.push(Ins::Call(add_function_import( + &mut imports, + metadata.name, + "__wasm_call_ctors", + thunk_ty, + ))); + } + + if metadata.has_initialize { + ctor_calls.push(Ins::Call(add_function_import( + &mut imports, + metadata.name, + "_initialize", + thunk_ty, + ))); + } + + if metadata.has_set_libraries { + ctor_calls.push(Ins::I32Const( + i32::try_from(dl_openables.libraries_address).unwrap(), + )); + ctor_calls.push(Ins::Call(add_function_import( + &mut imports, + metadata.name, + "__wasm_set_libraries", + one_i32_param_ty, + ))); + } + + for import in &metadata.memory_address_imports { + let (exporter, _) = find_offset_exporter(import, exporters)?; + + memory_address_inits.push(Ins::GlobalGet(add_global_import( + &mut imports, + "env", + &format!("{exporter}:memory_base"), + false, + ))); + memory_address_inits.push(Ins::GlobalGet(add_global_import( + &mut imports, + exporter, + import, + false, + ))); + memory_address_inits.push(Ins::I32Add); + memory_address_inits.push(Ins::GlobalSet(add_global_import( + &mut imports, + "env", + &format!("{}:{import}", metadata.name), + true, + ))); + } + } + + let mut dl_openable_functions = Vec::new(); + for metadata in metadata { + if metadata.dl_openable { + for export in &metadata.exports { + if let Type::Function(_) = &export.key.ty { + dl_openable_functions.push(add_function_import( + &mut imports, + metadata.name, + export.key.name, + get_and_increment(&mut type_offset), + )); + } + } + } + } + + let indirections = function_exports + .iter() + .map(|(name, _, index)| { + add_function_import( + &mut imports, + names[index], + name, + get_and_increment(&mut type_offset), + ) + }) + .collect::>(); + + module.section(&imports); + + { + let mut functions = FunctionSection::new(); + functions.function(thunk_ty); + module.section(&functions); + } + + module.section(&StartSection { + function_index: function_count, + }); + + { + let mut elements = ElementSection::new(); + elements.active( + None, + &const_u32(dl_openables.table_base), + Elements::Functions(&dl_openable_functions), + ); + elements.active( + None, + &const_u32(indirection_table_base), + Elements::Functions(&indirections), + ); + module.section(&elements); + } + + { + let mut code = CodeSection::new(); + let mut function = Function::new([]); + for ins in memory_address_inits + .iter() + .chain(&reloc_calls) + .chain(&ctor_calls) + { + function.instruction(ins); + } + function.instruction(&Ins::End); + code.function(&function); + module.section(&code); + } + + let mut data = DataSection::new(); + data.active(0, &const_u32(dl_openables.memory_base), dl_openables.buffer); + module.section(&data); + + module.section(&RawCustomSection( + &crate::base_producers().raw_custom_section(), + )); + + let module = module.finish(); + wasmparser::validate(&module)?; + + Ok(module) +} + +/// Find the library which exports the specified function or global address. +fn find_offset_exporter<'a>( + name: &str, + exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>, +) -> Result<(&'a str, &'a Export<'a>)> { + let export = ExportKey { + name, + ty: Type::Global(GlobalType { + ty: ValueType::I32, + mutable: false, + }), + }; + + exporters + .get(&export) + .copied() + .ok_or_else(|| anyhow!("unable to find {export:?} in any library")) +} + +/// Find the library which exports the specified function. +fn find_function_exporter<'a>( + name: &str, + ty: &FunctionType, + exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>, +) -> Result<(&'a str, &'a Export<'a>)> { + let export = ExportKey { + name, + ty: Type::Function(ty.clone()), + }; + + exporters + .get(&export) + .copied() + .ok_or_else(|| anyhow!("unable to find {export:?} in any library")) +} + +/// Analyze the specified library metadata, producing a symbol-to-library-name map of exports. +fn resolve_exporters<'a>( + metadata: &'a [Metadata<'a>], +) -> Result, Vec<(&'a str, &'a Export<'a>)>>> { + let mut exporters = IndexMap::<_, Vec<_>>::new(); + for metadata in metadata { + for export in &metadata.exports { + exporters + .entry(&export.key) + .or_default() + .push((metadata.name, export)); + } + } + Ok(exporters) +} + +/// Match up all imported symbols to their corresponding exports, reporting any missing or duplicate symbols. +fn resolve_symbols<'a>( + metadata: &'a [Metadata<'a>], + exporters: &'a IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>, +) -> ( + IndexMap<&'a ExportKey<'a>, (&'a str, &'a Export<'a>)>, + Vec<(&'a str, Export<'a>)>, + Vec<(&'a str, &'a ExportKey<'a>, &'a [(&'a str, &'a Export<'a>)])>, +) { + let function_exporters = exporters + .iter() + .filter_map(|(export, exporters)| { + if let Type::Function(_) = &export.ty { + Some((export.name, (export, exporters))) + } else { + None + } + }) + .collect_unique::>(); + + let mut resolved = IndexMap::new(); + let mut missing = Vec::new(); + let mut duplicates = Vec::new(); + + let mut triage = |metadata: &'a Metadata, export: Export<'a>| { + if let Some((key, value)) = exporters.get_key_value(&export.key) { + match value.as_slice() { + [] => unreachable!(), + [exporter] => { + // Note that we do not use `insert_unique` here since multiple libraries may import the same + // symbol, in which case we may redundantly insert the same value. + resolved.insert(*key, *exporter); + } + _ => { + duplicates.push((metadata.name, *key, value.as_slice())); + } + } + } else { + missing.push((metadata.name, export)); + } + }; + + for metadata in metadata { + for (name, (ty, flags)) in &metadata.env_imports { + triage( + metadata, + Export { + key: ExportKey { + name, + ty: Type::Function(ty.clone()), + }, + flags: *flags, + }, + ); + } + + for name in &metadata.memory_address_imports { + triage( + metadata, + Export { + key: ExportKey { + name, + ty: Type::Global(GlobalType { + ty: ValueType::I32, + mutable: false, + }), + }, + flags: 0, + }, + ); + } + } + + for metadata in metadata { + for name in &metadata.table_address_imports { + if let Some((key, value)) = function_exporters.get(name) { + match value.as_slice() { + [] => unreachable!(), + [exporter] => { + // Note that we do not use `insert_unique` here since multiple libraries may import the + // same symbol, in which case we may redundantly insert the same value. + resolved.insert(key, *exporter); + } + _ => { + duplicates.push((metadata.name, *key, value.as_slice())); + } + } + } else { + missing.push(( + metadata.name, + Export { + key: ExportKey { + name, + ty: Type::Function(FunctionType { + parameters: Vec::new(), + results: Vec::new(), + }), + }, + flags: 0, + }, + )); + } + } + } + + (resolved, missing, duplicates) +} + +/// Recursively add a library (represented by its offset) and its dependency to the specified set, maintaining +/// topological order (modulo cycles). +fn topo_add<'a>( + sorted: &mut IndexSet, + dependencies: &IndexMap>, + element: usize, +) { + let empty = &IndexSet::new(); + let deps = dependencies.get(&element).unwrap_or(empty); + + // First, add any dependencies which do not depend on `element` + for &dep in deps { + if !(sorted.contains(&dep) || dependencies.get(&dep).unwrap_or(empty).contains(&element)) { + topo_add(sorted, dependencies, dep); + } + } + + // Next, add the element + sorted.insert(element); + + // Finally, add any dependencies which depend on `element` + for &dep in deps { + if !sorted.contains(&dep) && dependencies.get(&dep).unwrap_or(empty).contains(&element) { + topo_add(sorted, dependencies, dep); + } + } +} + +/// Topologically sort a set of libraries (represented by their offsets) according to their dependencies, modulo +/// cycles. +fn topo_sort(count: usize, dependencies: &IndexMap>) -> Result> { + let mut sorted = IndexSet::new(); + for index in 0..count { + topo_add(&mut sorted, &dependencies, index); + } + + Ok(sorted.into_iter().collect()) +} + +/// Analyze the specified library metadata, producing a map of transitive dependencies, where each library is +/// represented by its offset in the original metadata slice. +fn find_dependencies( + metadata: &[Metadata], + exporters: &IndexMap<&ExportKey, (&str, &Export)>, +) -> Result>> { + // First, generate a map of direct dependencies (i.e. depender to dependees) + let mut dependencies = IndexMap::<_, IndexSet<_>>::new(); + let mut indexes = HashMap::new(); + for (index, metadata) in metadata.iter().enumerate() { + indexes.insert_unique(metadata.name, index); + for &needed in &metadata.needed_libs { + dependencies + .entry(metadata.name) + .or_default() + .insert(needed); + } + for (import_name, (ty, _)) in &metadata.env_imports { + dependencies + .entry(metadata.name) + .or_default() + .insert(find_function_exporter(import_name, ty, exporters)?.0); + } + } + + // Next, convert the map from names to offsets + let mut dependencies = dependencies + .into_iter() + .map(|(k, v)| { + ( + indexes[k], + v.into_iter() + .map(|v| indexes[v]) + .collect_unique::>(), + ) + }) + .collect_unique::>(); + + // Finally, add all transitive dependencies to the map in a fixpoint loop, exiting when no new dependencies are + // discovered. + let empty = &IndexSet::new(); + + loop { + let mut new = IndexMap::<_, IndexSet<_>>::new(); + for (index, exporters) in &dependencies { + for exporter in exporters { + for exporter in dependencies.get(exporter).unwrap_or(empty) { + if !exporters.contains(exporter) { + new.entry(*index).or_default().insert(*exporter); + } + } + } + } + + if new.is_empty() { + break Ok(dependencies); + } else { + for (index, exporters) in new { + dependencies.entry(index).or_default().extend(exporters); + } + } + } +} + +/// Analyze the specified metadata and generate a list of functions which should be re-exported as a +/// `call.indirect`-based function by the main (AKA "env") module, including the offset of the library containing +/// the original export. +fn env_function_exports<'a>( + metadata: &'a [Metadata<'a>], + exporters: &'a IndexMap<&'a ExportKey, (&'a str, &Export)>, + topo_sorted: &[usize], +) -> Result> { + let function_exporters = exporters + .iter() + .filter_map(|(export, exporter)| { + if let Type::Function(ty) = &export.ty { + Some((export.name, (ty, *exporter))) + } else { + None + } + }) + .collect_unique::>(); + + let indexes = metadata + .iter() + .enumerate() + .map(|(index, metadata)| (metadata.name, index)) + .collect_unique::>(); + + let mut result = Vec::new(); + let mut exported = HashSet::new(); + let mut seen = HashSet::new(); + + for &index in topo_sorted { + let metadata = &metadata[index]; + + for name in &metadata.table_address_imports { + if !exported.contains(name) { + let (ty, (exporter, _)) = function_exporters + .get(name) + .ok_or_else(|| anyhow!("unable to find {name:?} in any library"))?; + + result.push((*name, *ty, indexes[exporter])); + exported.insert(*name); + } + } + + for (import_name, (ty, _)) in &metadata.env_imports { + if !exported.contains(import_name) { + let exporter = indexes[find_function_exporter(import_name, ty, exporters) + .unwrap() + .0]; + if !seen.contains(&exporter) { + result.push((*import_name, ty, exporter)); + exported.insert(*import_name); + } + } + } + seen.insert(index); + } + + Ok(result) +} + +/// Synthesize a module which contains trapping stub exports for the specified functions. +fn make_stubs_module(missing: &[(&str, Export)]) -> Vec { + let mut types = TypeSection::new(); + let mut exports = ExportSection::new(); + let mut functions = FunctionSection::new(); + let mut code = CodeSection::new(); + for (offset, (_, export)) in missing.iter().enumerate() { + let offset = u32::try_from(offset).unwrap(); + + let Export { + key: + ExportKey { + name, + ty: Type::Function(ty), + }, + .. + } = export + else { + unreachable!(); + }; + + types.function( + ty.parameters.iter().copied().map(ValType::from), + ty.results.iter().copied().map(ValType::from), + ); + functions.function(offset); + let mut function = Function::new([]); + function.instruction(&Ins::Unreachable); + function.instruction(&Ins::End); + code.function(&function); + exports.export(name, ExportKind::Func, offset); + } + + let mut module = Module::new(); + + module.section(&types); + module.section(&functions); + module.section(&exports); + module.section(&code); + module.section(&RawCustomSection( + &crate::base_producers().raw_custom_section(), + )); + + let module = module.finish(); + wasmparser::validate(&module).unwrap(); + + module +} + +/// Determine which of the specified libraries are transitively reachable at runtime, i.e. reachable from a +/// component export or via `dlopen`. +fn find_reachable<'a>( + metadata: &'a [Metadata<'a>], + dependencies: &IndexMap>, +) -> IndexSet<&'a str> { + let reachable = metadata + .iter() + .enumerate() + .filter_map(|(index, metadata)| { + if metadata.has_component_exports || metadata.dl_openable { + Some(index) + } else { + None + } + }) + .collect_unique::>(); + + let empty = &IndexSet::new(); + + reachable + .iter() + .chain( + reachable + .iter() + .flat_map(|index| dependencies.get(index).unwrap_or(empty)), + ) + .map(|&index| metadata[index].name) + .collect() +} + +/// Builder type for composing dynamic library modules into a component +#[derive(Default)] +pub struct Linker { + /// The `(name, module, dl_openable)` triple representing the libraries to be composed + libraries: Vec<(String, Vec, bool)>, + + /// The set of adapters to use when generating the component + adapters: Vec<(String, Vec)>, + + /// Whether to validate the resulting component prior to returning it + validate: bool, + + /// Whether to generate trapping stubs for any unresolved imports + stub_missing_functions: bool, + + /// Size of stack (in bytes) to allocate in the synthesized main module + /// + /// If `None`, use `DEFAULT_STACK_SIZE_BYTES`. + stack_size: Option, +} + +impl Linker { + /// Add a dynamic library module to this linker. + /// + /// If `dl_openable` is true, all of the libraries exports will be added to the `dlopen`/`dlsym` lookup table + /// for runtime resolution. + pub fn library(mut self, name: &str, module: &[u8], dl_openable: bool) -> Result { + self.libraries + .push((name.to_owned(), module.to_vec(), dl_openable)); + + Ok(self) + } + + /// Add an adapter to this linker. + /// + /// See [crate::encoding::ComponentEncoder::adapter] for details. + pub fn adapter(mut self, name: &str, module: &[u8]) -> Result { + self.adapters.push((name.to_owned(), module.to_vec())); + + Ok(self) + } + + /// Specify whether to validate the resulting component prior to returning it + pub fn validate(mut self, validate: bool) -> Self { + self.validate = validate; + self + } + + /// Specify size of stack to allocate in the synthesized main module + pub fn stack_size(mut self, stack_size: u32) -> Self { + self.stack_size = Some(stack_size); + self + } + + /// Specify whether to generate trapping stubs for any unresolved imports + pub fn stub_missing_functions(mut self, stub_missing_functions: bool) -> Self { + self.stub_missing_functions = stub_missing_functions; + self + } + + /// Encode the component and return the bytes + pub fn encode(mut self) -> Result> { + let adapter_names = self + .adapters + .iter() + .map(|(name, _)| name.as_str()) + .collect_unique::>(); + + if adapter_names.len() != self.adapters.len() { + bail!("duplicate adapter name"); + } + + let metadata = self + .libraries + .iter() + .map(|(name, module, dl_openable)| { + Metadata::try_new(name, *dl_openable, module, &adapter_names) + .with_context(|| format!("failed to extract linking metadata from {name}")) + }) + .collect::>>()?; + + { + let names = self + .libraries + .iter() + .map(|(name, ..)| name.as_str()) + .collect_unique::>(); + + let missing = metadata + .iter() + .filter_map(|metadata| { + let missing = metadata + .needed_libs + .iter() + .copied() + .filter(|name| !names.contains(*name)) + .collect::>(); + + if missing.is_empty() { + None + } else { + Some((metadata.name, missing)) + } + }) + .collect::>(); + + if !missing.is_empty() { + bail!( + "missing libraries:\n{}", + missing + .iter() + .map(|(needed_by, missing)| format!( + "\t{needed_by} needs {}", + missing.join(", ") + )) + .collect::>() + .join("\n") + ); + } + } + + let mut exporters = resolve_exporters(&metadata)?; + + let cabi_realloc_exporter = exporters + .get_mut(&ExportKey { + name: "cabi_realloc", + ty: Type::Function(FunctionType { + parameters: vec![ValueType::I32; 4], + results: vec![ValueType::I32], + }), + }) + .map(|exporters| { + // TODO: When there are multiple exporters, we should choose the one that came first in the order + // they were specified. + let first = *exporters.first().unwrap(); + *exporters = vec![first]; + first.0 + }); + + let (exporters, missing, duplicates) = resolve_symbols(&metadata, &exporters); + + if !missing.is_empty() { + if missing + .iter() + .all(|(_, export)| matches!(&export.key.ty, Type::Function(_))) + && (self.stub_missing_functions + || missing + .iter() + .all(|(_, export)| 0 != (export.flags & WASM_SYM_BINDING_WEAK))) + { + self.stub_missing_functions = false; + self.libraries.push(( + "wit-component:stubs".into(), + make_stubs_module(&missing), + false, + )); + return self.encode(); + } else { + bail!( + "unresolved symbol(s):\n{}", + missing + .iter() + .filter(|(_, export)| 0 == (export.flags & WASM_SYM_BINDING_WEAK)) + .map(|(importer, export)| { format!("\t{importer} needs {}", export.key) }) + .collect::>() + .join("\n") + ); + } + } + + if !duplicates.is_empty() { + // TODO: When there are multiple exporters for a given symbol, we should choose the one that came first + // in the order they were specified. + bail!( + "duplicate symbol(s):\n{}", + duplicates + .iter() + .map(|(importer, key, exporters)| { + format!( + "\t{importer} needs {key}, provided by {}", + exporters + .iter() + .map(|(exporter, _)| *exporter) + .collect::>() + .join(", ") + ) + }) + .collect::>() + .join("\n") + ); + } + + let dependencies = find_dependencies(&metadata, &exporters)?; + + { + let reachable = find_reachable(&metadata, &dependencies); + let unreachable = self + .libraries + .iter() + .filter_map(|(name, ..)| (!reachable.contains(name.as_str())).then(|| name.clone())) + .collect_unique::>(); + + if !unreachable.is_empty() { + self.libraries + .retain(|(name, ..)| !unreachable.contains(name)); + return self.encode(); + } + } + + let topo_sorted = topo_sort(metadata.len(), &dependencies)?; + + let env_function_exports = env_function_exports(&metadata, &exporters, &topo_sorted)?; + + let (env_module, dl_openables, table_base) = make_env_module( + &metadata, + &env_function_exports, + cabi_realloc_exporter, + self.stack_size.unwrap_or(DEFAULT_STACK_SIZE_BYTES), + ); + + let mut encoder = ComponentEncoder::default() + .validate(self.validate) + .module(&env_module)?; + + for (name, module) in &self.adapters { + encoder = encoder.adapter(name, module)?; + } + + let default_env_items = [ + Item { + alias: "memory".into(), + kind: ExportKind::Memory, + which: MainOrAdapter::Main, + name: "memory".into(), + }, + Item { + alias: "__indirect_function_table".into(), + kind: ExportKind::Table, + which: MainOrAdapter::Main, + name: "__indirect_function_table".into(), + }, + Item { + alias: "__stack_pointer".into(), + kind: ExportKind::Global, + which: MainOrAdapter::Main, + name: "__stack_pointer".into(), + }, + ]; + + let mut seen = HashSet::new(); + for index in topo_sorted { + let (name, module, _) = &self.libraries[index]; + let metadata = &metadata[index]; + + let env_items = default_env_items + .iter() + .cloned() + .chain([ + Item { + alias: "__memory_base".into(), + kind: ExportKind::Global, + which: MainOrAdapter::Main, + name: format!("{name}:memory_base"), + }, + Item { + alias: "__table_base".into(), + kind: ExportKind::Global, + which: MainOrAdapter::Main, + name: format!("{name}:table_base"), + }, + ]) + .chain(metadata.env_imports.iter().map(|(name, (ty, _))| { + let (exporter, _) = find_function_exporter(name, ty, &exporters).unwrap(); + + Item { + alias: (*name).into(), + kind: ExportKind::Func, + which: if seen.contains(exporter) { + MainOrAdapter::Adapter(exporter.to_owned()) + } else { + MainOrAdapter::Main + }, + name: (*name).into(), + } + })) + .collect(); + + let global_item = |address_name: &str| Item { + alias: address_name.into(), + kind: ExportKind::Global, + which: MainOrAdapter::Main, + name: format!("{name}:{address_name}"), + }; + + let mem_items = metadata + .memory_address_imports + .iter() + .copied() + .map(global_item) + .chain(["__heap_base", "__heap_end"].into_iter().map(|name| Item { + alias: name.into(), + kind: ExportKind::Global, + which: MainOrAdapter::Main, + name: name.into(), + })) + .collect(); + + let func_items = metadata + .table_address_imports + .iter() + .copied() + .map(global_item) + .collect(); + + let mut import_items = BTreeMap::<_, Vec<_>>::new(); + for import in &metadata.imports { + import_items.entry(import.module).or_default().push(Item { + alias: import.name.into(), + kind: ExportKind::from(&import.ty), + which: MainOrAdapter::Main, + name: format!("{}:{}", import.module, import.name), + }); + } + + encoder = encoder.library( + name, + module, + LibraryInfo { + instantiate_after_shims: false, + arguments: [ + ("GOT.mem".into(), Instance::Items(mem_items)), + ("GOT.func".into(), Instance::Items(func_items)), + ("env".into(), Instance::Items(env_items)), + ] + .into_iter() + .chain( + import_items + .into_iter() + .map(|(k, v)| (k.into(), Instance::Items(v))), + ) + .collect(), + }, + )?; + + seen.insert(name.as_str()); + } + + encoder + .library( + "__init", + &make_init_module( + &metadata, + &exporters, + &env_function_exports, + dl_openables, + table_base, + )?, + LibraryInfo { + instantiate_after_shims: true, + arguments: iter::once(( + "env".into(), + Instance::MainOrAdapter(MainOrAdapter::Main), + )) + .chain(self.libraries.iter().map(|(name, ..)| { + ( + name.clone(), + Instance::MainOrAdapter(MainOrAdapter::Adapter(name.clone())), + ) + })) + .collect(), + }, + )? + .encode() + } +} diff --git a/crates/wit-component/src/linking/metadata.rs b/crates/wit-component/src/linking/metadata.rs new file mode 100644 index 0000000000..430f6b9775 --- /dev/null +++ b/crates/wit-component/src/linking/metadata.rs @@ -0,0 +1,540 @@ +//! Support for parsing and analyzing [dynamic +//! library](https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md) modules. + +use { + anyhow::{bail, Context, Error, Result}, + std::{ + collections::{BTreeSet, HashMap, HashSet}, + fmt, + }, + wasmparser::{ + BinaryReader, BinaryReaderError, ExternalKind, FuncType, Parser, Payload, RefType, + Subsection, Subsections, TableType, TypeRef, ValType, + }, +}; + +pub const WASM_DYLINK_MEM_INFO: u8 = 1; +pub const WASM_DYLINK_NEEDED: u8 = 2; +pub const WASM_DYLINK_EXPORT_INFO: u8 = 3; +pub const WASM_DYLINK_IMPORT_INFO: u8 = 4; + +/// Represents a core Wasm value type (not including V128 or reference types, which are not yet supported) +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ValueType { + I32, + I64, + F32, + F64, +} + +impl TryFrom for ValueType { + type Error = Error; + + fn try_from(value: ValType) -> Result { + Ok(match value { + ValType::I32 => Self::I32, + ValType::I64 => Self::I64, + ValType::F32 => Self::F32, + ValType::F64 => Self::F64, + _ => bail!("{value:?} not yet supported"), + }) + } +} + +impl From for wasm_encoder::ValType { + fn from(value: ValueType) -> Self { + match value { + ValueType::I32 => Self::I32, + ValueType::I64 => Self::I64, + ValueType::F32 => Self::F32, + ValueType::F64 => Self::F64, + } + } +} + +/// Represents a core Wasm function type +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct FunctionType { + pub parameters: Vec, + pub results: Vec, +} + +impl fmt::Display for FunctionType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?} -> {:?}", self.parameters, self.results) + } +} + +impl TryFrom<&FuncType> for FunctionType { + type Error = Error; + + fn try_from(value: &FuncType) -> Result { + Ok(Self { + parameters: value + .params() + .iter() + .map(|&v| ValueType::try_from(v)) + .collect::>()?, + results: value + .results() + .iter() + .map(|&v| ValueType::try_from(v)) + .collect::>()?, + }) + } +} + +/// Represents a core Wasm global variable type +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct GlobalType { + pub ty: ValueType, + pub mutable: bool, +} + +impl fmt::Display for GlobalType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.mutable { + write!(f, "mut ")?; + } + write!(f, "{:?}", self.ty) + } +} + +/// Represents a core Wasm export or import type +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Type { + Function(FunctionType), + Global(GlobalType), +} + +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Function(ty) => write!(f, "function {ty}"), + Self::Global(ty) => write!(f, "global {ty}"), + } + } +} + +impl From<&Type> for wasm_encoder::ExportKind { + fn from(value: &Type) -> Self { + match value { + Type::Function(_) => wasm_encoder::ExportKind::Func, + Type::Global(_) => wasm_encoder::ExportKind::Global, + } + } +} + +/// Represents a core Wasm import +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Import<'a> { + pub module: &'a str, + pub name: &'a str, + pub ty: Type, + pub flags: u32, +} + +/// Represents a core Wasm export +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ExportKey<'a> { + pub name: &'a str, + pub ty: Type, +} + +impl<'a> fmt::Display for ExportKey<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} ({})", self.name, self.ty) + } +} + +/// Represents a core Wasm export, including dylink.0 flags +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Export<'a> { + pub key: ExportKey<'a>, + pub flags: u32, +} + +/// Represents a `WASM_DYLINK_MEM_INFO` value +#[derive(Debug, Copy, Clone)] +pub struct MemInfo { + pub memory_size: u32, + pub memory_alignment: u32, + pub table_size: u32, + pub table_alignment: u32, +} + +impl Default for MemInfo { + fn default() -> Self { + Self { + memory_size: 0, + memory_alignment: 1, + table_size: 0, + table_alignment: 1, + } + } +} + +/// Metadata extracted from a dynamic library module +#[derive(Debug)] +pub struct Metadata<'a> { + /// The name of the module + /// + /// This is currently not part of the file itself and must be provided separately, but the plan is to add + /// something like a `WASM_DYLINK_SO_NAME` field to the dynamic linking tool convention so we can parse it + /// along with everything else. + pub name: &'a str, + + /// Whether this module should be resolvable via `dlopen` + pub dl_openable: bool, + + /// The `WASM_DYLINK_MEM_INFO` value (or all zeros if not found) + pub mem_info: MemInfo, + + /// The `WASM_DYLINK_NEEDED` values, if any + pub needed_libs: Vec<&'a str>, + + /// Whether this module exports `__wasm_apply_data_relocs` + pub has_data_relocs: bool, + + /// Whether this module exports `__wasm_call_ctors` + pub has_ctors: bool, + + /// Whether this module exports `_initialize` + pub has_initialize: bool, + + /// Whether this module exports `__wasm_set_libraries` + pub has_set_libraries: bool, + + /// Whether this module includes any `component-type*` custom sections which include exports + pub has_component_exports: bool, + + /// The functions imported from the `env` module, if any + pub env_imports: BTreeSet<(&'a str, (FunctionType, u32))>, + + /// The memory addresses imported from `GOT.mem`, if any + pub memory_address_imports: BTreeSet<&'a str>, + + /// The table addresses imported from `GOT.func`, if any + pub table_address_imports: BTreeSet<&'a str>, + + /// The symbols exported by this module, if any + pub exports: BTreeSet>, + + /// The symbols imported by this module (and not accounted for in the above fields), if any + pub imports: BTreeSet>, +} + +#[derive(Debug)] +struct ExportInfo<'a> { + name: &'a str, + flags: u32, +} + +#[derive(Debug)] +struct ImportInfo<'a> { + module: &'a str, + field: &'a str, + flags: u32, +} + +#[derive(Debug)] +enum DylinkSubsection<'a> { + MemInfo(MemInfo), + Needed(Vec<&'a str>), + ExportInfo(Vec>), + ImportInfo(Vec>), + Unknown(u8), +} + +type DylinkSectionReader<'a> = Subsections<'a, DylinkSubsection<'a>>; + +impl<'a> Subsection<'a> for DylinkSubsection<'a> { + fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result { + Ok(match id { + WASM_DYLINK_MEM_INFO => Self::MemInfo(MemInfo { + memory_size: reader.read_var_u32()?, + memory_alignment: reader.read_var_u32()?, + table_size: reader.read_var_u32()?, + table_alignment: reader.read_var_u32()?, + }), + WASM_DYLINK_NEEDED => Self::Needed( + (0..reader.read_var_u32()?) + .map(|_| reader.read_string()) + .collect::>()?, + ), + WASM_DYLINK_EXPORT_INFO => Self::ExportInfo( + (0..reader.read_var_u32()?) + .map(|_| { + Ok(ExportInfo { + name: reader.read_string()?, + flags: reader.read_var_u32()?, + }) + }) + .collect::>()?, + ), + WASM_DYLINK_IMPORT_INFO => Self::ImportInfo( + (0..reader.read_var_u32()?) + .map(|_| { + Ok(ImportInfo { + module: reader.read_string()?, + field: reader.read_string()?, + flags: reader.read_var_u32()?, + }) + }) + .collect::>()?, + ), + _ => Self::Unknown(id), + }) + } +} + +impl<'a> Metadata<'a> { + /// Parse the specified module and extract its metadata. + pub fn try_new( + name: &'a str, + dl_openable: bool, + module: &'a [u8], + adapter_names: &HashSet<&str>, + ) -> Result { + let bindgen = crate::metadata::decode(module)?.1; + let has_component_exports = !bindgen.resolve.worlds[bindgen.world].exports.is_empty(); + + let mut result = Self { + name, + dl_openable, + mem_info: MemInfo::default(), + needed_libs: Vec::new(), + has_data_relocs: false, + has_ctors: false, + has_initialize: false, + has_set_libraries: false, + has_component_exports, + env_imports: BTreeSet::new(), + memory_address_imports: BTreeSet::new(), + table_address_imports: BTreeSet::new(), + exports: BTreeSet::new(), + imports: BTreeSet::new(), + }; + let mut types = Vec::new(); + let mut function_types = Vec::new(); + let mut global_types = Vec::new(); + let mut import_info = HashMap::new(); + let mut export_info = HashMap::new(); + + for payload in Parser::new(0).parse_all(module) { + match payload? { + Payload::CustomSection(section) if section.name() == "dylink.0" => { + let reader = DylinkSectionReader::new(section.data(), section.data_offset()); + for subsection in reader { + match subsection.context("failed to parse `dylink.0` subsection")? { + DylinkSubsection::MemInfo(info) => result.mem_info = info, + DylinkSubsection::Needed(needed) => result.needed_libs = needed.clone(), + DylinkSubsection::ExportInfo(info) => { + export_info.extend(info.iter().map(|info| (info.name, info.flags))); + } + DylinkSubsection::ImportInfo(info) => { + import_info.extend( + info.iter() + .map(|info| ((info.module, info.field), info.flags)), + ); + } + DylinkSubsection::Unknown(index) => { + bail!("unrecognized `dylink.0` subsection: {index}") + } + } + } + } + + Payload::TypeSection(reader) => { + types = reader + .into_iter_err_on_gc_types() + .collect::, _>>()?; + } + + Payload::ImportSection(reader) => { + for import in reader { + let import = import?; + + match import.ty { + TypeRef::Func(ty) => function_types.push(usize::try_from(ty).unwrap()), + TypeRef::Global(ty) => global_types.push(ty), + _ => (), + } + + let type_error = || { + bail!( + "unexpected type for {}:{}: {:?}", + import.module, + import.name, + import.ty + ) + }; + + match (import.module, import.name) { + ("env", "memory") => { + if !matches!(import.ty, TypeRef::Memory(_)) { + return type_error(); + } + } + ("env", "__memory_base" | "__table_base" | "__stack_pointer") => { + if !matches!( + import.ty, + TypeRef::Global(wasmparser::GlobalType { + content_type: ValType::I32, + .. + }) + ) { + return type_error(); + } + } + ("env", "__indirect_function_table") => { + if let TypeRef::Table(TableType { + element_type, + maximum: None, + .. + }) = import.ty + { + if element_type != RefType::FUNCREF { + return type_error(); + } + } else { + return type_error(); + } + } + ("env", name) => { + if let TypeRef::Func(ty) = import.ty { + result.env_imports.insert(( + name, + ( + FunctionType::try_from( + &types[usize::try_from(ty).unwrap()], + )?, + *import_info.get(&("env", name)).unwrap_or(&0), + ), + )); + } else { + return type_error(); + } + } + ("GOT.mem", name) => { + if let TypeRef::Global(wasmparser::GlobalType { + content_type: ValType::I32, + .. + }) = import.ty + { + match name { + "__heap_base" | "__heap_end" => (), + _ => { + result.memory_address_imports.insert(name); + } + } + } else { + return type_error(); + } + } + ("GOT.func", name) => { + if let TypeRef::Global(wasmparser::GlobalType { + content_type: ValType::I32, + .. + }) = import.ty + { + result.table_address_imports.insert(name); + } else { + return type_error(); + } + } + (module, name) if adapter_names.contains(module) => { + let ty = match import.ty { + TypeRef::Global(wasmparser::GlobalType { + content_type, + mutable, + }) => Type::Global(GlobalType { + ty: content_type.try_into()?, + mutable, + }), + TypeRef::Func(ty) => Type::Function(FunctionType::try_from( + &types[usize::try_from(ty).unwrap()], + )?), + ty => { + bail!("unsupported import kind for {module}.{name}: {ty:?}",) + } + }; + let flags = *import_info.get(&(module, name)).unwrap_or(&0); + result.imports.insert(Import { + module, + name, + ty, + flags, + }); + } + _ => { + if !matches!(import.ty, TypeRef::Func(_) | TypeRef::Global(_)) { + return type_error(); + } + } + } + } + } + + Payload::FunctionSection(reader) => { + for function in reader { + function_types.push(usize::try_from(function?).unwrap()); + } + } + + Payload::GlobalSection(reader) => { + for global in reader { + global_types.push(global?.ty); + } + } + + Payload::ExportSection(reader) => { + for export in reader { + let export = export?; + + match export.name { + "__wasm_apply_data_relocs" => result.has_data_relocs = true, + "__wasm_call_ctors" => result.has_ctors = true, + "_initialize" => result.has_initialize = true, + "__wasm_set_libraries" => result.has_set_libraries = true, + _ => { + let ty = match export.kind { + ExternalKind::Func => Type::Function(FunctionType::try_from( + &types[function_types + [usize::try_from(export.index).unwrap()]], + )?), + ExternalKind::Global => { + let ty = + global_types[usize::try_from(export.index).unwrap()]; + Type::Global(GlobalType { + ty: ValueType::try_from(ty.content_type)?, + mutable: ty.mutable, + }) + } + kind => { + bail!( + "unsupported export kind for {}: {kind:?}", + export.name + ) + } + }; + let flags = *export_info.get(&export.name).unwrap_or(&0); + result.exports.insert(Export { + key: ExportKey { + name: export.name, + ty, + }, + flags, + }); + } + } + } + } + + _ => {} + } + } + + Ok(result) + } +} diff --git a/crates/wit-component/src/metadata.rs b/crates/wit-component/src/metadata.rs new file mode 100644 index 0000000000..a452e5ef5a --- /dev/null +++ b/crates/wit-component/src/metadata.rs @@ -0,0 +1,333 @@ +//! Definition for encoding of custom sections within core wasm modules of +//! component-model related data. +//! +//! When creating a component from a source language the high-level process for +//! doing this is that code will be generated into the source language by +//! `wit-bindgen` or a similar tool which will be compiled down to core wasm. +//! The core wasm file is then fed into `wit-component` and a component is +//! created. This means that the componentization process is decoupled from the +//! binding generation process and intentionally affords for linking together +//! libraries into the main core wasm module that import different interfaces. +//! +//! The purpose of this module is to define an intermediate format to reside in +//! a custom section in the core wasm output. This intermediate format is +//! carried through the wasm linker through a custom section whose name starts +//! with `component-type`. This custom section is created +//! per-language-binding-generation and consumed by slurping up all the +//! sections during the component creation process. +//! +//! Currently the encoding of this custom section is: +//! +//! * First, a version byte (`CURRENT_VERSION`). This is intended to detect +//! mismatches between different versions of the binding generator and +//! `wit-component` which may or may not become a problem over time. +//! +//! * Next a string encoding byte. +//! +//! * Next, three strings are encoded. These are the names of the root package, +//! document, and world that the bindings were generated for. These strings +//! are used as lookups into the next field. +//! +//! * Finally the Wasm-encoded representation of a `Resolve` is included in its +//! binary form. This is the encoding of a package into wasm, and the bound +//! world for the bindings is specified from the prior strings. + +use crate::validation::BARE_FUNC_MODULE_NAME; +use crate::{DecodedWasm, StringEncoding}; +use anyhow::{bail, Context, Result}; +use indexmap::IndexMap; +use wasm_encoder::Encode; +use wasm_metadata::Producers; +use wasmparser::BinaryReader; +use wit_parser::{Package, PackageName, Resolve, World, WorldId, WorldItem}; + +const CURRENT_VERSION: u8 = 0x03; + +/// The result of decoding binding information from a WebAssembly binary. +/// +/// This structure is returned by [`decode`] and represents the interface of a +/// WebAssembly binary. +pub struct Bindgen { + /// Interface and type information for this binary. + pub resolve: Resolve, + /// The world that was bound. + pub world: WorldId, + /// Metadata about this specific module that was bound. + pub metadata: ModuleMetadata, + /// Producer information about tools used to produce this specific module. + pub producers: Option, +} + +impl Default for Bindgen { + fn default() -> Bindgen { + let mut resolve = Resolve::default(); + let package = resolve.packages.alloc(Package { + name: PackageName { + namespace: "root".to_string(), + name: "root".to_string(), + version: None, + }, + docs: Default::default(), + interfaces: Default::default(), + worlds: Default::default(), + }); + let world = resolve.worlds.alloc(World { + name: "root".to_string(), + docs: Default::default(), + imports: Default::default(), + exports: Default::default(), + includes: Default::default(), + include_names: Default::default(), + package: Some(package), + }); + resolve.packages[package] + .worlds + .insert("root".to_string(), world); + Bindgen { + resolve, + world, + metadata: ModuleMetadata::default(), + producers: None, + } + } +} + +/// Module-level metadata that's specific to one core WebAssembly module. This +/// is extracted with a [`Bindgen`]. +#[derive(Default)] +pub struct ModuleMetadata { + /// Per-function options imported into the core wasm module, currently only + /// related to string encoding. + pub import_encodings: IndexMap<(String, String), StringEncoding>, + + /// Per-function options exported from the core wasm module, currently only + /// related to string encoding. + pub export_encodings: IndexMap, +} + +/// This function will parse the `wasm` binary given as input and return a +/// [`Bindgen`] which extracts the custom sections describing component-level +/// types from within the binary itself. +/// +/// This is used to parse the output of `wit-bindgen`-generated modules and is +/// one of the earliest phases in transitioning such a module to a component. +/// The extraction here provides the metadata necessary to continue the process +/// later on. +/// +/// Note that a "stripped" binary where `component-type` sections are removed +/// is returned as well to embed within a component. +pub fn decode(wasm: &[u8]) -> Result<(Vec, Bindgen)> { + let mut ret = Bindgen::default(); + let mut new_module = wasm_encoder::Module::new(); + + for payload in wasmparser::Parser::new(0).parse_all(wasm) { + let payload = payload.context("decoding item in module")?; + match payload { + wasmparser::Payload::CustomSection(cs) if cs.name().starts_with("component-type") => { + let data = Bindgen::decode(cs.data()) + .with_context(|| format!("decoding custom section {}", cs.name()))?; + ret.merge(data) + .with_context(|| format!("updating metadata for section {}", cs.name()))?; + } + _ => { + if let Some((id, range)) = payload.as_section() { + new_module.section(&wasm_encoder::RawSection { + id, + data: &wasm[range], + }); + } + } + } + } + + Ok((new_module.finish(), ret)) +} + +/// Creates a `component-type*` custom section to be decoded by `decode` above. +/// +/// This is primarily created by wit-bindgen-based guest generators to embed +/// into the final core wasm binary. The core wasm binary is later fed +/// through `wit-component` to produce the actual component where this returned +/// section will be decoded. +pub fn encode( + resolve: &Resolve, + world: WorldId, + encoding: StringEncoding, + extra_producers: Option<&Producers>, +) -> Result> { + let world = &resolve.worlds[world]; + let pkg = &resolve.packages[world.package.unwrap()]; + + assert!( + resolve + .packages + .iter() + .filter(|(_, p)| p.name == pkg.name) + .count() + == 1 + ); + + let mut ret = Vec::new(); + ret.push(CURRENT_VERSION); + ret.push(match encoding { + StringEncoding::UTF8 => 0x00, + StringEncoding::UTF16 => 0x01, + StringEncoding::CompactUTF16 => 0x02, + }); + world.name.encode(&mut ret); + // This appends a wasm binary encoded Component to the ret: + let mut component_builder = crate::encoding::encode_component(resolve, world.package.unwrap())?; + + let mut producers = crate::base_producers(); + if let Some(p) = extra_producers { + producers.merge(&p); + } + component_builder.raw_custom_section(&producers.raw_custom_section()); + ret.extend(component_builder.finish()); + Ok(ret) +} + +impl Bindgen { + fn decode(data: &[u8]) -> Result { + let mut reader = BinaryReader::new(data); + let version = reader.read_u8()?; + if version != CURRENT_VERSION { + bail!("component-type version {version} does not match supported version {CURRENT_VERSION}"); + } + let encoding = match reader.read_u8()? { + 0x00 => StringEncoding::UTF8, + 0x01 => StringEncoding::UTF16, + 0x02 => StringEncoding::CompactUTF16, + byte => bail!("invalid string encoding {byte:#x}"), + }; + let world_name = reader.read_string()?; + + let (resolve, pkg) = match crate::decode(&data[reader.original_position()..])? { + DecodedWasm::WitPackage(resolve, pkg) => (resolve, pkg), + DecodedWasm::Component(..) => bail!("expected an encoded wit package"), + }; + let world = resolve.packages[pkg].worlds[world_name]; + let metadata = ModuleMetadata::new(&resolve, world, encoding); + let producers = wasm_metadata::Producers::from_wasm(&data[reader.original_position()..])?; + Ok(Bindgen { + resolve, + world, + metadata, + producers, + }) + } + + /// Merges another `BindgenMetadata` into this one. + /// + /// This operation is intended to be akin to "merging worlds" when the + /// abstraction level for that is what we're working at here. For now the + /// merge operation only succeeds if the two metadata descriptions are + /// entirely disjoint. + /// + /// Note that at this time there's no support for changing string encodings + /// between metadata. + pub fn merge(&mut self, other: Bindgen) -> Result { + let Bindgen { + resolve, + world, + metadata: + ModuleMetadata { + import_encodings, + export_encodings, + }, + producers, + } = other; + + let world = self + .resolve + .merge(resolve) + .context("failed to merge WIT package sets together")? + .worlds[world.index()]; + self.resolve + .merge_worlds(world, self.world) + .context("failed to merge worlds from two documents")?; + + for (name, encoding) in export_encodings { + let prev = self + .metadata + .export_encodings + .insert(name.clone(), encoding); + if let Some(prev) = prev { + if prev != encoding { + bail!("conflicting string encodings specified for export `{name}`"); + } + } + } + for ((module, name), encoding) in import_encodings { + let prev = self + .metadata + .import_encodings + .insert((module.clone(), name.clone()), encoding); + if let Some(prev) = prev { + if prev != encoding { + bail!("conflicting string encodings specified for import `{module}::{name}`"); + } + } + } + if let Some(producers) = producers { + if let Some(mine) = &mut self.producers { + mine.merge(&producers); + } else { + self.producers = Some(producers); + } + } + + Ok(world) + } +} + +impl ModuleMetadata { + /// Creates a new `ModuleMetadata` instance holding the given set of + /// interfaces which are expected to all use the `encoding` specified. + pub fn new(resolve: &Resolve, world: WorldId, encoding: StringEncoding) -> ModuleMetadata { + let mut ret = ModuleMetadata::default(); + + let world = &resolve.worlds[world]; + for (name, item) in world.imports.iter() { + let name = resolve.name_world_key(name); + match item { + WorldItem::Function(_) => { + let prev = ret + .import_encodings + .insert((BARE_FUNC_MODULE_NAME.to_string(), name.clone()), encoding); + assert!(prev.is_none()); + } + WorldItem::Interface(i) => { + for (func, _) in resolve.interfaces[*i].functions.iter() { + let prev = ret + .import_encodings + .insert((name.clone(), func.clone()), encoding); + assert!(prev.is_none()); + } + } + WorldItem::Type(_) => {} + } + } + + for (name, item) in world.exports.iter() { + let name = resolve.name_world_key(name); + match item { + WorldItem::Function(func) => { + let name = func.core_export_name(None).into_owned(); + let prev = ret.export_encodings.insert(name.clone(), encoding); + assert!(prev.is_none()); + } + WorldItem::Interface(i) => { + for (_, func) in resolve.interfaces[*i].functions.iter() { + let name = func.core_export_name(Some(&name)).into_owned(); + let prev = ret.export_encodings.insert(name, encoding); + assert!(prev.is_none()); + } + } + WorldItem::Type(_) => {} + } + } + + ret + } +} diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs new file mode 100644 index 0000000000..2fa9aba35f --- /dev/null +++ b/crates/wit-component/src/printing.rs @@ -0,0 +1,973 @@ +use anyhow::{anyhow, bail, Result}; +use std::collections::HashMap; +use std::fmt::{self, Write}; +use std::mem; +use wit_parser::*; + +// NB: keep in sync with `crates/wit-parser/src/ast/lex.rs` +const PRINT_SEMICOLONS_DEFAULT: bool = false; + +/// A utility for printing WebAssembly interface definitions to a string. +pub struct WitPrinter { + output: Output, + + // Count of how many items in this current block have been printed to print + // a blank line between each item, but not the first item. + any_items: bool, + + // Whether to print doc comments. + emit_docs: bool, + + print_semicolons: bool, +} + +impl Default for WitPrinter { + fn default() -> Self { + Self { + output: Default::default(), + any_items: false, + emit_docs: true, + print_semicolons: match std::env::var("WIT_REQUIRE_SEMICOLONS") { + Ok(s) => s == "1", + Err(_) => PRINT_SEMICOLONS_DEFAULT, + }, + } + } +} + +impl WitPrinter { + /// Configure whether doc comments will be printed. + /// + /// Defaults to true. + pub fn emit_docs(&mut self, enabled: bool) -> &mut Self { + self.emit_docs = enabled; + self + } + + /// Print the given WIT package to a string. + pub fn print(&mut self, resolve: &Resolve, pkgid: PackageId) -> Result { + let pkg = &resolve.packages[pkgid]; + self.print_docs(&pkg.docs); + self.output.push_str("package "); + self.print_name(&pkg.name.namespace); + self.output.push_str(":"); + self.print_name(&pkg.name.name); + if let Some(version) = &pkg.name.version { + self.output.push_str(&format!("@{version}")); + } + self.print_semicolon(); + self.output.push_str("\n\n"); + for (name, id) in pkg.interfaces.iter() { + self.print_docs(&resolve.interfaces[*id].docs); + self.output.push_str("interface "); + self.print_name(name); + self.output.push_str(" {\n"); + self.print_interface(resolve, *id)?; + writeln!(&mut self.output, "}}\n")?; + } + + for (name, id) in pkg.worlds.iter() { + self.print_docs(&resolve.worlds[*id].docs); + self.output.push_str("world "); + self.print_name(name); + self.output.push_str(" {\n"); + self.print_world(resolve, *id)?; + writeln!(&mut self.output, "}}")?; + } + + Ok(std::mem::take(&mut self.output).into()) + } + + fn print_semicolon(&mut self) { + if self.print_semicolons { + self.output.push_str(";"); + } + } + + fn new_item(&mut self) { + if self.any_items { + self.output.push_str("\n"); + } + self.any_items = true; + } + + /// Print the given WebAssembly interface to a string. + fn print_interface(&mut self, resolve: &Resolve, id: InterfaceId) -> Result<()> { + let prev_items = mem::replace(&mut self.any_items, false); + let interface = &resolve.interfaces[id]; + + let mut resource_funcs = HashMap::new(); + let mut freestanding = Vec::new(); + for (name, func) in interface.functions.iter() { + if let Some(id) = resource_func(func) { + resource_funcs.entry(id).or_insert(Vec::new()).push(func); + } else { + freestanding.push((name, func)); + } + } + + self.print_types( + resolve, + TypeOwner::Interface(id), + interface + .types + .iter() + .map(|(name, id)| (name.as_str(), *id)), + &resource_funcs, + )?; + + for (name, func) in freestanding { + self.new_item(); + self.print_docs(&func.docs); + self.print_name(name); + self.output.push_str(": "); + self.print_function(resolve, func)?; + self.print_semicolon(); + self.output.push_str("\n"); + } + + self.any_items = prev_items; + + Ok(()) + } + + fn print_types<'a>( + &mut self, + resolve: &Resolve, + owner: TypeOwner, + types: impl Iterator, + resource_funcs: &HashMap>, + ) -> Result<()> { + // Partition types defined in this interface into either those imported + // from foreign interfaces or those defined locally. + let mut types_to_declare = Vec::new(); + let mut types_to_import: Vec<(_, Vec<_>)> = Vec::new(); + for (name, ty_id) in types { + let ty = &resolve.types[ty_id]; + if let TypeDefKind::Type(Type::Id(other)) = ty.kind { + let other = &resolve.types[other]; + match other.owner { + TypeOwner::None => {} + other_owner if owner != other_owner => { + let other_name = other + .name + .as_ref() + .ok_or_else(|| anyhow!("cannot import unnamed type"))?; + if let Some((owner, list)) = types_to_import.last_mut() { + if *owner == other_owner { + list.push((name, other_name)); + continue; + } + } + types_to_import.push((other_owner, vec![(name, other_name)])); + continue; + } + _ => {} + } + } + + types_to_declare.push(ty_id); + } + + // Generate a `use` statement for all imported types. + let my_pkg = match owner { + TypeOwner::Interface(id) => resolve.interfaces[id].package.unwrap(), + TypeOwner::World(id) => resolve.worlds[id].package.unwrap(), + TypeOwner::None => unreachable!(), + }; + for (owner, tys) in types_to_import { + self.any_items = true; + write!(&mut self.output, "use ")?; + let id = match owner { + TypeOwner::Interface(id) => id, + // it's only possible to import types from interfaces at + // this time. + _ => unreachable!(), + }; + self.print_path_to_interface(resolve, id, my_pkg)?; + write!(&mut self.output, ".{{")?; + for (i, (my_name, other_name)) in tys.into_iter().enumerate() { + if i > 0 { + write!(&mut self.output, ", ")?; + } + if my_name == other_name { + self.print_name(my_name); + } else { + self.print_name(other_name); + self.output.push_str(" as "); + self.print_name(my_name); + } + } + write!(&mut self.output, "}}")?; + self.print_semicolon(); + self.output.push_str("\n"); + } + + for id in types_to_declare { + self.new_item(); + self.print_docs(&resolve.types[id].docs); + match resolve.types[id].kind { + TypeDefKind::Resource => self.print_resource( + resolve, + id, + resource_funcs.get(&id).unwrap_or(&Vec::new()), + )?, + _ => self.declare_type(resolve, &Type::Id(id))?, + } + } + + Ok(()) + } + + fn print_resource(&mut self, resolve: &Resolve, id: TypeId, funcs: &[&Function]) -> Result<()> { + let ty = &resolve.types[id]; + self.output.push_str("resource "); + self.print_name(ty.name.as_ref().expect("resources must be named")); + if funcs.is_empty() { + self.print_semicolon(); + self.output.push_str("\n"); + return Ok(()); + } + self.output.push_str(" {\n"); + for func in funcs { + match &func.kind { + FunctionKind::Constructor(_) => { + self.print_docs(&func.docs); + } + FunctionKind::Method(_) => { + self.print_docs(&func.docs); + self.print_name(func.item_name()); + self.output.push_str(": "); + } + FunctionKind::Static(_) => { + self.print_docs(&func.docs); + self.print_name(func.item_name()); + self.output.push_str(": "); + self.output.push_str("static "); + } + FunctionKind::Freestanding => unreachable!(), + } + self.print_function(resolve, func)?; + self.print_semicolon(); + self.output.push_str("\n"); + } + self.output.push_str("}\n"); + + Ok(()) + } + + fn print_function(&mut self, resolve: &Resolve, func: &Function) -> Result<()> { + // Constructors are named slightly differently. + match &func.kind { + FunctionKind::Constructor(_) => self.output.push_str("constructor("), + _ => self.output.push_str("func("), + } + + // Methods don't print their `self` argument + let params_to_skip = match &func.kind { + FunctionKind::Method(_) => 1, + _ => 0, + }; + for (i, (name, ty)) in func.params.iter().skip(params_to_skip).enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.print_name(name); + self.output.push_str(": "); + self.print_type_name(resolve, ty)?; + } + self.output.push_str(")"); + + // constructors don't have their results printed + if let FunctionKind::Constructor(_) = func.kind { + return Ok(()); + } + + match &func.results { + Results::Named(rs) => match rs.len() { + 0 => (), + _ => { + self.output.push_str(" -> ("); + for (i, (name, ty)) in rs.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.print_name(name); + self.output.push_str(": "); + self.print_type_name(resolve, ty)?; + } + self.output.push_str(")"); + } + }, + Results::Anon(ty) => { + self.output.push_str(" -> "); + self.print_type_name(resolve, ty)?; + } + } + Ok(()) + } + + fn print_world(&mut self, resolve: &Resolve, id: WorldId) -> Result<()> { + let prev_items = mem::replace(&mut self.any_items, false); + let world = &resolve.worlds[id]; + let pkgid = world.package.unwrap(); + let mut types = Vec::new(); + let mut resource_funcs = HashMap::new(); + for (name, import) in world.imports.iter() { + match import { + WorldItem::Type(t) => match name { + WorldKey::Name(s) => types.push((s.as_str(), *t)), + WorldKey::Interface(_) => unreachable!(), + }, + _ => { + if let WorldItem::Function(f) = import { + if let Some(id) = resource_func(f) { + resource_funcs.entry(id).or_insert(Vec::new()).push(f); + continue; + } + } + self.print_world_item(resolve, name, import, pkgid, "import")?; + // Don't put a blank line between imports, but count + // imports as having printed something so if anything comes + // after them then a blank line is printed after imports. + self.any_items = true; + } + } + } + self.print_types( + resolve, + TypeOwner::World(id), + types.into_iter(), + &resource_funcs, + )?; + if !world.exports.is_empty() { + self.new_item(); + } + for (name, export) in world.exports.iter() { + self.print_world_item(resolve, name, export, pkgid, "export")?; + } + self.any_items = prev_items; + Ok(()) + } + + fn print_world_item( + &mut self, + resolve: &Resolve, + name: &WorldKey, + item: &WorldItem, + cur_pkg: PackageId, + desc: &str, + ) -> Result<()> { + // Print inline item docs + if matches!(name, WorldKey::Name(_)) { + self.print_docs(match item { + WorldItem::Interface(id) => &resolve.interfaces[*id].docs, + WorldItem::Function(f) => &f.docs, + // Types are handled separately + WorldItem::Type(_) => unreachable!(), + }); + } + + self.output.push_str(desc); + self.output.push_str(" "); + match name { + WorldKey::Name(name) => { + self.print_name(name); + self.output.push_str(": "); + match item { + WorldItem::Interface(id) => { + assert!(resolve.interfaces[*id].name.is_none()); + writeln!(self.output, "interface {{")?; + self.print_interface(resolve, *id)?; + writeln!(self.output, "}}")?; + } + WorldItem::Function(f) => { + self.print_function(resolve, f)?; + self.print_semicolon(); + self.output.push_str("\n"); + } + // Types are handled separately + WorldItem::Type(_) => unreachable!(), + } + } + WorldKey::Interface(id) => { + match item { + WorldItem::Interface(id2) => assert_eq!(id, id2), + _ => unreachable!(), + } + self.print_path_to_interface(resolve, *id, cur_pkg)?; + self.print_semicolon(); + self.output.push_str("\n"); + } + } + Ok(()) + } + + fn print_path_to_interface( + &mut self, + resolve: &Resolve, + interface: InterfaceId, + cur_pkg: PackageId, + ) -> Result<()> { + let iface = &resolve.interfaces[interface]; + if iface.package == Some(cur_pkg) { + self.print_name(iface.name.as_ref().unwrap()); + } else { + let pkg = &resolve.packages[iface.package.unwrap()].name; + self.print_name(&pkg.namespace); + self.output.push_str(":"); + self.print_name(&pkg.name); + self.output.push_str("/"); + self.print_name(iface.name.as_ref().unwrap()); + if let Some(version) = &pkg.version { + self.output.push_str(&format!("@{version}")); + } + } + Ok(()) + } + + fn print_type_name(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> { + match ty { + Type::Bool => self.output.push_str("bool"), + Type::U8 => self.output.push_str("u8"), + Type::U16 => self.output.push_str("u16"), + Type::U32 => self.output.push_str("u32"), + Type::U64 => self.output.push_str("u64"), + Type::S8 => self.output.push_str("s8"), + Type::S16 => self.output.push_str("s16"), + Type::S32 => self.output.push_str("s32"), + Type::S64 => self.output.push_str("s64"), + Type::Float32 => self.output.push_str("float32"), + Type::Float64 => self.output.push_str("float64"), + Type::Char => self.output.push_str("char"), + Type::String => self.output.push_str("string"), + + Type::Id(id) => { + let ty = &resolve.types[*id]; + if let Some(name) = &ty.name { + self.print_name(name); + return Ok(()); + } + + match &ty.kind { + TypeDefKind::Handle(h) => { + self.print_handle_type(resolve, h, false)?; + } + TypeDefKind::Resource => { + bail!("resolve has an unnamed resource type"); + } + TypeDefKind::Tuple(t) => { + self.print_tuple_type(resolve, t)?; + } + TypeDefKind::Option(t) => { + self.print_option_type(resolve, t)?; + } + TypeDefKind::Result(t) => { + self.print_result_type(resolve, t)?; + } + TypeDefKind::Record(_) => { + bail!("resolve has an unnamed record type"); + } + TypeDefKind::Flags(_) => { + bail!("resolve has unnamed flags type") + } + TypeDefKind::Enum(_) => { + bail!("resolve has unnamed enum type") + } + TypeDefKind::Variant(_) => { + bail!("resolve has unnamed variant type") + } + TypeDefKind::List(ty) => { + self.output.push_str("list<"); + self.print_type_name(resolve, ty)?; + self.output.push_str(">"); + } + TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?, + TypeDefKind::Future(_) => { + todo!("document has an unnamed future type") + } + TypeDefKind::Stream(_) => { + todo!("document has an unnamed stream type") + } + TypeDefKind::Unknown => unreachable!(), + } + } + } + + Ok(()) + } + + fn print_handle_type( + &mut self, + resolve: &Resolve, + handle: &Handle, + force_handle_type_printed: bool, + ) -> Result<()> { + match handle { + Handle::Own(ty) => { + let ty = &resolve.types[*ty]; + if force_handle_type_printed { + self.output.push_str("own<"); + } + self.print_name( + ty.name + .as_ref() + .ok_or_else(|| anyhow!("unnamed resource type"))?, + ); + if force_handle_type_printed { + self.output.push_str(">"); + } + } + + Handle::Borrow(ty) => { + self.output.push_str("borrow<"); + let ty = &resolve.types[*ty]; + self.print_name( + ty.name + .as_ref() + .ok_or_else(|| anyhow!("unnamed resource type"))?, + ); + self.output.push_str(">"); + } + } + + Ok(()) + } + + fn print_tuple_type(&mut self, resolve: &Resolve, tuple: &Tuple) -> Result<()> { + self.output.push_str("tuple<"); + for (i, ty) in tuple.types.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.print_type_name(resolve, ty)?; + } + self.output.push_str(">"); + + Ok(()) + } + + fn print_option_type(&mut self, resolve: &Resolve, payload: &Type) -> Result<()> { + self.output.push_str("option<"); + self.print_type_name(resolve, payload)?; + self.output.push_str(">"); + Ok(()) + } + + fn print_result_type(&mut self, resolve: &Resolve, result: &Result_) -> Result<()> { + match result { + Result_ { + ok: Some(ok), + err: Some(err), + } => { + self.output.push_str("result<"); + self.print_type_name(resolve, ok)?; + self.output.push_str(", "); + self.print_type_name(resolve, err)?; + self.output.push_str(">"); + } + Result_ { + ok: None, + err: Some(err), + } => { + self.output.push_str("result<_, "); + self.print_type_name(resolve, err)?; + self.output.push_str(">"); + } + Result_ { + ok: Some(ok), + err: None, + } => { + self.output.push_str("result<"); + self.print_type_name(resolve, ok)?; + self.output.push_str(">"); + } + Result_ { + ok: None, + err: None, + } => { + self.output.push_str("result"); + } + } + Ok(()) + } + + fn declare_type(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> { + match ty { + Type::Bool + | Type::U8 + | Type::U16 + | Type::U32 + | Type::U64 + | Type::S8 + | Type::S16 + | Type::S32 + | Type::S64 + | Type::Float32 + | Type::Float64 + | Type::Char + | Type::String => return Ok(()), + + Type::Id(id) => { + let ty = &resolve.types[*id]; + match &ty.kind { + TypeDefKind::Handle(h) => { + self.declare_handle(resolve, ty.name.as_deref(), h)? + } + TypeDefKind::Resource => panic!("resources should be processed separately"), + TypeDefKind::Record(r) => { + self.declare_record(resolve, ty.name.as_deref(), r)? + } + TypeDefKind::Tuple(t) => self.declare_tuple(resolve, ty.name.as_deref(), t)?, + TypeDefKind::Flags(f) => self.declare_flags(ty.name.as_deref(), f)?, + TypeDefKind::Variant(v) => { + self.declare_variant(resolve, ty.name.as_deref(), v)? + } + TypeDefKind::Option(t) => { + self.declare_option(resolve, ty.name.as_deref(), t)? + } + TypeDefKind::Result(r) => { + self.declare_result(resolve, ty.name.as_deref(), r)? + } + TypeDefKind::Enum(e) => self.declare_enum(ty.name.as_deref(), e)?, + TypeDefKind::List(inner) => { + self.declare_list(resolve, ty.name.as_deref(), inner)? + } + TypeDefKind::Type(inner) => match ty.name.as_deref() { + Some(name) => { + self.output.push_str("type "); + self.print_name(name); + self.output.push_str(" = "); + self.print_type_name(resolve, inner)?; + self.print_semicolon(); + self.output.push_str("\n"); + } + None => bail!("unnamed type in document"), + }, + TypeDefKind::Future(_) => todo!("declare future"), + TypeDefKind::Stream(_) => todo!("declare stream"), + TypeDefKind::Unknown => unreachable!(), + } + } + } + Ok(()) + } + + fn declare_handle( + &mut self, + resolve: &Resolve, + name: Option<&str>, + handle: &Handle, + ) -> Result<()> { + match name { + Some(name) => { + self.output.push_str("type "); + self.print_name(name); + self.output.push_str(" = "); + // Note that the `true` here forces owned handles to be printed + // as `own`. The purpose of this is because `type a = b`, if + // `b` is a resource, is encoded differently as `type a = + // own`. By forcing a handle to be printed here it's staying + // true to what's in the WIT document. + self.print_handle_type(resolve, handle, true)?; + self.print_semicolon(); + self.output.push_str("\n"); + + Ok(()) + } + None => bail!("document has unnamed handle type"), + } + } + + fn declare_record( + &mut self, + resolve: &Resolve, + name: Option<&str>, + record: &Record, + ) -> Result<()> { + match name { + Some(name) => { + self.output.push_str("record "); + self.print_name(name); + self.output.push_str(" {\n"); + for field in &record.fields { + self.print_docs(&field.docs); + self.print_name(&field.name); + self.output.push_str(": "); + self.print_type_name(resolve, &field.ty)?; + self.output.push_str(",\n"); + } + self.output.push_str("}\n"); + Ok(()) + } + None => bail!("document has unnamed record type"), + } + } + + fn declare_tuple( + &mut self, + resolve: &Resolve, + name: Option<&str>, + tuple: &Tuple, + ) -> Result<()> { + if let Some(name) = name { + self.output.push_str("type "); + self.print_name(name); + self.output.push_str(" = "); + self.print_tuple_type(resolve, tuple)?; + self.print_semicolon(); + self.output.push_str("\n"); + } + Ok(()) + } + + fn declare_flags(&mut self, name: Option<&str>, flags: &Flags) -> Result<()> { + match name { + Some(name) => { + self.output.push_str("flags "); + self.print_name(name); + self.output.push_str(" {\n"); + for flag in &flags.flags { + self.print_docs(&flag.docs); + self.print_name(&flag.name); + self.output.push_str(",\n"); + } + self.output.push_str("}\n"); + } + None => bail!("document has unnamed flags type"), + } + Ok(()) + } + + fn declare_variant( + &mut self, + resolve: &Resolve, + name: Option<&str>, + variant: &Variant, + ) -> Result<()> { + let name = match name { + Some(name) => name, + None => bail!("document has unnamed variant type"), + }; + self.output.push_str("variant "); + self.print_name(name); + self.output.push_str(" {\n"); + for case in &variant.cases { + self.print_docs(&case.docs); + self.print_name(&case.name); + if let Some(ty) = case.ty { + self.output.push_str("("); + self.print_type_name(resolve, &ty)?; + self.output.push_str(")"); + } + self.output.push_str(",\n"); + } + self.output.push_str("}\n"); + Ok(()) + } + + fn declare_option( + &mut self, + resolve: &Resolve, + name: Option<&str>, + payload: &Type, + ) -> Result<()> { + if let Some(name) = name { + self.output.push_str("type "); + self.print_name(name); + self.output.push_str(" = "); + self.print_option_type(resolve, payload)?; + self.print_semicolon(); + self.output.push_str("\n"); + } + Ok(()) + } + + fn declare_result( + &mut self, + resolve: &Resolve, + name: Option<&str>, + result: &Result_, + ) -> Result<()> { + if let Some(name) = name { + self.output.push_str("type "); + self.print_name(name); + self.output.push_str(" = "); + self.print_result_type(resolve, result)?; + self.print_semicolon(); + self.output.push_str("\n"); + } + Ok(()) + } + + fn declare_enum(&mut self, name: Option<&str>, enum_: &Enum) -> Result<()> { + let name = match name { + Some(name) => name, + None => bail!("document has unnamed enum type"), + }; + self.output.push_str("enum "); + self.print_name(name); + self.output.push_str(" {\n"); + for case in &enum_.cases { + self.print_docs(&case.docs); + self.print_name(&case.name); + self.output.push_str(",\n"); + } + self.output.push_str("}\n"); + Ok(()) + } + + fn declare_list(&mut self, resolve: &Resolve, name: Option<&str>, ty: &Type) -> Result<()> { + if let Some(name) = name { + self.output.push_str("type "); + self.print_name(name); + self.output.push_str(" = list<"); + self.print_type_name(resolve, ty)?; + self.output.push_str(">"); + self.print_semicolon(); + self.output.push_str("\n"); + return Ok(()); + } + + Ok(()) + } + + fn print_name(&mut self, name: &str) { + if is_keyword(name) { + self.output.push_str("%"); + } + self.output.push_str(name); + } + + fn print_docs(&mut self, docs: &Docs) { + if self.emit_docs { + if let Some(contents) = &docs.contents { + for line in contents.lines() { + self.output.push_str("/// "); + self.output.push_str(line); + self.output.push_str("\n"); + } + } + } + } +} + +fn resource_func(f: &Function) -> Option { + match f.kind { + FunctionKind::Freestanding => None, + FunctionKind::Method(id) | FunctionKind::Constructor(id) | FunctionKind::Static(id) => { + Some(id) + } + } +} + +fn is_keyword(name: &str) -> bool { + matches!( + name, + "use" + | "type" + | "func" + | "u8" + | "u16" + | "u32" + | "u64" + | "s8" + | "s16" + | "s32" + | "s64" + | "float32" + | "float64" + | "char" + | "resource" + | "record" + | "flags" + | "variant" + | "enum" + | "bool" + | "string" + | "option" + | "result" + | "future" + | "stream" + | "list" + | "own" + | "borrow" + | "_" + | "as" + | "from" + | "static" + | "interface" + | "tuple" + | "world" + | "import" + | "export" + | "package" + | "with" + | "include" + | "constructor" + ) +} + +/// Helper structure to help maintain an indentation level when printing source, +/// modeled after the support in `wit-bindgen-core`. +#[derive(Default)] +struct Output { + indent: usize, + output: String, +} + +impl Output { + fn push_str(&mut self, src: &str) { + let lines = src.lines().collect::>(); + for (i, line) in lines.iter().enumerate() { + let trimmed = line.trim(); + if trimmed.starts_with('}') && self.output.ends_with(" ") { + self.output.pop(); + self.output.pop(); + } + self.output.push_str(if lines.len() == 1 { + line + } else { + line.trim_start() + }); + if trimmed.ends_with('{') { + self.indent += 1; + } + if trimmed.starts_with('}') { + // Note that a `saturating_sub` is used here to prevent a panic + // here in the case of invalid code being generated in debug + // mode. It's typically easier to debug those issues through + // looking at the source code rather than getting a panic. + self.indent = self.indent.saturating_sub(1); + } + if i != lines.len() - 1 || src.ends_with('\n') { + // Trim trailing whitespace, if any, then push an indented + // newline + while let Some(c) = self.output.chars().next_back() { + if c.is_whitespace() && c != '\n' { + self.output.pop(); + } else { + break; + } + } + self.output.push('\n'); + for _ in 0..self.indent { + self.output.push_str(" "); + } + } + } + } +} + +impl Write for Output { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.push_str(s); + Ok(()) + } +} + +impl From for String { + fn from(output: Output) -> String { + output.output + } +} diff --git a/crates/wit-component/src/targets.rs b/crates/wit-component/src/targets.rs new file mode 100644 index 0000000000..cfc252f216 --- /dev/null +++ b/crates/wit-component/src/targets.rs @@ -0,0 +1,47 @@ +use crate::encoding::encode_world; +use anyhow::{Context, Result}; +use wasm_encoder::{ComponentBuilder, ComponentExportKind, ComponentTypeRef}; +use wasmparser::{Validator, WasmFeatures}; +use wit_parser::{Resolve, WorldId}; + +/// This function checks whether `component_to_test` correctly conforms to the world specified. +/// It does so by instantiating a generated component that imports a component instance with +/// the component type as described by the "target" world. +pub fn targets(resolve: &Resolve, world: WorldId, component_to_test: &[u8]) -> Result<()> { + let mut root_component = ComponentBuilder::default(); + + // (1) Embed the component to test. + let component_to_test_idx = root_component.component_raw(component_to_test); + + // (2) Encode the world to a component type and embed a new component which + // imports the encoded component type. + let test_component_idx = { + let component_ty = encode_world(resolve, world)?; + let mut component = ComponentBuilder::default(); + let component_ty_idx = component.type_component(&component_ty); + component.import( + &resolve.worlds[world].name, + ComponentTypeRef::Component(component_ty_idx), + ); + root_component.component(component) + }; + + // (3) Instantiate the component from (2) with the component to test from (1). + let args: Vec<(String, ComponentExportKind, u32)> = vec![( + resolve.worlds[world].name.clone(), + ComponentExportKind::Component, + component_to_test_idx, + )]; + root_component.instantiate(test_component_idx, args); + + let bytes = root_component.finish(); + + Validator::new_with_features(WasmFeatures { + component_model: true, + ..Default::default() + }) + .validate_all(&bytes) + .context("failed to validate encoded bytes")?; + + Ok(()) +} diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs new file mode 100644 index 0000000000..1262add2e6 --- /dev/null +++ b/crates/wit-component/src/validation.rs @@ -0,0 +1,833 @@ +use crate::metadata::{Bindgen, ModuleMetadata}; +use anyhow::{bail, Context, Result}; +use indexmap::{map::Entry, IndexMap, IndexSet}; +use std::mem; +use wasmparser::names::{KebabName, KebabNameKind}; +use wasmparser::{ + types::Types, ComponentExternName, Encoding, ExternalKind, FuncType, Parser, Payload, TypeRef, + ValType, ValidPayload, Validator, +}; +use wit_parser::{ + abi::{AbiVariant, WasmSignature, WasmType}, + Function, InterfaceId, PackageName, Resolve, TypeDefKind, TypeId, WorldId, WorldItem, WorldKey, +}; + +fn is_canonical_function(name: &str) -> bool { + name.starts_with("cabi_") || name.starts_with("canonical_abi_") +} + +fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType { + fn from_wasm_type(ty: &WasmType) -> ValType { + match ty { + WasmType::I32 => ValType::I32, + WasmType::I64 => ValType::I64, + WasmType::F32 => ValType::F32, + WasmType::F64 => ValType::F64, + } + } + + FuncType::new( + signature.params.iter().map(from_wasm_type), + signature.results.iter().map(from_wasm_type), + ) +} + +pub const MAIN_MODULE_IMPORT_NAME: &str = "__main_module__"; + +/// The module name used when a top-level function in a world is imported into a +/// core wasm module. Note that this is not a valid WIT identifier to avoid +/// clashes with valid WIT interfaces. This is also not empty because LLVM +/// interprets an empty module import string as "not specified" which means it +/// turns into `env`. +pub const BARE_FUNC_MODULE_NAME: &str = "$root"; + +pub const RESOURCE_DROP: &str = "[resource-drop]"; +pub const RESOURCE_REP: &str = "[resource-rep]"; +pub const RESOURCE_NEW: &str = "[resource-new]"; + +pub const POST_RETURN_PREFIX: &str = "cabi_post_"; + +/// Metadata about a validated module and what was found internally. +/// +/// All imports to the module are described by the union of `required_imports` +/// and `adapters_required`. +/// +/// This structure is created by the `validate_module` function. +pub struct ValidatedModule<'a> { + /// The required imports into this module which are to be satisfied by + /// imported component model instances. + /// + /// The key of this map is the name of the interface that the module imports + /// from and the value is the set of functions required from that interface. + /// This is used to generate an appropriate instance import in the generated + /// component which imports only the set of required functions. + pub required_imports: IndexMap<&'a str, RequiredImports>, + + /// This is the set of imports into the module which were not satisfied by + /// imported interfaces but are required to be satisfied by adapter modules. + /// + /// The key of this map is the name of the adapter that was imported into + /// the module and the value is a further map from function to function type + /// as required by this module. This map is used to shrink adapter modules + /// to the precise size required for this module by ensuring it doesn't + /// export (and subsequently import) extraneous functions. + pub adapters_required: IndexMap<&'a str, IndexMap<&'a str, FuncType>>, + + /// Resource-related functions required and imported which work over + /// exported resources from the final component. + /// + /// Note that this is disjoint from `required_imports` which handles + /// imported resources and this is only for exported resources. Exported + /// resources still require intrinsics to be imported into the core module + /// itself. + pub required_resource_funcs: IndexMap>, + + /// Whether or not this module exported a linear memory. + pub has_memory: bool, + + /// Whether or not this module exported a `cabi_realloc` function. + pub realloc: Option<&'a str>, + + /// Whether or not this module exported a `cabi_realloc_adapter` function. + pub adapter_realloc: Option<&'a str>, + + /// The original metadata specified for this module. + pub metadata: &'a ModuleMetadata, + + /// Post-return functions annotated with `cabi_post_*` in their function + /// name. + pub post_returns: IndexSet, +} + +#[derive(Default)] +pub struct RequiredImports { + pub funcs: IndexSet, + pub resources: IndexSet, +} + +pub struct ResourceInfo { + pub drop_import: Option, + pub new_import: Option, + pub rep_import: Option, + pub dtor_export: Option, + pub id: TypeId, +} + +/// This function validates the following: +/// +/// * The `bytes` represent a valid core WebAssembly module. +/// * The module's imports are all satisfied by the given `imports` interfaces +/// or the `adapters` set. +/// * The given default and exported interfaces are satisfied by the module's +/// exports. +/// +/// The `ValidatedModule` return value contains the metadata which describes the +/// input module on success. This is then further used to generate a component +/// for this module. +pub fn validate_module<'a>( + bytes: &'a [u8], + metadata: &'a Bindgen, + exports: &IndexSet, + adapters: &IndexSet<&str>, +) -> Result> { + let mut validator = Validator::new(); + let mut types = None; + let mut import_funcs = IndexMap::new(); + let mut export_funcs = IndexMap::new(); + let mut ret = ValidatedModule { + required_imports: Default::default(), + adapters_required: Default::default(), + has_memory: false, + realloc: None, + adapter_realloc: None, + metadata: &metadata.metadata, + required_resource_funcs: Default::default(), + post_returns: Default::default(), + }; + + for payload in Parser::new(0).parse_all(bytes) { + let payload = payload?; + if let ValidPayload::End(tys) = validator.payload(&payload)? { + types = Some(tys); + break; + } + + match payload { + Payload::Version { encoding, .. } if encoding != Encoding::Module => { + bail!("data is not a WebAssembly module"); + } + Payload::ImportSection(s) => { + for import in s { + let import = import?; + match import.ty { + TypeRef::Func(ty) => { + let map = match import_funcs.entry(import.module) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => e.insert(IndexMap::new()), + }; + + assert!(map.insert(import.name, ty).is_none()); + } + _ => bail!("module is only allowed to import functions"), + } + } + } + Payload::ExportSection(s) => { + for export in s { + let export = export?; + + match export.kind { + ExternalKind::Func => { + if is_canonical_function(export.name) { + // TODO: validate that the cabi_realloc + // function is [i32, i32, i32, i32] -> [i32] + if export.name == "cabi_realloc" + || export.name == "canonical_abi_realloc" + { + ret.realloc = Some(export.name); + } + if export.name == "cabi_realloc_adapter" { + ret.adapter_realloc = Some(export.name); + } + } + + assert!(export_funcs.insert(export.name, export.index).is_none()) + } + ExternalKind::Memory => { + if export.name == "memory" { + ret.has_memory = true; + } + } + _ => continue, + } + } + } + _ => continue, + } + } + + let types = types.unwrap(); + let world = &metadata.resolve.worlds[metadata.world]; + let mut exported_resource_funcs = Vec::new(); + + for (name, funcs) in &import_funcs { + // An empty module name is indicative of the top-level import namespace, + // so look for top-level functions here. + if *name == BARE_FUNC_MODULE_NAME { + let required = + validate_imports_top_level(&metadata.resolve, metadata.world, funcs, &types)?; + let prev = ret.required_imports.insert(BARE_FUNC_MODULE_NAME, required); + assert!(prev.is_none()); + continue; + } + + if let Some(interface_name) = name.strip_prefix("[export]") { + exported_resource_funcs.push((name, interface_name, &import_funcs[name])); + continue; + } + + match world.imports.get(&world_key(&metadata.resolve, name)) { + Some(WorldItem::Interface(interface)) => { + let required = + validate_imported_interface(&metadata.resolve, *interface, name, funcs, &types) + .with_context(|| format!("failed to validate import interface `{name}`"))?; + let prev = ret.required_imports.insert(name, required); + assert!(prev.is_none()); + } + None if adapters.contains(name) => { + let map = ret.adapters_required.entry(name).or_default(); + for (func, ty) in funcs { + let ty = types[types.core_type_at(*ty)].unwrap_func(); + map.insert(func, ty.clone()); + } + } + Some(WorldItem::Function(_) | WorldItem::Type(_)) => { + bail!("import `{}` is not an interface", name) + } + None => bail!("module requires an import interface named `{name}`"), + } + } + + for name in exports { + validate_exported_item( + &metadata.resolve, + &world.exports[name], + &metadata.resolve.name_world_key(name), + &export_funcs, + &types, + &mut ret.post_returns, + &mut ret.required_resource_funcs, + )?; + } + + for (name, interface_name, funcs) in exported_resource_funcs { + let world_key = world_key(&metadata.resolve, interface_name); + match world.exports.get(&world_key) { + Some(WorldItem::Interface(i)) => { + validate_exported_interface_resource_imports( + &metadata.resolve, + *i, + name, + funcs, + &types, + &mut ret.required_resource_funcs, + )?; + } + _ => bail!("import from `{name}` does not correspond to exported interface"), + } + } + + Ok(ret) +} + +fn validate_exported_interface_resource_imports<'a>( + resolve: &Resolve, + interface: InterfaceId, + import_module: &str, + funcs: &IndexMap<&'a str, u32>, + types: &Types, + required_resource_funcs: &mut IndexMap>, +) -> Result<()> { + let is_resource = |name: &str| match resolve.interfaces[interface].types.get(name) { + Some(ty) => matches!(resolve.types[*ty].kind, TypeDefKind::Resource), + None => false, + }; + for (func_name, ty) in funcs { + if valid_exported_resource_func(func_name, *ty, types, is_resource)?.is_none() { + bail!("import of `{func_name}` is not a valid resource function"); + } + let info = required_resource_funcs.get_mut(import_module).unwrap(); + if let Some(resource_name) = func_name.strip_prefix(RESOURCE_DROP) { + info[resource_name].drop_import = Some(func_name.to_string()); + continue; + } + if let Some(resource_name) = func_name.strip_prefix(RESOURCE_NEW) { + info[resource_name].new_import = Some(func_name.to_string()); + continue; + } + if let Some(resource_name) = func_name.strip_prefix(RESOURCE_REP) { + info[resource_name].rep_import = Some(func_name.to_string()); + continue; + } + + unreachable!(); + } + Ok(()) +} + +/// Validation information from an "adapter module" which is distinct from a +/// "main module" validated above. +/// +/// This is created by the `validate_adapter_module` function. +pub struct ValidatedAdapter<'a> { + /// If specified this is the list of required imports from the original set + /// of possible imports along with the set of functions required from each + /// imported interface. + pub required_imports: IndexMap, + + /// Resource-related functions required and imported which work over + /// exported resources from the final component. + /// + /// Note that this is disjoint from `required_imports` which handles + /// imported resources and this is only for exported resources. Exported + /// resources still require intrinsics to be imported into the core module + /// itself. + pub required_resource_funcs: IndexMap>, + + /// This is the module and field name of the memory import, if one is + /// specified. + /// + /// Due to LLVM codegen this is typically `env::memory` as a totally separate + /// import from the `required_import` above. + pub needs_memory: Option<(String, String)>, + + /// Set of names required to be exported from the main module which are + /// imported by this adapter through the `__main_module__` synthetic export. + /// This is how the WASI adapter imports `_start`, for example. + pub needs_core_exports: IndexSet, + + /// Name of the exported function to use for the realloc canonical option + /// for lowering imports. + pub import_realloc: Option, + + /// Same as `import_realloc`, but for exported interfaces. + pub export_realloc: Option, + + /// Metadata about the original adapter module. + pub metadata: &'a ModuleMetadata, + + /// Post-return functions annotated with `cabi_post_*` in their function + /// name. + pub post_returns: IndexSet, +} + +/// This function will validate the `bytes` provided as a wasm adapter module. +/// Notably this will validate the wasm module itself in addition to ensuring +/// that it has the "shape" of an adapter module. Current constraints are: +/// +/// * The adapter module can import only one memory +/// * The adapter module can only import from the name of `interface` specified, +/// and all function imports must match the `required` types which correspond +/// to the lowered types of the functions in `interface`. +/// +/// The wasm module passed into this function is the output of the GC pass of an +/// adapter module's original source. This means that the adapter module is +/// already minimized and this is a double-check that the minimization pass +/// didn't accidentally break the wasm module. +/// +/// If `is_library` is true, we waive some of the constraints described above, +/// allowing the module to import tables and globals, as well as import +/// functions at the world level, not just at the interface level. +pub fn validate_adapter_module<'a>( + bytes: &[u8], + resolve: &'a Resolve, + world: WorldId, + metadata: &'a ModuleMetadata, + required_by_import: Option<&IndexMap<&str, FuncType>>, + exports: &IndexSet, + is_library: bool, +) -> Result> { + let mut validator = Validator::new(); + let mut import_funcs = IndexMap::new(); + let mut export_funcs = IndexMap::new(); + let mut types = None; + let mut funcs = Vec::new(); + let mut ret = ValidatedAdapter { + required_imports: Default::default(), + required_resource_funcs: Default::default(), + needs_memory: None, + needs_core_exports: Default::default(), + import_realloc: None, + export_realloc: None, + metadata, + post_returns: Default::default(), + }; + + for payload in Parser::new(0).parse_all(bytes) { + let payload = payload?; + match validator.payload(&payload)? { + ValidPayload::End(tys) => { + types = Some(tys); + break; + } + ValidPayload::Func(validator, body) => { + funcs.push((validator, body)); + } + _ => {} + } + + match payload { + Payload::Version { encoding, .. } if encoding != Encoding::Module => { + bail!("data is not a WebAssembly module"); + } + + Payload::ImportSection(s) => { + for import in s { + let import = import?; + match import.ty { + TypeRef::Func(ty) => { + let map = match import_funcs.entry(import.module) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => e.insert(IndexMap::new()), + }; + + assert!(map.insert(import.name, ty).is_none()); + } + + // A memory is allowed to be imported into the adapter + // module so that's skipped here + TypeRef::Memory(_) => { + ret.needs_memory = + Some((import.module.to_string(), import.name.to_string())); + } + + TypeRef::Global(_) | TypeRef::Table(_) if is_library => (), + + _ => { + bail!("adapter module is only allowed to import functions and memories") + } + } + } + } + Payload::ExportSection(s) => { + for export in s { + let export = export?; + + match export.kind { + ExternalKind::Func => { + export_funcs.insert(export.name, export.index); + if export.name == "cabi_export_realloc" { + ret.export_realloc = Some(export.name.to_string()); + } + if export.name == "cabi_import_realloc" { + ret.import_realloc = Some(export.name.to_string()); + } + } + _ => continue, + } + } + } + _ => continue, + } + } + + let mut resources = Default::default(); + for (validator, body) in funcs { + let mut validator = validator.into_validator(resources); + validator.validate(&body)?; + resources = validator.into_allocations(); + } + + let types = types.unwrap(); + let mut exported_resource_funcs = Vec::new(); + for (name, funcs) in &import_funcs { + if *name == MAIN_MODULE_IMPORT_NAME { + ret.needs_core_exports + .extend(funcs.iter().map(|(name, _ty)| name.to_string())); + continue; + } + + // An empty module name is indicative of the top-level import namespace, + // so look for top-level functions here. + if *name == BARE_FUNC_MODULE_NAME { + let required = validate_imports_top_level(resolve, world, funcs, &types)?; + ret.required_imports + .insert(BARE_FUNC_MODULE_NAME.to_string(), required); + continue; + } + + if let Some(interface_name) = name.strip_prefix("[export]") { + exported_resource_funcs.push((name, interface_name, &import_funcs[name])); + continue; + } + + match resolve.worlds[world].imports.get(&world_key(resolve, name)) { + Some(WorldItem::Interface(interface)) => { + let required = + validate_imported_interface(resolve, *interface, name, funcs, &types) + .with_context(|| format!("failed to validate import interface `{name}`"))?; + let prev = ret.required_imports.insert(name.to_string(), required); + assert!(prev.is_none()); + } + None | Some(WorldItem::Function(_) | WorldItem::Type(_)) => { + if !is_library { + bail!( + "adapter module requires an import interface named `{}`", + name + ) + } + } + } + } + + if let Some(required) = required_by_import { + for (name, ty) in required { + let idx = match export_funcs.get(name) { + Some(idx) => *idx, + None => bail!("adapter module did not export `{name}`"), + }; + let id = types.function_at(idx); + let actual = types[id].unwrap_func(); + validate_func_sig(name, ty, actual)?; + } + } + + let world = &resolve.worlds[world]; + + for name in exports { + validate_exported_item( + resolve, + &world.exports[name], + &resolve.name_world_key(name), + &export_funcs, + &types, + &mut ret.post_returns, + &mut ret.required_resource_funcs, + )?; + } + + for (name, interface_name, funcs) in exported_resource_funcs { + let world_key = world_key(resolve, interface_name); + match world.exports.get(&world_key) { + Some(WorldItem::Interface(i)) => { + validate_exported_interface_resource_imports( + resolve, + *i, + name, + funcs, + &types, + &mut ret.required_resource_funcs, + )?; + } + _ => bail!("import from `{name}` does not correspond to exported interface"), + } + } + + Ok(ret) +} + +fn world_key(resolve: &Resolve, name: &str) -> WorldKey { + let name = if name.contains('/') { + ComponentExternName::Interface(name) + } else { + ComponentExternName::Kebab(name) + }; + let kebab_name = KebabName::new(name, 0); + let (pkgname, interface) = match kebab_name.as_ref().map(|k| k.kind()) { + Ok(KebabNameKind::Id { + namespace, + package, + version, + interface, + }) => ( + PackageName { + namespace: namespace.as_str().to_string(), + name: package.as_str().to_string(), + version, + }, + interface.as_str(), + ), + _ => return WorldKey::Name(name.as_str().to_string()), + }; + match resolve + .package_names + .get(&pkgname) + .and_then(|p| resolve.packages[*p].interfaces.get(interface)) + { + Some(id) => WorldKey::Interface(*id), + None => WorldKey::Name(name.as_str().to_string()), + } +} + +fn validate_imports_top_level( + resolve: &Resolve, + world: WorldId, + funcs: &IndexMap<&str, u32>, + types: &Types, +) -> Result { + let is_resource = |name: &str| match resolve.worlds[world] + .imports + .get(&WorldKey::Name(name.to_string())) + { + Some(WorldItem::Type(r)) => { + matches!(resolve.types[*r].kind, TypeDefKind::Resource) + } + _ => false, + }; + let mut required = RequiredImports::default(); + for (name, ty) in funcs { + match resolve.worlds[world].imports.get(&world_key(resolve, name)) { + Some(WorldItem::Function(func)) => { + let ty = types[types.core_type_at(*ty)].unwrap_func(); + validate_func(resolve, ty, func, AbiVariant::GuestImport)?; + } + Some(_) => bail!("expected world top-level import `{name}` to be a function"), + None => match valid_imported_resource_func(name, *ty, types, is_resource)? { + Some(name) => { + required.resources.insert(name.to_string()); + } + None => bail!("no top-level imported function `{name}` specified"), + }, + } + required.funcs.insert(name.to_string()); + } + Ok(required) +} + +fn valid_imported_resource_func<'a>( + func_name: &'a str, + ty: u32, + types: &Types, + is_resource: impl Fn(&str) -> bool, +) -> Result> { + if let Some(resource_name) = func_name.strip_prefix(RESOURCE_DROP) { + if is_resource(resource_name) { + let ty = types[types.core_type_at(ty)].unwrap_func(); + let expected = FuncType::new([ValType::I32], []); + validate_func_sig(func_name, &expected, ty)?; + return Ok(Some(resource_name)); + } + } + Ok(None) +} + +fn valid_exported_resource_func<'a>( + func_name: &'a str, + ty: u32, + types: &Types, + is_resource: impl Fn(&str) -> bool, +) -> Result> { + if let Some(name) = valid_imported_resource_func(func_name, ty, types, &is_resource)? { + return Ok(Some(name)); + } + if let Some(resource_name) = func_name + .strip_prefix(RESOURCE_REP) + .or_else(|| func_name.strip_prefix(RESOURCE_NEW)) + { + if is_resource(resource_name) { + let ty = types[types.core_type_at(ty)].unwrap_func(); + let expected = FuncType::new([ValType::I32], [ValType::I32]); + validate_func_sig(func_name, &expected, ty)?; + return Ok(Some(resource_name)); + } + } + Ok(None) +} + +fn validate_imported_interface( + resolve: &Resolve, + interface: InterfaceId, + name: &str, + imports: &IndexMap<&str, u32>, + types: &Types, +) -> Result { + let mut required = RequiredImports::default(); + let is_resource = |name: &str| { + let ty = match resolve.interfaces[interface].types.get(name) { + Some(ty) => *ty, + None => return false, + }; + matches!(resolve.types[ty].kind, TypeDefKind::Resource) + }; + for (func_name, ty) in imports { + match resolve.interfaces[interface].functions.get(*func_name) { + Some(f) => { + let ty = types[types.core_type_at(*ty)].unwrap_func(); + validate_func(resolve, ty, f, AbiVariant::GuestImport)?; + } + None => match valid_imported_resource_func(func_name, *ty, types, is_resource)? { + Some(name) => { + required.resources.insert(name.to_string()); + } + None => bail!( + "import interface `{name}` is missing function \ + `{func_name}` that is required by the module", + ), + }, + } + required.funcs.insert(func_name.to_string()); + } + + Ok(required) +} + +fn validate_func( + resolve: &Resolve, + ty: &wasmparser::FuncType, + func: &Function, + abi: AbiVariant, +) -> Result<()> { + validate_func_sig( + &func.name, + &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)), + ty, + ) +} + +fn validate_post_return( + resolve: &Resolve, + ty: &wasmparser::FuncType, + func: &Function, +) -> Result<()> { + // The expected signature of a post-return function is to take all the + // parameters that are returned by the guest function and then return no + // results. Model this by calculating the signature of `func` and then + // moving its results into the parameters list while emptying out the + // results. + let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func); + sig.params = mem::take(&mut sig.results); + validate_func_sig( + &format!("{} post-return", func.name), + &wasm_sig_to_func_type(sig), + ty, + ) +} + +fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> { + if ty != expected { + bail!( + "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`", + name, + expected.params(), + expected.results(), + ty.params(), + ty.results() + ); + } + + Ok(()) +} + +fn validate_exported_item<'a>( + resolve: &'a Resolve, + item: &'a WorldItem, + export_name: &str, + exports: &IndexMap<&str, u32>, + types: &Types, + post_returns: &mut IndexSet, + required_resource_funcs: &mut IndexMap>, +) -> Result<()> { + let mut validate = |func: &Function, name: Option<&str>| { + let expected_export_name = func.core_export_name(name); + let func_index = match exports.get(expected_export_name.as_ref()) { + Some(func_index) => func_index, + None => bail!( + "module does not export required function `{}`", + expected_export_name + ), + }; + let id = types.function_at(*func_index); + let ty = types[id].unwrap_func(); + validate_func(resolve, ty, func, AbiVariant::GuestExport)?; + + let post_return = format!("{POST_RETURN_PREFIX}{expected_export_name}"); + if let Some(index) = exports.get(&post_return[..]) { + let ok = post_returns.insert(post_return); + assert!(ok); + let id = types.function_at(*index); + let ty = types[id].unwrap_func(); + validate_post_return(resolve, ty, func)?; + } + Ok(()) + }; + match item { + WorldItem::Function(func) => validate(func, None)?, + WorldItem::Interface(interface) => { + let interface = &resolve.interfaces[*interface]; + for (_, f) in interface.functions.iter() { + validate(f, Some(export_name)).with_context(|| { + format!("failed to validate exported interface `{export_name}`") + })?; + } + let mut map = IndexMap::new(); + for (name, id) in interface.types.iter() { + if !matches!(resolve.types[*id].kind, TypeDefKind::Resource) { + continue; + } + let mut info = ResourceInfo { + id: *id, + dtor_export: None, + drop_import: None, + rep_import: None, + new_import: None, + }; + let dtor = format!("{export_name}#[dtor]{name}"); + if let Some((_, name, func_idx)) = exports.get_full(dtor.as_str()) { + let id = types.function_at(*func_idx); + let ty = types[id].unwrap_func(); + let expected = FuncType::new([ValType::I32], []); + validate_func_sig(name, &expected, ty)?; + info.dtor_export = Some(name.to_string()); + } + let prev = map.insert(name.to_string(), info); + assert!(prev.is_none()); + } + let prev = required_resource_funcs.insert(format!("[export]{export_name}"), map); + assert!(prev.is_none()); + } + // not required to have anything exported in the core wasm module + WorldItem::Type(_) => {} + } + + Ok(()) +} diff --git a/crates/wit-component/tests/.gitignore b/crates/wit-component/tests/.gitignore new file mode 100644 index 0000000000..9365962f41 --- /dev/null +++ b/crates/wit-component/tests/.gitignore @@ -0,0 +1,2 @@ +!*.wasm +!*.wat diff --git a/crates/wit-component/tests/components.rs b/crates/wit-component/tests/components.rs new file mode 100644 index 0000000000..4bf1f7ad15 --- /dev/null +++ b/crates/wit-component/tests/components.rs @@ -0,0 +1,237 @@ +use anyhow::{bail, Context, Error, Result}; +use pretty_assertions::assert_eq; +use std::{borrow::Cow, fs, path::Path}; +use wasm_encoder::{Encode, Section}; +use wit_component::{ComponentEncoder, DecodedWasm, Linker, StringEncoding, WitPrinter}; +use wit_parser::{PackageId, Resolve, UnresolvedPackage}; + +/// Tests the encoding of components. +/// +/// This test looks in the `components/` directory for test cases. +/// +/// The expected input files for a test case are: +/// +/// * [required] `module.wat` *or* some combination of `lib-$name.wat` and +/// `dlopen-lib-$name.wat` - contains the core module definition(s) to be +/// encoded as a component. If one or more `lib-$name.wat` and/or +/// `dlopen-lib-$name.wat` files exist, they will be linked using `Linker` +/// such that the `lib-` ones are not `dlopen`-able but the `dlopen-lib-` ones +/// are. +/// * [required] `module.wit` *or* `lib-$name.wat` and `dlopen-lib-$name.wat` +/// corresponding to the WAT files above - WIT package(s) describing the +/// interfaces of the `module.wat` or `lib-$name.wat` and +/// `dlopen-lib-$name.wat` files. Must have a `default world` +/// * [optional] `adapt-$name.wat` - optional adapter for the module name +/// `$name`, can be specified for multiple `$name`s +/// * [optional] `adapt-$name.wit` - required for each `*.wat` adapter to +/// describe imports/exports of the adapter. +/// * [optional] `stub-missing-functions` - if linking libraries and this file +/// exists, `Linker::stub_missing_functions` will be set to `true`. The +/// contents of the file are ignored. +/// +/// And the output files are one of the following: +/// +/// * `component.wat` - the expected encoded component in text format if the +/// encoding is expected to succeed. +/// * `component.wit` - if `component.wat` exists this is the inferred interface +/// of the component. +/// * `error.txt` - the expected error message if the encoding is expected to +/// fail. +/// +/// The test encodes a component based on the input files. If the encoding +/// succeeds, it expects the output to match `component.wat`. If the encoding +/// fails, it expects the output to match `error.txt`. +/// +/// Run the test with the environment variable `BLESS` set to update +/// either `component.wat` or `error.txt` depending on the outcome of the encoding. +#[test] +fn component_encoding_via_flags() -> Result<()> { + drop(env_logger::try_init()); + + for entry in fs::read_dir("tests/components")? { + let path = entry?.path(); + if !path.is_dir() { + continue; + } + + let test_case = path.file_stem().unwrap().to_str().unwrap(); + println!("testing {test_case}"); + + let mut resolve = Resolve::default(); + let (pkg, _) = resolve.push_dir(&path)?; + + let module_path = path.join("module.wat"); + let mut adapters = glob::glob(path.join("adapt-*.wat").to_str().unwrap())?; + let result = if module_path.is_file() { + let module = read_core_module(&module_path, &resolve, pkg)?; + adapters + .try_fold( + ComponentEncoder::default().module(&module)?.validate(true), + |encoder, path| { + let (name, wasm) = read_name_and_module("adapt-", &path?, &resolve, pkg)?; + Ok::<_, Error>(encoder.adapter(&name, &wasm)?) + }, + )? + .encode() + } else { + let mut libs = glob::glob(path.join("lib-*.wat").to_str().unwrap())? + .map(|path| ("lib-", path, false)) + .chain( + glob::glob(path.join("dlopen-lib-*.wat").to_str().unwrap())? + .map(|path| ("dlopen-lib-", path, true)), + ); + + let mut linker = Linker::default().validate(true); + + if path.join("stub-missing-functions").is_file() { + linker = linker.stub_missing_functions(true); + } + + let linker = libs.try_fold(linker, |linker, (prefix, path, dl_openable)| { + let (name, wasm) = read_name_and_module(prefix, &path?, &resolve, pkg)?; + Ok::<_, Error>(linker.library(&name, &wasm, dl_openable)?) + })?; + + adapters + .try_fold(linker, |linker, path| { + let (name, wasm) = read_name_and_module("adapt-", &path?, &resolve, pkg)?; + Ok::<_, Error>(linker.adapter(&name, &wasm)?) + })? + .encode() + }; + let component_path = path.join("component.wat"); + let component_wit_path = path.join("component.wit.print"); + let error_path = path.join("error.txt"); + + let bytes = match result { + Ok(bytes) => { + if test_case.starts_with("error-") { + bail!("expected an error but got success"); + } + bytes + } + Err(err) => { + if !test_case.starts_with("error-") { + return Err(err); + } + assert_output(&format!("{err:?}"), &error_path)?; + continue; + } + }; + + let wat = wasmprinter::print_bytes(&bytes)?; + assert_output(&wat, &component_path)?; + let (pkg, resolve) = match wit_component::decode(&bytes)? { + DecodedWasm::WitPackage(..) => unreachable!(), + DecodedWasm::Component(resolve, world) => { + (resolve.worlds[world].package.unwrap(), resolve) + } + }; + let wit = WitPrinter::default().print(&resolve, pkg)?; + assert_output(&wit, &component_wit_path)?; + + UnresolvedPackage::parse(&component_wit_path, &wit) + .context("failed to parse printed WIT")?; + + // Check that the producer data got piped through properly + let metadata = wasm_metadata::Metadata::from_binary(&bytes)?; + match metadata { + // Depends on the ComponentEncoder always putting the first module as the 0th child: + wasm_metadata::Metadata::Component { children, .. } => match children[0].as_ref() { + wasm_metadata::Metadata::Module { producers, .. } => { + let producers = producers.as_ref().expect("child module has producers"); + let processed_by = producers + .get("processed-by") + .expect("child has processed-by section"); + assert_eq!( + processed_by + .get("wit-component") + .expect("wit-component producer present"), + env!("CARGO_PKG_VERSION") + ); + if module_path.is_file() { + assert_eq!( + processed_by + .get("my-fake-bindgen") + .expect("added bindgen field present"), + "123.45" + ); + } else { + // Otherwise, we used `Linker`, which synthesizes the + // "main" module and thus won't have `my-fake-bindgen` + } + } + _ => panic!("expected child to be a module"), + }, + _ => panic!("expected top level metadata of component"), + } + } + + Ok(()) +} + +fn read_name_and_module( + prefix: &str, + path: &Path, + resolve: &Resolve, + pkg: PackageId, +) -> Result<(String, Vec)> { + let wasm = read_core_module(path, resolve, pkg)?; + let stem = path.file_stem().unwrap().to_str().unwrap(); + let name = stem.trim_start_matches(prefix).to_owned(); + Ok((name, wasm)) +} + +/// Parses the core wasm module at `path`, expected as a `*.wat` file. +/// +/// The `resolve` and `pkg` are the parsed WIT package from this test's +/// directory and the `path`'s filename is used to find a WIT document of the +/// corresponding name which should have a world that `path` ascribes to. +fn read_core_module(path: &Path, resolve: &Resolve, pkg: PackageId) -> Result> { + let mut wasm = wat::parse_file(path)?; + let name = path.file_stem().and_then(|s| s.to_str()).unwrap(); + let world = resolve + .select_world(pkg, Some(name)) + .context("failed to select a world")?; + + // Add this producer data to the wit-component metadata so we can make sure it gets through the + // translation: + let mut producers = wasm_metadata::Producers::empty(); + producers.add("processed-by", "my-fake-bindgen", "123.45"); + + let encoded = + wit_component::metadata::encode(resolve, world, StringEncoding::UTF8, Some(&producers))?; + + let section = wasm_encoder::CustomSection { + name: "component-type".into(), + data: Cow::Borrowed(&encoded), + }; + wasm.push(section.id()); + section.encode(&mut wasm); + Ok(wasm) +} + +fn assert_output(contents: &str, path: &Path) -> Result<()> { + let contents = contents.replace("\r\n", "\n").replace( + concat!("\"", env!("CARGO_PKG_VERSION"), "\""), + "\"$CARGO_PKG_VERSION\"", + ); + if std::env::var_os("BLESS").is_some() { + fs::write(path, contents)?; + } else { + match fs::read_to_string(path) { + Ok(expected) => { + assert_eq!( + expected.replace("\r\n", "\n").trim(), + contents.trim(), + "failed baseline comparison ({})", + path.display(), + ); + } + Err(_) => { + panic!("expected {path:?} to contain\n{contents}"); + } + } + } + Ok(()) +} diff --git a/crates/wit-component/tests/components/adapt-empty-interface/adapt-old.wat b/crates/wit-component/tests/components/adapt-empty-interface/adapt-old.wat new file mode 100644 index 0000000000..899cfbd036 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-empty-interface/adapt-old.wat @@ -0,0 +1,3 @@ +(module + (func (export "thunk")) +) diff --git a/crates/wit-component/tests/components/adapt-empty-interface/adapt-old.wit b/crates/wit-component/tests/components/adapt-empty-interface/adapt-old.wit new file mode 100644 index 0000000000..325408137d --- /dev/null +++ b/crates/wit-component/tests/components/adapt-empty-interface/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + thunk-that-is-not-called: func(); + } +} diff --git a/crates/wit-component/tests/components/adapt-empty-interface/component.wat b/crates/wit-component/tests/components/adapt-empty-interface/component.wat new file mode 100644 index 0000000000..f7414c4aae --- /dev/null +++ b/crates/wit-component/tests/components/adapt-empty-interface/component.wat @@ -0,0 +1,60 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (import "old" "thunk" (func (;0;) (type 0))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "thunk" (func 0)) + ) + (core module (;2;) + (type (;0;) (func)) + (func $adapt-old-thunk (;0;) (type 0) + i32.const 0 + call_indirect (type 0) + ) + (table (;0;) 1 1 funcref) + (export "0" (func $adapt-old-thunk)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func)) + (import "" "0" (func (;0;) (type 0))) + (import "" "$imports" (table (;0;) 1 1 funcref)) + (elem (;0;) (i32.const 0) func 0) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "0" (core func (;0;))) + (core instance (;1;) + (export "thunk" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (core instance (;3;) (instantiate 1)) + (alias core export 0 "$imports" (core table (;0;))) + (alias core export 3 "thunk" (core func (;1;))) + (core instance (;4;) + (export "$imports" (table 0)) + (export "0" (func 1)) + ) + (core instance (;5;) (instantiate 3 + (with "" (instance 4)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-empty-interface/component.wit.print b/crates/wit-component/tests/components/adapt-empty-interface/component.wit.print new file mode 100644 index 0000000000..bcd860d376 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-empty-interface/component.wit.print @@ -0,0 +1,4 @@ +package root:component + +world root { +} diff --git a/crates/wit-component/tests/components/adapt-empty-interface/module.wat b/crates/wit-component/tests/components/adapt-empty-interface/module.wat new file mode 100644 index 0000000000..fa9d20a83a --- /dev/null +++ b/crates/wit-component/tests/components/adapt-empty-interface/module.wat @@ -0,0 +1,3 @@ +(module + (import "old" "thunk" (func)) +) diff --git a/crates/wit-component/tests/components/adapt-empty-interface/module.wit b/crates/wit-component/tests/components/adapt-empty-interface/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-empty-interface/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/adapt-export-default/adapt-old.wat b/crates/wit-component/tests/components/adapt-export-default/adapt-old.wat new file mode 100644 index 0000000000..a01bf8563a --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-default/adapt-old.wat @@ -0,0 +1,4 @@ +(module + (import "__main_module__" "the_entrypoint" (func $entry)) + (export "entrypoint" (func $entry)) +) diff --git a/crates/wit-component/tests/components/adapt-export-default/adapt-old.wit b/crates/wit-component/tests/components/adapt-export-default/adapt-old.wit new file mode 100644 index 0000000000..52d2cbb4be --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-default/adapt-old.wit @@ -0,0 +1,3 @@ +world adapt-old { + export entrypoint: func(); +} diff --git a/crates/wit-component/tests/components/adapt-export-default/component.wat b/crates/wit-component/tests/components/adapt-export-default/component.wat new file mode 100644 index 0000000000..d68b0f1d67 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-default/component.wat @@ -0,0 +1,32 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "the_entrypoint" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func)) + (import "__main_module__" "the_entrypoint" (func $entry (;0;) (type 0))) + (export "entrypoint" (func $entry)) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "the_entrypoint" (core func (;0;))) + (core instance (;1;) + (export "the_entrypoint" (func 0)) + ) + (core instance (;2;) (instantiate 1 + (with "__main_module__" (instance 1)) + ) + ) + (type (;0;) (func)) + (alias core export 2 "entrypoint" (core func (;1;))) + (func (;0;) (type 0) (canon lift (core func 1))) + (export (;1;) "entrypoint" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-export-default/component.wit.print b/crates/wit-component/tests/components/adapt-export-default/component.wit.print new file mode 100644 index 0000000000..3b69830770 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-default/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + export entrypoint: func() +} diff --git a/crates/wit-component/tests/components/adapt-export-default/module.wat b/crates/wit-component/tests/components/adapt-export-default/module.wat new file mode 100644 index 0000000000..c557a73bc4 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-default/module.wat @@ -0,0 +1,3 @@ +(module + (func (export "the_entrypoint")) +) diff --git a/crates/wit-component/tests/components/adapt-export-default/module.wit b/crates/wit-component/tests/components/adapt-export-default/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-default/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/adapt-export-namespaced/adapt-old.wat b/crates/wit-component/tests/components/adapt-export-namespaced/adapt-old.wat new file mode 100644 index 0000000000..0c4debd062 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-namespaced/adapt-old.wat @@ -0,0 +1,4 @@ +(module + (import "__main_module__" "the_entrypoint" (func $entry)) + (export "foo:foo/new#entrypoint" (func $entry)) +) diff --git a/crates/wit-component/tests/components/adapt-export-namespaced/adapt-old.wit b/crates/wit-component/tests/components/adapt-export-namespaced/adapt-old.wit new file mode 100644 index 0000000000..27d1cf9d1b --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-namespaced/adapt-old.wit @@ -0,0 +1,7 @@ +interface new { + entrypoint: func(); +} + +world adapt-old { + export new; +} diff --git a/crates/wit-component/tests/components/adapt-export-namespaced/component.wat b/crates/wit-component/tests/components/adapt-export-namespaced/component.wat new file mode 100644 index 0000000000..516cfadabb --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-namespaced/component.wat @@ -0,0 +1,42 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "the_entrypoint" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func)) + (import "__main_module__" "the_entrypoint" (func $entry (;0;) (type 0))) + (export "foo:foo/new#entrypoint" (func $entry)) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "the_entrypoint" (core func (;0;))) + (core instance (;1;) + (export "the_entrypoint" (func 0)) + ) + (core instance (;2;) (instantiate 1 + (with "__main_module__" (instance 1)) + ) + ) + (type (;0;) (func)) + (alias core export 2 "foo:foo/new#entrypoint" (core func (;1;))) + (func (;0;) (type 0) (canon lift (core func 1))) + (component (;0;) + (type (;0;) (func)) + (import "import-func-entrypoint" (func (;0;) (type 0))) + (type (;1;) (func)) + (export (;1;) "entrypoint" (func 0) (func (type 1))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-entrypoint" (func 0)) + ) + ) + (export (;1;) (interface "foo:foo/new") (instance 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-export-namespaced/component.wit.print b/crates/wit-component/tests/components/adapt-export-namespaced/component.wit.print new file mode 100644 index 0000000000..d4d0543221 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-namespaced/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + export foo:foo/new +} diff --git a/crates/wit-component/tests/components/adapt-export-namespaced/module.wat b/crates/wit-component/tests/components/adapt-export-namespaced/module.wat new file mode 100644 index 0000000000..c557a73bc4 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-namespaced/module.wat @@ -0,0 +1,3 @@ +(module + (func (export "the_entrypoint")) +) diff --git a/crates/wit-component/tests/components/adapt-export-namespaced/module.wit b/crates/wit-component/tests/components/adapt-export-namespaced/module.wit new file mode 100644 index 0000000000..c54087df30 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-namespaced/module.wit @@ -0,0 +1,3 @@ +package foo:foo; + +world module {} diff --git a/crates/wit-component/tests/components/adapt-export-reallocs/adapt-old.wat b/crates/wit-component/tests/components/adapt-export-reallocs/adapt-old.wat new file mode 100644 index 0000000000..f29e1ddb15 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-reallocs/adapt-old.wat @@ -0,0 +1,47 @@ +(module + (import "__main_module__" "main" (func $main (param i32 i32))) + (import "new" "read" (func $read (param i32 i32))) + + + (global $sp (mut i32) (i32.const 0)) + + (func $start + (global.set $sp + (i32.mul + (memory.grow (i32.const 1)) + (i32.const 65536))) + ) + + (func (export "entrypoint") (param i32 i32) + unreachable + ) + + (func (export "cabi_export_realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + + (func (export "read") (param $ptr i32) (param $len i32) + (local $fp i32) + (global.set $sp + (local.tee $fp + (i32.sub + (global.get $sp) + (i32.const 8) + ) + ) + ) + + (call $read (local.get $len) (local.get $fp)) + + (global.set $sp + (i32.add + (local.get $fp) + (i32.const 8) + ) + ) + ) + + (func (export "cabi_import_realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) +) diff --git a/crates/wit-component/tests/components/adapt-export-reallocs/adapt-old.wit b/crates/wit-component/tests/components/adapt-export-reallocs/adapt-old.wit new file mode 100644 index 0000000000..a3441b23aa --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-reallocs/adapt-old.wit @@ -0,0 +1,6 @@ +world adapt-old { + import new: interface { + read: func(amt: u32) -> list; + } + export entrypoint: func(args: list); +} diff --git a/crates/wit-component/tests/components/adapt-export-reallocs/component.wat b/crates/wit-component/tests/components/adapt-export-reallocs/component.wat new file mode 100644 index 0000000000..89dd67e186 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-reallocs/component.wat @@ -0,0 +1,131 @@ +(component + (type (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (func (param "amt" u32) (result 0))) + (export (;0;) "read" (func (type 1))) + ) + ) + (import "new" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32 i32))) + (import "old" "read" (func (;0;) (type 0))) + (func (;1;) (type 0) (param $args i32) (param $argv i32)) + (memory (;0;) 1) + (export "main" (func 1)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "new" "read" (func $read (;0;) (type 0))) + (func (;1;) (type 0) (param i32 i32) + unreachable + ) + (func (;2;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;3;) (type 0) (param i32 i32) + (local i32) + global.get $sp + i32.const 8 + i32.sub + local.tee 2 + global.set $sp + local.get 1 + local.get 2 + call $read + local.get 2 + i32.const 8 + i32.add + global.set $sp + ) + (func (;4;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (global $sp (;0;) (mut i32) i32.const 0) + (export "entrypoint" (func 1)) + (export "cabi_export_realloc" (func 2)) + (export "read" (func 3)) + (export "cabi_import_realloc" (func 4)) + ) + (core module (;2;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32))) + (func $indirect-new-read (;0;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-old-read (;1;) (type 1) (param i32 i32) + local.get 0 + local.get 1 + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-new-read)) + (export "1" (func $adapt-old-read)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "read" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 0 "0" (core func (;1;))) + (core instance (;3;) + (export "read" (func 1)) + ) + (core instance (;4;) (instantiate 1 + (with "new" (instance 3)) + ) + ) + (alias core export 4 "cabi_export_realloc" (core func (;2;))) + (alias core export 4 "cabi_import_realloc" (core func (;3;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "read" (func (;0;))) + (core func (;4;) (canon lower (func 0) (memory 0) (realloc 3))) + (alias core export 4 "read" (core func (;5;))) + (core instance (;5;) + (export "$imports" (table 0)) + (export "0" (func 4)) + (export "1" (func 5)) + ) + (core instance (;6;) (instantiate 3 + (with "" (instance 5)) + ) + ) + (type (;1;) (list string)) + (type (;2;) (func (param "args" 1))) + (alias core export 4 "entrypoint" (core func (;6;))) + (func (;1;) (type 2) (canon lift (core func 6) (memory 0) (realloc 2) string-encoding=utf8)) + (export (;2;) "entrypoint" (func 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-export-reallocs/component.wit.print b/crates/wit-component/tests/components/adapt-export-reallocs/component.wit.print new file mode 100644 index 0000000000..183298fccf --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-reallocs/component.wit.print @@ -0,0 +1,9 @@ +package root:component + +world root { + import new: interface { + read: func(amt: u32) -> list + } + + export entrypoint: func(args: list) +} diff --git a/crates/wit-component/tests/components/adapt-export-reallocs/module.wat b/crates/wit-component/tests/components/adapt-export-reallocs/module.wat new file mode 100644 index 0000000000..81a8de37f7 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-reallocs/module.wat @@ -0,0 +1,8 @@ +(module + (import "old" "read" (func (param i32 i32))) + (func (export "main") (param $args i32) (param $argv i32) + ;; ... + ) + + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/adapt-export-reallocs/module.wit b/crates/wit-component/tests/components/adapt-export-reallocs/module.wit new file mode 100644 index 0000000000..c54087df30 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-reallocs/module.wit @@ -0,0 +1,3 @@ +package foo:foo; + +world module {} diff --git a/crates/wit-component/tests/components/adapt-export-save-args/adapt-old.wat b/crates/wit-component/tests/components/adapt-export-save-args/adapt-old.wat new file mode 100644 index 0000000000..9d0d56789d --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-save-args/adapt-old.wat @@ -0,0 +1,13 @@ +(module + (import "__main_module__" "the_entrypoint" (func $entry)) + + (global $nargs (mut i32) (i32.const 0)) + + (func (export "entrypoint") (param $nargs i32) + (global.set $nargs (local.get $nargs)) + call $entry + ) + + (func (export "nargs") (result i32) + global.get $nargs) +) diff --git a/crates/wit-component/tests/components/adapt-export-save-args/adapt-old.wit b/crates/wit-component/tests/components/adapt-export-save-args/adapt-old.wit new file mode 100644 index 0000000000..c8750a0aad --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-save-args/adapt-old.wit @@ -0,0 +1,3 @@ +world adapt-old { + export entrypoint: func(nargs: u32); +} diff --git a/crates/wit-component/tests/components/adapt-export-save-args/component.wat b/crates/wit-component/tests/components/adapt-export-save-args/component.wat new file mode 100644 index 0000000000..23d0d9a7cb --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-save-args/component.wat @@ -0,0 +1,86 @@ +(component + (core module (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (import "old" "nargs" (func (;0;) (type 0))) + (func (;1;) (type 1)) + (export "the_entrypoint" (func 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (result i32))) + (import "__main_module__" "the_entrypoint" (func $entry (;0;) (type 0))) + (func (;1;) (type 1) (param i32) + local.get 0 + global.set $nargs + call $entry + ) + (func (;2;) (type 2) (result i32) + global.get $nargs + ) + (global $nargs (;0;) (mut i32) i32.const 0) + (export "entrypoint" (func 1)) + (export "nargs" (func 2)) + ) + (core module (;2;) + (type (;0;) (func (result i32))) + (func $adapt-old-nargs (;0;) (type 0) (result i32) + i32.const 0 + call_indirect (type 0) + ) + (table (;0;) 1 1 funcref) + (export "0" (func $adapt-old-nargs)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (result i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "$imports" (table (;0;) 1 1 funcref)) + (elem (;0;) (i32.const 0) func 0) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "0" (core func (;0;))) + (core instance (;1;) + (export "nargs" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "the_entrypoint" (core func (;1;))) + (core instance (;3;) + (export "the_entrypoint" (func 1)) + ) + (core instance (;4;) (instantiate 1 + (with "__main_module__" (instance 3)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias core export 4 "nargs" (core func (;2;))) + (core instance (;5;) + (export "$imports" (table 0)) + (export "0" (func 2)) + ) + (core instance (;6;) (instantiate 3 + (with "" (instance 5)) + ) + ) + (type (;0;) (func (param "nargs" u32))) + (alias core export 4 "entrypoint" (core func (;3;))) + (func (;0;) (type 0) (canon lift (core func 3))) + (export (;1;) "entrypoint" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-export-save-args/component.wit.print b/crates/wit-component/tests/components/adapt-export-save-args/component.wit.print new file mode 100644 index 0000000000..1946b9c042 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-save-args/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + export entrypoint: func(nargs: u32) +} diff --git a/crates/wit-component/tests/components/adapt-export-save-args/module.wat b/crates/wit-component/tests/components/adapt-export-save-args/module.wat new file mode 100644 index 0000000000..d2e03c4935 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-save-args/module.wat @@ -0,0 +1,4 @@ +(module + (import "old" "nargs" (func (result i32))) + (func (export "the_entrypoint")) +) diff --git a/crates/wit-component/tests/components/adapt-export-save-args/module.wit b/crates/wit-component/tests/components/adapt-export-save-args/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-save-args/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/adapt-export-with-post-return/adapt-old.wat b/crates/wit-component/tests/components/adapt-export-with-post-return/adapt-old.wat new file mode 100644 index 0000000000..197c7014ff --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-with-post-return/adapt-old.wat @@ -0,0 +1,33 @@ +;; This example represents adapting modules which use an early version of the +;; canonical ABI, back when `cabi_realloc` was named `canonical_abi_realloc` and +;; had a friend named `canonical_abi_free`. Such modules are pretty easy to +;; adapt since the adapter can use the main module's allocator for both lowering +;; and post-return functions. +;; +;; See https://github.com/fermyon/spin-componentize for a real-world example. + +(module + (import "__main_module__" "canonical_abi_realloc" (func $realloc (param i32 i32 i32 i32) (result i32))) + (import "__main_module__" "canonical_abi_free" (func $free (param i32 i32 i32))) + (import "env" "memory" (memory 0)) + (global $__stack_pointer (mut i32) i32.const 0) + (global $allocation_state (mut i32) i32.const 0) + + (func (export "foo:foo/new#foo") (result i32) + ;; This is a dummy, non-working implementation, just to make gc.rs do what + ;; we want, which is to treat this adapter as if it uses the main module's + ;; allocator to allocate and free memory. + + global.get $__stack_pointer + global.get $allocation_state + (call $realloc (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0)) + unreachable + ) + + (func (export "cabi_post_foo:foo/new#foo") (param i32) + ;; another dummy implementation + + (call $free (i32.const 0) (i32.const 0) (i32.const 0)) + unreachable + ) +) diff --git a/crates/wit-component/tests/components/adapt-export-with-post-return/adapt-old.wit b/crates/wit-component/tests/components/adapt-export-with-post-return/adapt-old.wit new file mode 100644 index 0000000000..ef3210f059 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-with-post-return/adapt-old.wit @@ -0,0 +1,7 @@ +interface new { + foo: func() -> string; +} + +world adapt-old { + export new; +} diff --git a/crates/wit-component/tests/components/adapt-export-with-post-return/component.wat b/crates/wit-component/tests/components/adapt-export-with-post-return/component.wat new file mode 100644 index 0000000000..1f87b438cf --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-with-post-return/component.wat @@ -0,0 +1,102 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i32))) + (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;1;) (type 1) (param i32 i32 i32) + unreachable + ) + (memory (;0;) 1) + (export "canonical_abi_realloc" (func 0)) + (export "canonical_abi_free" (func 1)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func (param i32))) + (type (;4;) (func)) + (import "__main_module__" "canonical_abi_realloc" (func $realloc (;0;) (type 0))) + (import "__main_module__" "canonical_abi_free" (func $free (;1;) (type 1))) + (func (;2;) (type 2) (result i32) + call $allocate_stack + global.get $__stack_pointer + global.get $allocation_state + i32.const 0 + i32.const 0 + i32.const 0 + i32.const 0 + call $realloc + unreachable + ) + (func (;3;) (type 3) (param i32) + call $allocate_stack + i32.const 0 + i32.const 0 + i32.const 0 + call $free + unreachable + ) + (func $allocate_stack (;4;) (type 4) + global.get $allocation_state + i32.const 0 + i32.eq + if ;; label = @1 + i32.const 1 + global.set $allocation_state + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $realloc + i32.const 65536 + i32.add + global.set $__stack_pointer + i32.const 2 + global.set $allocation_state + end + ) + (global $__stack_pointer (;0;) (mut i32) i32.const 0) + (global $allocation_state (;1;) (mut i32) i32.const 0) + (export "foo:foo/new#foo" (func 2)) + (export "cabi_post_foo:foo/new#foo" (func 3)) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "canonical_abi_realloc" (core func (;0;))) + (alias core export 0 "canonical_abi_realloc" (core func (;1;))) + (alias core export 0 "canonical_abi_free" (core func (;2;))) + (core instance (;1;) + (export "canonical_abi_realloc" (func 1)) + (export "canonical_abi_free" (func 2)) + ) + (core instance (;2;) (instantiate 1 + (with "__main_module__" (instance 1)) + ) + ) + (type (;0;) (func (result string))) + (alias core export 2 "foo:foo/new#foo" (core func (;3;))) + (alias core export 2 "cabi_post_foo:foo/new#foo" (core func (;4;))) + (func (;0;) (type 0) (canon lift (core func 3) (memory 0) string-encoding=utf8 (post-return 4))) + (component (;0;) + (type (;0;) (func (result string))) + (import "import-func-foo" (func (;0;) (type 0))) + (type (;1;) (func (result string))) + (export (;1;) "foo" (func 0) (func (type 1))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-foo" (func 0)) + ) + ) + (export (;1;) (interface "foo:foo/new") (instance 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-export-with-post-return/component.wit.print b/crates/wit-component/tests/components/adapt-export-with-post-return/component.wit.print new file mode 100644 index 0000000000..d4d0543221 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-with-post-return/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + export foo:foo/new +} diff --git a/crates/wit-component/tests/components/adapt-export-with-post-return/module.wat b/crates/wit-component/tests/components/adapt-export-with-post-return/module.wat new file mode 100644 index 0000000000..98361ae612 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-with-post-return/module.wat @@ -0,0 +1,9 @@ +(module + (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (export "canonical_abi_free") (param i32 i32 i32) + unreachable + ) + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/adapt-export-with-post-return/module.wit b/crates/wit-component/tests/components/adapt-export-with-post-return/module.wit new file mode 100644 index 0000000000..c54087df30 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-export-with-post-return/module.wit @@ -0,0 +1,3 @@ +package foo:foo; + +world module {} diff --git a/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/adapt-unused.wat b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/adapt-unused.wat new file mode 100644 index 0000000000..ea9a0b70f9 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/adapt-unused.wat @@ -0,0 +1,7 @@ +(module + (import "foo:foo/adapter-imports" "foo" (func $foo (param i32 i32))) + (func (export "adapter-bar") (param i32 i32) + (call $foo (i32.const 0) (i32.const 0)) + ) + (func (export "cabi_export_realloc") (param i32 i32 i32 i32) (result i32) unreachable) +) diff --git a/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/adapt-unused.wit b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/adapt-unused.wit new file mode 100644 index 0000000000..91d3c57d94 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/adapt-unused.wit @@ -0,0 +1,9 @@ +interface adapter-imports { + foo: func(x: string); +} + +world adapt-unused { + import adapter-imports; + + export adapter-bar: func(x: string); +} diff --git a/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/component.wat b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/component.wat new file mode 100644 index 0000000000..a2689c0132 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/component.wat @@ -0,0 +1,115 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "x" string))) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import (interface "foo:foo/adapter-imports") (instance (;0;) (type 0))) + (type (;1;) (func (param "x" string))) + (import "foo" (func (;0;) (type 1))) + (core module (;0;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func)) + (import "$root" "foo" (func (;0;) (type 0))) + (func (;1;) (type 1) + unreachable + ) + (memory (;0;) 1) + (export "bar" (func 1)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo:foo/adapter-imports" "foo" (func $foo (;0;) (type 0))) + (func (;1;) (type 0) (param i32 i32) + i32.const 0 + i32.const 0 + call $foo + ) + (func (;2;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (export "adapter-bar" (func 1)) + (export "cabi_export_realloc" (func 2)) + ) + (core module (;2;) + (type (;0;) (func (param i32 i32))) + (func $indirect-$root-foo (;0;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 0 + call_indirect (type 0) + ) + (func $indirect-foo:foo/adapter-imports-foo (;1;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 1 + call_indirect (type 0) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-$root-foo)) + (export "1" (func $indirect-foo:foo/adapter-imports-foo)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32 i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "0" (core func (;0;))) + (core instance (;1;) + (export "foo" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "$root" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 0 "1" (core func (;1;))) + (core instance (;3;) + (export "foo" (func 1)) + ) + (core instance (;4;) (instantiate 1 + (with "foo:foo/adapter-imports" (instance 3)) + ) + ) + (alias core export 4 "cabi_export_realloc" (core func (;2;))) + (alias core export 0 "$imports" (core table (;0;))) + (core func (;3;) (canon lower (func 0) (memory 0) string-encoding=utf8)) + (alias export 0 "foo" (func (;1;))) + (core func (;4;) (canon lower (func 1) (memory 0) string-encoding=utf8)) + (core instance (;5;) + (export "$imports" (table 0)) + (export "0" (func 3)) + (export "1" (func 4)) + ) + (core instance (;6;) (instantiate 3 + (with "" (instance 5)) + ) + ) + (type (;2;) (func)) + (alias core export 2 "bar" (core func (;5;))) + (func (;2;) (type 2) (canon lift (core func 5))) + (export (;3;) "bar" (func 2)) + (alias core export 4 "adapter-bar" (core func (;6;))) + (func (;4;) (type 1) (canon lift (core func 6) (memory 0) (realloc 2) string-encoding=utf8)) + (export (;5;) "adapter-bar" (func 4)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/component.wit.print b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/component.wit.print new file mode 100644 index 0000000000..5d06bd3474 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/component.wit.print @@ -0,0 +1,9 @@ +package root:component + +world root { + import foo:foo/adapter-imports + import foo: func(x: string) + + export bar: func() + export adapter-bar: func(x: string) +} diff --git a/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/module.wat b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/module.wat new file mode 100644 index 0000000000..00afe7a01f --- /dev/null +++ b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/module.wat @@ -0,0 +1,5 @@ +(module + (import "$root" "foo" (func (param i32 i32))) + (func (export "bar") unreachable) + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/module.wit b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/module.wit new file mode 100644 index 0000000000..1dbfb93883 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-import-only-used-in-adapter/module.wit @@ -0,0 +1,6 @@ +package foo:foo; + +world module { + import foo: func(x: string); + export bar: func(); +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/adapt-old.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/adapt-old.wat new file mode 100644 index 0000000000..403204da2d --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/adapt-old.wat @@ -0,0 +1,76 @@ +(module + (import "new" "get-two" (func $get_two (param i32))) + (import "__main_module__" "cabi_realloc" (func $cabi_realloc (param i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 0)) + + (global $__stack_pointer (mut i32) i32.const 0) + (global $some_other_mutable_global (mut i32) i32.const 0) + + ;; `wit-component` should use this to track the status of a lazy stack + ;; allocation: + (global $allocation_state (mut i32) i32.const 0) + + ;; This is a sample adapter which is adapting between ABI. This exact function + ;; signature is imported by `module.wat` and we're implementing it here with a + ;; canonical-abi function that returns two integers. The canonical ABI for + ;; returning two integers is different than the ABI of this function, hence + ;; the adapter here. + ;; + ;; The purpose of this test case is to exercise the `$__stack_pointer` global. + ;; The stack pointer here needs to be initialized to something valid for + ;; this adapter module which is done with an injected `start` function into + ;; this adapter module when it's bundled into a component. + (func (export "get_sum") (result i32) + (local i32 i32) + + ;; `wit-component` should have injected a call to a function that allocates + ;; the stack and sets $allocation_state to 2 + (if (i32.ne (global.get $allocation_state) (i32.const 2)) (then (unreachable))) + + ;; First, allocate a page using $cabi_realloc and write to it. This tests + ;; that we can use the main module's allocator if present (or else a + ;; substitute synthesized by `wit-component`). + (local.set 0 + (call $cabi_realloc + (i32.const 0) + (i32.const 0) + (i32.const 8) + (i32.const 65536))) + + (i32.store (local.get 0) (i32.const 42)) + (i32.store offset=65532 (local.get 0) (i32.const 42)) + + ;; Allocate 8 bytes of stack space for the two u32 return values. The + ;; original stack pointer is saved in local 0 and the stack frame for this + ;; function is saved in local 1. + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + + ;; Call the imported function which will return two u32 values into the + ;; return pointer specified here, our stack frame. + local.get 1 + call $get_two + + ;; Compute the result of this function by adding together the two return + ;; values. + (i32.add + (i32.load (local.get 1)) + (i32.load offset=4 (local.get 1))) + + ;; Test that if there is another mutable global in this module that it + ;; doesn't affect the detection of the stack pointer. This extra mutable + ;; global should not be initialized or tampered with as part of the + ;; initialize-the-stack-pointer injected function + (global.set $some_other_mutable_global (global.get $some_other_mutable_global)) + + ;; Restore the stack pointer to the value it was at prior to entering this + ;; function. + local.get 0 + global.set $__stack_pointer + ) + +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/adapt-old.wit b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/adapt-old.wit new file mode 100644 index 0000000000..a9f798e81e --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + get-two: func() -> (a: u32, b: u32); + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/component.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/component.wat new file mode 100644 index 0000000000..f7995d5908 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/component.wat @@ -0,0 +1,174 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (result "a" u32) (result "b" u32))) + (export (;0;) "get-two" (func (type 0))) + ) + ) + (import "new" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "old" "get_sum" (func (;0;) (type 0))) + (func $cabi_realloc (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + i32.const 123456789 + ) + (func $cabi_realloc_adapter (;2;) (type 1) (param i32 i32 i32 i32) (result i32) + i32.const 987654321 + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func $cabi_realloc)) + (export "cabi_realloc_adapter" (func $cabi_realloc_adapter)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func)) + (import "env" "memory" (memory (;0;) 0)) + (import "new" "get-two" (func $get_two (;0;) (type 0))) + (import "__main_module__" "cabi_realloc" (func $cabi_realloc (;1;) (type 1))) + (func (;2;) (type 2) (result i32) + (local i32 i32) + call $allocate_stack + global.get $allocation_state + i32.const 2 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $cabi_realloc + local.set 0 + local.get 0 + i32.const 42 + i32.store + local.get 0 + i32.const 42 + i32.store offset=65532 + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + local.get 1 + call $get_two + local.get 1 + i32.load + local.get 1 + i32.load offset=4 + i32.add + global.get $some_other_mutable_global + global.set $some_other_mutable_global + local.get 0 + global.set $__stack_pointer + ) + (func $allocate_stack (;3;) (type 3) + global.get $allocation_state + i32.const 0 + i32.eq + if ;; label = @1 + i32.const 1 + global.set $allocation_state + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $cabi_realloc + i32.const 65536 + i32.add + global.set $__stack_pointer + i32.const 2 + global.set $allocation_state + end + ) + (global $__stack_pointer (;0;) (mut i32) i32.const 0) + (global $some_other_mutable_global (;1;) (mut i32) i32.const 0) + (global $allocation_state (;2;) (mut i32) i32.const 0) + (export "get_sum" (func 2)) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (func $indirect-new-get-two (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-old-get_sum (;1;) (type 1) (result i32) + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-new-get-two)) + (export "1" (func $adapt-old-get_sum)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "get_sum" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;1;))) + (alias core export 2 "cabi_realloc_adapter" (core func (;2;))) + (core instance (;3;) + (export "cabi_realloc" (func 2)) + ) + (core instance (;4;) + (export "memory" (memory 0)) + ) + (alias core export 0 "0" (core func (;3;))) + (core instance (;5;) + (export "get-two" (func 3)) + ) + (core instance (;6;) (instantiate 1 + (with "__main_module__" (instance 3)) + (with "env" (instance 4)) + (with "new" (instance 5)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "get-two" (func (;0;))) + (core func (;4;) (canon lower (func 0) (memory 0))) + (alias core export 6 "get_sum" (core func (;5;))) + (core instance (;7;) + (export "$imports" (table 0)) + (export "0" (func 4)) + (export "1" (func 5)) + ) + (core instance (;8;) (instantiate 3 + (with "" (instance 7)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/component.wit.print b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/component.wit.print new file mode 100644 index 0000000000..b1f183513f --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import new: interface { + get-two: func() -> (a: u32, b: u32) + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/module.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/module.wat new file mode 100644 index 0000000000..20941bb595 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/module.wat @@ -0,0 +1,12 @@ +(module + (import "old" "get_sum" (func (result i32))) + (func $cabi_realloc (param i32 i32 i32 i32) (result i32) + (i32.const 123456789) + ) + (func $cabi_realloc_adapter (param i32 i32 i32 i32) (result i32) + (i32.const 987654321) + ) + (memory (export "memory") 1) + (export "cabi_realloc" (func $cabi_realloc)) + (export "cabi_realloc_adapter" (func $cabi_realloc_adapter)) +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/module.wit b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-adapt-realloc/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/adapt-old.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/adapt-old.wat new file mode 100644 index 0000000000..56cb4d0270 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/adapt-old.wat @@ -0,0 +1,68 @@ +(module + (import "new" "get-two" (func $get_two (param i32))) + (import "__main_module__" "cabi_realloc" (func $cabi_realloc (param i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 0)) + + (global $__stack_pointer (mut i32) i32.const 0) + (global $some_other_mutable_global (mut i32) i32.const 0) + + ;; This is a sample adapter which is adapting between ABI. This exact function + ;; signature is imported by `module.wat` and we're implementing it here with a + ;; canonical-abi function that returns two integers. The canonical ABI for + ;; returning two integers is different than the ABI of this function, hence + ;; the adapter here. + ;; + ;; The purpose of this test case is to exercise the `$__stack_pointer` global. + ;; The stack pointer here needs to be initialized to something valid for + ;; this adapter module which is done with an injected `start` function into + ;; this adapter module when it's bundled into a component. + (func (export "get_sum") (result i32) + (local i32 i32) + + ;; First, allocate a page using $cabi_realloc and write to it. This tests + ;; that we can use the main module's allocator if present (or else a + ;; substitute synthesized by `wit-component`). + (local.set 0 + (call $cabi_realloc + (i32.const 0) + (i32.const 0) + (i32.const 8) + (i32.const 65536))) + + (i32.store (local.get 0) (i32.const 42)) + (i32.store offset=65532 (local.get 0) (i32.const 42)) + + ;; Allocate 8 bytes of stack space for the two u32 return values. The + ;; original stack pointer is saved in local 0 and the stack frame for this + ;; function is saved in local 1. + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + + ;; Call the imported function which will return two u32 values into the + ;; return pointer specified here, our stack frame. + local.get 1 + call $get_two + + ;; Compute the result of this function by adding together the two return + ;; values. + (i32.add + (i32.load (local.get 1)) + (i32.load offset=4 (local.get 1))) + + ;; Test that if there is another mutable global in this module that it + ;; doesn't affect the detection of the stack pointer. This extra mutable + ;; global should not be initialized or tampered with as part of the + ;; initialize-the-stack-pointer injected function + (global.set $some_other_mutable_global (global.get $some_other_mutable_global)) + + ;; Restore the stack pointer to the value it was at prior to entering this + ;; function. + local.get 0 + global.set $__stack_pointer + ) + +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/adapt-old.wit b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/adapt-old.wit new file mode 100644 index 0000000000..a9f798e81e --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + get-two: func() -> (a: u32, b: u32); + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/component.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/component.wat new file mode 100644 index 0000000000..cb68c63c7b --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/component.wat @@ -0,0 +1,216 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (result "a" u32) (result "b" u32))) + (export (;0;) "get-two" (func (type 0))) + ) + ) + (import "new" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "old" "get_sum" (func (;0;) (type 0))) + (func $cabi_realloc (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + (local i32) + i32.const 0 + local.get 0 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 0 + local.get 1 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 65536 + local.get 3 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 1 + memory.grow + local.tee 4 + i32.const -1 + i32.eq + if ;; label = @1 + unreachable + end + local.get 4 + i32.const 16 + i32.shl + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func $cabi_realloc)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func (param i32 i32 i32 i32) (result i32))) + (type (;4;) (func)) + (import "env" "memory" (memory (;0;) 0)) + (import "new" "get-two" (func $get_two (;0;) (type 0))) + (import "__main_module__" "cabi_realloc" (func $cabi_realloc (;1;) (type 1))) + (func (;2;) (type 2) (result i32) + (local i32 i32) + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $cabi_realloc + local.set 0 + local.get 0 + i32.const 42 + i32.store + local.get 0 + i32.const 42 + i32.store offset=65532 + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + local.get 1 + call $get_two + local.get 1 + i32.load + local.get 1 + i32.load offset=4 + i32.add + global.get $some_other_mutable_global + global.set $some_other_mutable_global + local.get 0 + global.set $__stack_pointer + ) + (func $realloc_via_memory_grow (;3;) (type 3) (param i32 i32 i32 i32) (result i32) + (local i32) + i32.const 0 + local.get 0 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 0 + local.get 1 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 65536 + local.get 3 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 1 + memory.grow + local.tee 4 + i32.const -1 + i32.eq + if ;; label = @1 + unreachable + end + local.get 4 + i32.const 16 + i32.shl + ) + (func $allocate_stack (;4;) (type 4) + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $realloc_via_memory_grow + i32.const 65536 + i32.add + global.set $__stack_pointer + ) + (global $__stack_pointer (;0;) (mut i32) i32.const 0) + (global $some_other_mutable_global (;1;) (mut i32) i32.const 0) + (export "get_sum" (func 2)) + (start $allocate_stack) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (func $indirect-new-get-two (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-old-get_sum (;1;) (type 1) (result i32) + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-new-get-two)) + (export "1" (func $adapt-old-get_sum)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "get_sum" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;1;))) + (alias core export 2 "cabi_realloc" (core func (;2;))) + (core instance (;3;) + (export "cabi_realloc" (func 2)) + ) + (core instance (;4;) + (export "memory" (memory 0)) + ) + (alias core export 0 "0" (core func (;3;))) + (core instance (;5;) + (export "get-two" (func 3)) + ) + (core instance (;6;) (instantiate 1 + (with "__main_module__" (instance 3)) + (with "env" (instance 4)) + (with "new" (instance 5)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "get-two" (func (;0;))) + (core func (;4;) (canon lower (func 0) (memory 0))) + (alias core export 6 "get_sum" (core func (;5;))) + (core instance (;7;) + (export "$imports" (table 0)) + (export "0" (func 4)) + (export "1" (func 5)) + ) + (core instance (;8;) (instantiate 3 + (with "" (instance 7)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/component.wit.print b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/component.wit.print new file mode 100644 index 0000000000..b1f183513f --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import new: interface { + get-two: func() -> (a: u32, b: u32) + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/module.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/module.wat new file mode 100644 index 0000000000..bf7e135842 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/module.wat @@ -0,0 +1,38 @@ +(module + (import "old" "get_sum" (func (result i32))) + ;; Minimal realloc which only accepts new, page-sized allocations: + (func $cabi_realloc (param i32 i32 i32 i32) (result i32) + (local i32) + i32.const 0 + local.get 0 + i32.ne + if + unreachable + end + i32.const 0 + local.get 1 + i32.ne + if + unreachable + end + i32.const 65536 + local.get 3 + i32.ne + if + unreachable + end + i32.const 1 + memory.grow + local.tee 4 + i32.const -1 + i32.eq + if + unreachable + end + local.get 4 + i32.const 16 + i32.shl + ) + (memory (export "memory") 1) + (export "cabi_realloc" (func $cabi_realloc)) +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/module.wit b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/module.wit new file mode 100644 index 0000000000..c54087df30 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc-no-state/module.wit @@ -0,0 +1,3 @@ +package foo:foo; + +world module {} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/adapt-old.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/adapt-old.wat new file mode 100644 index 0000000000..403204da2d --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/adapt-old.wat @@ -0,0 +1,76 @@ +(module + (import "new" "get-two" (func $get_two (param i32))) + (import "__main_module__" "cabi_realloc" (func $cabi_realloc (param i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 0)) + + (global $__stack_pointer (mut i32) i32.const 0) + (global $some_other_mutable_global (mut i32) i32.const 0) + + ;; `wit-component` should use this to track the status of a lazy stack + ;; allocation: + (global $allocation_state (mut i32) i32.const 0) + + ;; This is a sample adapter which is adapting between ABI. This exact function + ;; signature is imported by `module.wat` and we're implementing it here with a + ;; canonical-abi function that returns two integers. The canonical ABI for + ;; returning two integers is different than the ABI of this function, hence + ;; the adapter here. + ;; + ;; The purpose of this test case is to exercise the `$__stack_pointer` global. + ;; The stack pointer here needs to be initialized to something valid for + ;; this adapter module which is done with an injected `start` function into + ;; this adapter module when it's bundled into a component. + (func (export "get_sum") (result i32) + (local i32 i32) + + ;; `wit-component` should have injected a call to a function that allocates + ;; the stack and sets $allocation_state to 2 + (if (i32.ne (global.get $allocation_state) (i32.const 2)) (then (unreachable))) + + ;; First, allocate a page using $cabi_realloc and write to it. This tests + ;; that we can use the main module's allocator if present (or else a + ;; substitute synthesized by `wit-component`). + (local.set 0 + (call $cabi_realloc + (i32.const 0) + (i32.const 0) + (i32.const 8) + (i32.const 65536))) + + (i32.store (local.get 0) (i32.const 42)) + (i32.store offset=65532 (local.get 0) (i32.const 42)) + + ;; Allocate 8 bytes of stack space for the two u32 return values. The + ;; original stack pointer is saved in local 0 and the stack frame for this + ;; function is saved in local 1. + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + + ;; Call the imported function which will return two u32 values into the + ;; return pointer specified here, our stack frame. + local.get 1 + call $get_two + + ;; Compute the result of this function by adding together the two return + ;; values. + (i32.add + (i32.load (local.get 1)) + (i32.load offset=4 (local.get 1))) + + ;; Test that if there is another mutable global in this module that it + ;; doesn't affect the detection of the stack pointer. This extra mutable + ;; global should not be initialized or tampered with as part of the + ;; initialize-the-stack-pointer injected function + (global.set $some_other_mutable_global (global.get $some_other_mutable_global)) + + ;; Restore the stack pointer to the value it was at prior to entering this + ;; function. + local.get 0 + global.set $__stack_pointer + ) + +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/adapt-old.wit b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/adapt-old.wit new file mode 100644 index 0000000000..a9f798e81e --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + get-two: func() -> (a: u32, b: u32); + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/component.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/component.wat new file mode 100644 index 0000000000..d9b2d8838e --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/component.wat @@ -0,0 +1,199 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (result "a" u32) (result "b" u32))) + (export (;0;) "get-two" (func (type 0))) + ) + ) + (import "new" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "old" "get_sum" (func (;0;) (type 0))) + (func $cabi_realloc (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + (local i32) + i32.const 0 + local.get 0 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 0 + local.get 1 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 65536 + local.get 3 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 1 + memory.grow + local.tee 4 + i32.const -1 + i32.eq + if ;; label = @1 + unreachable + end + local.get 4 + i32.const 16 + i32.shl + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func $cabi_realloc)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func)) + (import "env" "memory" (memory (;0;) 0)) + (import "new" "get-two" (func $get_two (;0;) (type 0))) + (import "__main_module__" "cabi_realloc" (func $cabi_realloc (;1;) (type 1))) + (func (;2;) (type 2) (result i32) + (local i32 i32) + call $allocate_stack + global.get $allocation_state + i32.const 2 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $cabi_realloc + local.set 0 + local.get 0 + i32.const 42 + i32.store + local.get 0 + i32.const 42 + i32.store offset=65532 + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + local.get 1 + call $get_two + local.get 1 + i32.load + local.get 1 + i32.load offset=4 + i32.add + global.get $some_other_mutable_global + global.set $some_other_mutable_global + local.get 0 + global.set $__stack_pointer + ) + (func $allocate_stack (;3;) (type 3) + global.get $allocation_state + i32.const 0 + i32.eq + if ;; label = @1 + i32.const 1 + global.set $allocation_state + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $cabi_realloc + i32.const 65536 + i32.add + global.set $__stack_pointer + i32.const 2 + global.set $allocation_state + end + ) + (global $__stack_pointer (;0;) (mut i32) i32.const 0) + (global $some_other_mutable_global (;1;) (mut i32) i32.const 0) + (global $allocation_state (;2;) (mut i32) i32.const 0) + (export "get_sum" (func 2)) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (func $indirect-new-get-two (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-old-get_sum (;1;) (type 1) (result i32) + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-new-get-two)) + (export "1" (func $adapt-old-get_sum)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "get_sum" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;1;))) + (alias core export 2 "cabi_realloc" (core func (;2;))) + (core instance (;3;) + (export "cabi_realloc" (func 2)) + ) + (core instance (;4;) + (export "memory" (memory 0)) + ) + (alias core export 0 "0" (core func (;3;))) + (core instance (;5;) + (export "get-two" (func 3)) + ) + (core instance (;6;) (instantiate 1 + (with "__main_module__" (instance 3)) + (with "env" (instance 4)) + (with "new" (instance 5)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "get-two" (func (;0;))) + (core func (;4;) (canon lower (func 0) (memory 0))) + (alias core export 6 "get_sum" (core func (;5;))) + (core instance (;7;) + (export "$imports" (table 0)) + (export "0" (func 4)) + (export "1" (func 5)) + ) + (core instance (;8;) (instantiate 3 + (with "" (instance 7)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/component.wit.print b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/component.wit.print new file mode 100644 index 0000000000..b1f183513f --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import new: interface { + get-two: func() -> (a: u32, b: u32) + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/module.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/module.wat new file mode 100644 index 0000000000..bf7e135842 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/module.wat @@ -0,0 +1,38 @@ +(module + (import "old" "get_sum" (func (result i32))) + ;; Minimal realloc which only accepts new, page-sized allocations: + (func $cabi_realloc (param i32 i32 i32 i32) (result i32) + (local i32) + i32.const 0 + local.get 0 + i32.ne + if + unreachable + end + i32.const 0 + local.get 1 + i32.ne + if + unreachable + end + i32.const 65536 + local.get 3 + i32.ne + if + unreachable + end + i32.const 1 + memory.grow + local.tee 4 + i32.const -1 + i32.eq + if + unreachable + end + local.get 4 + i32.const 16 + i32.shl + ) + (memory (export "memory") 1) + (export "cabi_realloc" (func $cabi_realloc)) +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/module.wit b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/module.wit new file mode 100644 index 0000000000..c54087df30 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-realloc/module.wit @@ -0,0 +1,3 @@ +package foo:foo; + +world module {} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/adapt-old.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/adapt-old.wat new file mode 100644 index 0000000000..6626b29b7c --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/adapt-old.wat @@ -0,0 +1,62 @@ +(module + (import "new" "get-two" (func $get_two (param i32))) + (import "env" "memory" (memory 0)) + + (global $__stack_pointer (mut i32) i32.const 0) + (global $some_other_mutable_global (mut i32) i32.const 0) + + ;; `wit-component` should use this to track the status of a lazy stack + ;; allocation: + (global $allocation_state (mut i32) i32.const 0) + + ;; This is a sample adapter which is adapting between ABI. This exact function + ;; signature is imported by `module.wat` and we're implementing it here with a + ;; canonical-abi function that returns two integers. The canonical ABI for + ;; returning two integers is different than the ABI of this function, hence + ;; the adapter here. + ;; + ;; The purpose of this test case is to exercise the `$__stack_pointer` global. + ;; The stack pointer here needs to be initialized to something valid for + ;; this adapter module which is done with an injected `start` function into + ;; this adapter module when it's bundled into a component. + (func (export "get_sum") (result i32) + (local i32 i32) + + ;; `wit-component` should have injected a call to a function that allocates + ;; the stack and sets $allocation_state to 2 + (if (i32.ne (global.get $allocation_state) (i32.const 2)) (then (unreachable))) + + ;; Allocate 8 bytes of stack space for the two u32 return values. The + ;; original stack pointer is saved in local 0 and the stack frame for this + ;; function is saved in local 1. + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + + ;; Call the imported function which will return two u32 values into the + ;; return pointer specified here, our stack frame. + local.get 1 + call $get_two + + ;; Compute the result of this function by adding together the two return + ;; values. + (i32.add + (i32.load (local.get 1)) + (i32.load offset=4 (local.get 1))) + + ;; Test that if there is another mutable global in this module that it + ;; doesn't affect the detection of the stack pointer. This extra mutable + ;; global should not be initialized or tampered with as part of the + ;; initialize-the-stack-pointer injected function + (global.set $some_other_mutable_global (global.get $some_other_mutable_global)) + + ;; Restore the stack pointer to the value it was at prior to entering this + ;; function. + local.get 0 + global.set $__stack_pointer + ) + +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/adapt-old.wit b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/adapt-old.wit new file mode 100644 index 0000000000..a9f798e81e --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + get-two: func() -> (a: u32, b: u32); + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/component.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/component.wat new file mode 100644 index 0000000000..46410b80fb --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/component.wat @@ -0,0 +1,187 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (result "a" u32) (result "b" u32))) + (export (;0;) "get-two" (func (type 0))) + ) + ) + (import "new" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "old" "get_sum" (func (;0;) (type 0))) + (func $cabi_realloc (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + (local i32) + i32.const 0 + local.get 0 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 0 + local.get 1 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 65536 + local.get 3 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 1 + memory.grow + local.tee 4 + i32.const -1 + i32.eq + if ;; label = @1 + unreachable + end + local.get 4 + i32.const 16 + i32.shl + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func $cabi_realloc)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32 i32 i32 i32) (result i32))) + (type (;3;) (func)) + (import "env" "memory" (memory (;0;) 0)) + (import "new" "get-two" (func $get_two (;0;) (type 0))) + (import "__main_module__" "cabi_realloc" (func $cabi_realloc (;1;) (type 2))) + (func (;2;) (type 1) (result i32) + (local i32 i32) + call $allocate_stack + global.get $allocation_state + i32.const 2 + i32.ne + if ;; label = @1 + unreachable + end + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + local.get 1 + call $get_two + local.get 1 + i32.load + local.get 1 + i32.load offset=4 + i32.add + global.get $some_other_mutable_global + global.set $some_other_mutable_global + local.get 0 + global.set $__stack_pointer + ) + (func $allocate_stack (;3;) (type 3) + global.get $allocation_state + i32.const 0 + i32.eq + if ;; label = @1 + i32.const 1 + global.set $allocation_state + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $cabi_realloc + i32.const 65536 + i32.add + global.set $__stack_pointer + i32.const 2 + global.set $allocation_state + end + ) + (global $__stack_pointer (;0;) (mut i32) i32.const 0) + (global $some_other_mutable_global (;1;) (mut i32) i32.const 0) + (global $allocation_state (;2;) (mut i32) i32.const 0) + (export "get_sum" (func 2)) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (func $indirect-new-get-two (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-old-get_sum (;1;) (type 1) (result i32) + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-new-get-two)) + (export "1" (func $adapt-old-get_sum)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "get_sum" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;1;))) + (alias core export 2 "cabi_realloc" (core func (;2;))) + (core instance (;3;) + (export "cabi_realloc" (func 2)) + ) + (core instance (;4;) + (export "memory" (memory 0)) + ) + (alias core export 0 "0" (core func (;3;))) + (core instance (;5;) + (export "get-two" (func 3)) + ) + (core instance (;6;) (instantiate 1 + (with "__main_module__" (instance 3)) + (with "env" (instance 4)) + (with "new" (instance 5)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "get-two" (func (;0;))) + (core func (;4;) (canon lower (func 0) (memory 0))) + (alias core export 6 "get_sum" (core func (;5;))) + (core instance (;7;) + (export "$imports" (table 0)) + (export "0" (func 4)) + (export "1" (func 5)) + ) + (core instance (;8;) (instantiate 3 + (with "" (instance 7)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/component.wit.print b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/component.wit.print new file mode 100644 index 0000000000..b1f183513f --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import new: interface { + get-two: func() -> (a: u32, b: u32) + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/module.wat b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/module.wat new file mode 100644 index 0000000000..bf7e135842 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/module.wat @@ -0,0 +1,38 @@ +(module + (import "old" "get_sum" (func (result i32))) + ;; Minimal realloc which only accepts new, page-sized allocations: + (func $cabi_realloc (param i32 i32 i32 i32) (result i32) + (local i32) + i32.const 0 + local.get 0 + i32.ne + if + unreachable + end + i32.const 0 + local.get 1 + i32.ne + if + unreachable + end + i32.const 65536 + local.get 3 + i32.ne + if + unreachable + end + i32.const 1 + memory.grow + local.tee 4 + i32.const -1 + i32.eq + if + unreachable + end + local.get 4 + i32.const 16 + i32.shl + ) + (memory (export "memory") 1) + (export "cabi_realloc" (func $cabi_realloc)) +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/module.wit b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack-with-reallocing-adapter/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/adapt-inject-stack/adapt-old.wat b/crates/wit-component/tests/components/adapt-inject-stack/adapt-old.wat new file mode 100644 index 0000000000..9699792d5b --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack/adapt-old.wat @@ -0,0 +1,54 @@ +(module + (import "new" "get-two" (func $get_two (param i32))) + (import "env" "memory" (memory 0)) + + (global $__stack_pointer (mut i32) i32.const 0) + (global $some_other_mutable_global (mut i32) i32.const 0) + + ;; This is a sample adapter which is adapting between ABI. This exact function + ;; signature is imported by `module.wat` and we're implementing it here with a + ;; canonical-abi function that returns two integers. The canonical ABI for + ;; returning two integers is different than the ABI of this function, hence + ;; the adapter here. + ;; + ;; The purpose of this test case is to exercise the `$__stack_pointer` global. + ;; The stack pointer here needs to be initialized to something valid for + ;; this adapter module which is done with an injected `start` function into + ;; this adapter module when it's bundled into a component. + (func (export "get_sum") (result i32) + (local i32 i32) + + ;; Allocate 8 bytes of stack space for the two u32 return values. The + ;; original stack pointer is saved in local 0 and the stack frame for this + ;; function is saved in local 1. + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + + ;; Call the imported function which will return two u32 values into the + ;; return pointer specified here, our stack frame. + local.get 1 + call $get_two + + ;; Compute the result of this function by adding together the two return + ;; values. + (i32.add + (i32.load (local.get 1)) + (i32.load offset=4 (local.get 1))) + + ;; Test that if there is another mutable global in this module that it + ;; doesn't affect the detection of the stack pointer. This extra mutable + ;; global should not be initialized or tampered with as part of the + ;; initialize-the-stack-pointer injected function + (global.set $some_other_mutable_global (global.get $some_other_mutable_global)) + + ;; Restore the stack pointer to the value it was at prior to entering this + ;; function. + local.get 0 + global.set $__stack_pointer + ) + +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack/adapt-old.wit b/crates/wit-component/tests/components/adapt-inject-stack/adapt-old.wit new file mode 100644 index 0000000000..a9f798e81e --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + get-two: func() -> (a: u32, b: u32); + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack/component.wat b/crates/wit-component/tests/components/adapt-inject-stack/component.wat new file mode 100644 index 0000000000..fed4d96511 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack/component.wat @@ -0,0 +1,162 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (result "a" u32) (result "b" u32))) + (export (;0;) "get-two" (func (type 0))) + ) + ) + (import "new" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (result i32))) + (import "old" "get_sum" (func (;0;) (type 0))) + (memory (;0;) 1) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32 i32 i32 i32) (result i32))) + (type (;3;) (func)) + (import "env" "memory" (memory (;0;) 0)) + (import "new" "get-two" (func $get_two (;0;) (type 0))) + (func (;1;) (type 1) (result i32) + (local i32 i32) + global.get $__stack_pointer + local.tee 0 + i32.const 8 + i32.sub + local.tee 1 + global.set $__stack_pointer + local.get 1 + call $get_two + local.get 1 + i32.load + local.get 1 + i32.load offset=4 + i32.add + global.get $some_other_mutable_global + global.set $some_other_mutable_global + local.get 0 + global.set $__stack_pointer + ) + (func $realloc_via_memory_grow (;2;) (type 2) (param i32 i32 i32 i32) (result i32) + (local i32) + i32.const 0 + local.get 0 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 0 + local.get 1 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 65536 + local.get 3 + i32.ne + if ;; label = @1 + unreachable + end + i32.const 1 + memory.grow + local.tee 4 + i32.const -1 + i32.eq + if ;; label = @1 + unreachable + end + local.get 4 + i32.const 16 + i32.shl + ) + (func $allocate_stack (;3;) (type 3) + i32.const 0 + i32.const 0 + i32.const 8 + i32.const 65536 + call $realloc_via_memory_grow + i32.const 65536 + i32.add + global.set $__stack_pointer + ) + (global $__stack_pointer (;0;) (mut i32) i32.const 0) + (global $some_other_mutable_global (;1;) (mut i32) i32.const 0) + (export "get_sum" (func 1)) + (start $allocate_stack) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (func $indirect-new-get-two (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-old-get_sum (;1;) (type 1) (result i32) + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-new-get-two)) + (export "1" (func $adapt-old-get_sum)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "get_sum" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (core instance (;3;) + (export "memory" (memory 0)) + ) + (alias core export 0 "0" (core func (;1;))) + (core instance (;4;) + (export "get-two" (func 1)) + ) + (core instance (;5;) (instantiate 1 + (with "env" (instance 3)) + (with "new" (instance 4)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "get-two" (func (;0;))) + (core func (;2;) (canon lower (func 0) (memory 0))) + (alias core export 5 "get_sum" (core func (;3;))) + (core instance (;6;) + (export "$imports" (table 0)) + (export "0" (func 2)) + (export "1" (func 3)) + ) + (core instance (;7;) (instantiate 3 + (with "" (instance 6)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-inject-stack/component.wit.print b/crates/wit-component/tests/components/adapt-inject-stack/component.wit.print new file mode 100644 index 0000000000..b1f183513f --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import new: interface { + get-two: func() -> (a: u32, b: u32) + } +} diff --git a/crates/wit-component/tests/components/adapt-inject-stack/module.wat b/crates/wit-component/tests/components/adapt-inject-stack/module.wat new file mode 100644 index 0000000000..9fd5ac0fcb --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack/module.wat @@ -0,0 +1,4 @@ +(module + (import "old" "get_sum" (func (result i32))) + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/adapt-inject-stack/module.wit b/crates/wit-component/tests/components/adapt-inject-stack/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-inject-stack/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/adapt-list-return/adapt-old.wat b/crates/wit-component/tests/components/adapt-list-return/adapt-old.wat new file mode 100644 index 0000000000..9a451b7bca --- /dev/null +++ b/crates/wit-component/tests/components/adapt-list-return/adapt-old.wat @@ -0,0 +1,14 @@ +(module + (import "new" "read" (func $read (param i32))) + (import "env" "memory" (memory 0)) + + (func (export "read") (param i32 i32) + i32.const 8 + call $read + unreachable + ) + + (func (export "cabi_import_realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) +) diff --git a/crates/wit-component/tests/components/adapt-list-return/adapt-old.wit b/crates/wit-component/tests/components/adapt-list-return/adapt-old.wit new file mode 100644 index 0000000000..693bd57eb3 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-list-return/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + read: func() -> list; + } +} diff --git a/crates/wit-component/tests/components/adapt-list-return/component.wat b/crates/wit-component/tests/components/adapt-list-return/component.wat new file mode 100644 index 0000000000..68aa2ec0d3 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-list-return/component.wat @@ -0,0 +1,104 @@ +(component + (type (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (func (result 0))) + (export (;0;) "read" (func (type 1))) + ) + ) + (import "new" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32 i32))) + (import "old" "read" (func (;0;) (type 0))) + (memory (;0;) 1) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32))) + (type (;2;) (func (param i32 i32 i32 i32) (result i32))) + (import "new" "read" (func $read (;0;) (type 0))) + (func (;1;) (type 1) (param i32 i32) + i32.const 8 + call $read + unreachable + ) + (func (;2;) (type 2) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (export "read" (func 1)) + (export "cabi_import_realloc" (func 2)) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32))) + (func $indirect-new-read (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-old-read (;1;) (type 1) (param i32 i32) + local.get 0 + local.get 1 + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-new-read)) + (export "1" (func $adapt-old-read)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "read" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 0 "0" (core func (;1;))) + (core instance (;3;) + (export "read" (func 1)) + ) + (core instance (;4;) (instantiate 1 + (with "new" (instance 3)) + ) + ) + (alias core export 4 "cabi_import_realloc" (core func (;2;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "read" (func (;0;))) + (core func (;3;) (canon lower (func 0) (memory 0) (realloc 2))) + (alias core export 4 "read" (core func (;4;))) + (core instance (;5;) + (export "$imports" (table 0)) + (export "0" (func 3)) + (export "1" (func 4)) + ) + (core instance (;6;) (instantiate 3 + (with "" (instance 5)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-list-return/component.wit.print b/crates/wit-component/tests/components/adapt-list-return/component.wit.print new file mode 100644 index 0000000000..6a5d7c87d0 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-list-return/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import new: interface { + read: func() -> list + } +} diff --git a/crates/wit-component/tests/components/adapt-list-return/module.wat b/crates/wit-component/tests/components/adapt-list-return/module.wat new file mode 100644 index 0000000000..e68c95b08f --- /dev/null +++ b/crates/wit-component/tests/components/adapt-list-return/module.wat @@ -0,0 +1,4 @@ +(module + (import "old" "read" (func (param i32 i32))) + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/adapt-list-return/module.wit b/crates/wit-component/tests/components/adapt-list-return/module.wit new file mode 100644 index 0000000000..c54087df30 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-list-return/module.wit @@ -0,0 +1,3 @@ +package foo:foo; + +world module {} diff --git a/crates/wit-component/tests/components/adapt-memory-simple/adapt-old.wat b/crates/wit-component/tests/components/adapt-memory-simple/adapt-old.wat new file mode 100644 index 0000000000..deb5d349d6 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-memory-simple/adapt-old.wat @@ -0,0 +1,4 @@ +(module + (import "new" "log" (func $log (param i32 i32))) + (export "log" (func $log)) +) diff --git a/crates/wit-component/tests/components/adapt-memory-simple/adapt-old.wit b/crates/wit-component/tests/components/adapt-memory-simple/adapt-old.wit new file mode 100644 index 0000000000..5e15bfaeb0 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-memory-simple/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + log: func(s: string); + } +} diff --git a/crates/wit-component/tests/components/adapt-memory-simple/component.wat b/crates/wit-component/tests/components/adapt-memory-simple/component.wat new file mode 100644 index 0000000000..59e9e1636d --- /dev/null +++ b/crates/wit-component/tests/components/adapt-memory-simple/component.wat @@ -0,0 +1,90 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "s" string))) + (export (;0;) "log" (func (type 0))) + ) + ) + (import "new" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32 i32))) + (import "old" "log" (func (;0;) (type 0))) + (memory (;0;) 1) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32 i32))) + (import "new" "log" (func $log (;0;) (type 0))) + (export "log" (func $log)) + ) + (core module (;2;) + (type (;0;) (func (param i32 i32))) + (func $indirect-new-log (;0;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-old-log (;1;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 1 + call_indirect (type 0) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-new-log)) + (export "1" (func $adapt-old-log)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32 i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "log" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "old" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 0 "0" (core func (;1;))) + (core instance (;3;) + (export "log" (func 1)) + ) + (core instance (;4;) (instantiate 1 + (with "new" (instance 3)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "log" (func (;0;))) + (core func (;2;) (canon lower (func 0) (memory 0) string-encoding=utf8)) + (alias core export 4 "log" (core func (;3;))) + (core instance (;5;) + (export "$imports" (table 0)) + (export "0" (func 2)) + (export "1" (func 3)) + ) + (core instance (;6;) (instantiate 3 + (with "" (instance 5)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-memory-simple/component.wit.print b/crates/wit-component/tests/components/adapt-memory-simple/component.wit.print new file mode 100644 index 0000000000..e7996e6e9e --- /dev/null +++ b/crates/wit-component/tests/components/adapt-memory-simple/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import new: interface { + log: func(s: string) + } +} diff --git a/crates/wit-component/tests/components/adapt-memory-simple/module.wat b/crates/wit-component/tests/components/adapt-memory-simple/module.wat new file mode 100644 index 0000000000..5bdcb0eaf1 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-memory-simple/module.wat @@ -0,0 +1,4 @@ +(module + (import "old" "log" (func (param i32 i32))) + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/adapt-memory-simple/module.wit b/crates/wit-component/tests/components/adapt-memory-simple/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-memory-simple/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/adapt-multiple/adapt-foo.wat b/crates/wit-component/tests/components/adapt-multiple/adapt-foo.wat new file mode 100644 index 0000000000..e9ea200e97 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-multiple/adapt-foo.wat @@ -0,0 +1,10 @@ +;; this is a polyfill module that translates from wasi-preview1 to a different +;; interface + +(module + (import "other1" "foo" (func $foo)) + (import "other2" "bar" (func $bar)) + + (func (export "foo") call $foo) + (func (export "bar") call $bar) +) diff --git a/crates/wit-component/tests/components/adapt-multiple/adapt-foo.wit b/crates/wit-component/tests/components/adapt-multiple/adapt-foo.wit new file mode 100644 index 0000000000..6949592da6 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-multiple/adapt-foo.wit @@ -0,0 +1,8 @@ +world adapt-foo { + import other1: interface { + foo: func(); + } + import other2: interface { + bar: func(); + } +} diff --git a/crates/wit-component/tests/components/adapt-multiple/component.wat b/crates/wit-component/tests/components/adapt-multiple/component.wat new file mode 100644 index 0000000000..092448ccf5 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-multiple/component.wat @@ -0,0 +1,107 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import "other1" (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (func)) + (export (;0;) "bar" (func (type 0))) + ) + ) + (import "other2" (instance (;1;) (type 1))) + (core module (;0;) + (type (;0;) (func)) + (import "foo" "foo" (func (;0;) (type 0))) + (import "foo" "bar" (func (;1;) (type 0))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func)) + (import "other1" "foo" (func $foo (;0;) (type 0))) + (import "other2" "bar" (func $bar (;1;) (type 0))) + (func (;2;) (type 0) + call $foo + ) + (func (;3;) (type 0) + call $bar + ) + (export "foo" (func 2)) + (export "bar" (func 3)) + ) + (core module (;2;) + (type (;0;) (func)) + (func $adapt-foo-foo (;0;) (type 0) + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-foo-bar (;1;) (type 0) + i32.const 1 + call_indirect (type 0) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $adapt-foo-foo)) + (export "1" (func $adapt-foo-bar)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func)) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias core export 0 "0" (core func (;0;))) + (alias core export 0 "1" (core func (;1;))) + (core instance (;1;) + (export "foo" (func 0)) + (export "bar" (func 1)) + ) + (core instance (;2;) (instantiate 0 + (with "foo" (instance 1)) + ) + ) + (alias export 0 "foo" (func (;0;))) + (core func (;2;) (canon lower (func 0))) + (core instance (;3;) + (export "foo" (func 2)) + ) + (alias export 1 "bar" (func (;1;))) + (core func (;3;) (canon lower (func 1))) + (core instance (;4;) + (export "bar" (func 3)) + ) + (core instance (;5;) (instantiate 1 + (with "other1" (instance 3)) + (with "other2" (instance 4)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias core export 5 "foo" (core func (;4;))) + (alias core export 5 "bar" (core func (;5;))) + (core instance (;6;) + (export "$imports" (table 0)) + (export "0" (func 4)) + (export "1" (func 5)) + ) + (core instance (;7;) (instantiate 3 + (with "" (instance 6)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-multiple/component.wit.print b/crates/wit-component/tests/components/adapt-multiple/component.wit.print new file mode 100644 index 0000000000..bfdb507a66 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-multiple/component.wit.print @@ -0,0 +1,10 @@ +package root:component + +world root { + import other1: interface { + foo: func() + } + import other2: interface { + bar: func() + } +} diff --git a/crates/wit-component/tests/components/adapt-multiple/module.wat b/crates/wit-component/tests/components/adapt-multiple/module.wat new file mode 100644 index 0000000000..eb5951a168 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-multiple/module.wat @@ -0,0 +1,4 @@ +(module + (import "foo" "foo" (func)) + (import "foo" "bar" (func)) +) diff --git a/crates/wit-component/tests/components/adapt-multiple/module.wit b/crates/wit-component/tests/components/adapt-multiple/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-multiple/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/adapt-preview1/adapt-wasi-snapshot-preview1.wat b/crates/wit-component/tests/components/adapt-preview1/adapt-wasi-snapshot-preview1.wat new file mode 100644 index 0000000000..0b9abe3ad5 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-preview1/adapt-wasi-snapshot-preview1.wat @@ -0,0 +1,13 @@ +;; this is a polyfill module that translates from wasi-preview1 to a different +;; interface + +(module + (import "foo:foo/my-wasi" "proc-exit" (func $proc_exit (param i32))) + (func (export "proc_exit") (param i32) + local.get 0 + call $proc_exit + ) + (func (export "random_get") (param i32 i32) (result i32) + i32.const 0) + (func (export "something_else")) +) diff --git a/crates/wit-component/tests/components/adapt-preview1/adapt-wasi-snapshot-preview1.wit b/crates/wit-component/tests/components/adapt-preview1/adapt-wasi-snapshot-preview1.wit new file mode 100644 index 0000000000..0c67747396 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-preview1/adapt-wasi-snapshot-preview1.wit @@ -0,0 +1,12 @@ +// This is the interface imported by the `adapt-*.wat` file which is used +// to implement the `wasi_snapshot_preview1` interface. + +interface my-wasi { + random-get: func(size: u32) -> list; + proc-exit: func(code: u32); + something-not-used: func(); +} + +world adapt-wasi-snapshot-preview1 { + import my-wasi; +} diff --git a/crates/wit-component/tests/components/adapt-preview1/component.wat b/crates/wit-component/tests/components/adapt-preview1/component.wat new file mode 100644 index 0000000000..31c1410b5f --- /dev/null +++ b/crates/wit-component/tests/components/adapt-preview1/component.wat @@ -0,0 +1,119 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import "foo" (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (func (param "code" u32))) + (export (;0;) "proc-exit" (func (type 0))) + ) + ) + (import (interface "foo:foo/my-wasi") (instance (;1;) (type 1))) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i32 i32) (result i32))) + (import "foo" "foo" (func (;0;) (type 0))) + (import "wasi-snapshot-preview1" "proc_exit" (func (;1;) (type 1))) + (import "wasi-snapshot-preview1" "random_get" (func (;2;) (type 2))) + (memory (;0;) 1) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (import "foo:foo/my-wasi" "proc-exit" (func $proc_exit (;0;) (type 0))) + (func (;1;) (type 0) (param i32) + local.get 0 + call $proc_exit + ) + (func (;2;) (type 1) (param i32 i32) (result i32) + i32.const 0 + ) + (export "proc_exit" (func 1)) + (export "random_get" (func 2)) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (func $adapt-wasi-snapshot-preview1-proc_exit (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-wasi-snapshot-preview1-random_get (;1;) (type 1) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $adapt-wasi-snapshot-preview1-proc_exit)) + (export "1" (func $adapt-wasi-snapshot-preview1-random_get)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias export 0 "foo" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;1;) + (export "foo" (func 0)) + ) + (alias core export 0 "0" (core func (;1;))) + (alias core export 0 "1" (core func (;2;))) + (core instance (;2;) + (export "proc_exit" (func 1)) + (export "random_get" (func 2)) + ) + (core instance (;3;) (instantiate 0 + (with "foo" (instance 1)) + (with "wasi-snapshot-preview1" (instance 2)) + ) + ) + (alias core export 3 "memory" (core memory (;0;))) + (alias export 1 "proc-exit" (func (;1;))) + (core func (;3;) (canon lower (func 1))) + (core instance (;4;) + (export "proc-exit" (func 3)) + ) + (core instance (;5;) (instantiate 1 + (with "foo:foo/my-wasi" (instance 4)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias core export 5 "proc_exit" (core func (;4;))) + (alias core export 5 "random_get" (core func (;5;))) + (core instance (;6;) + (export "$imports" (table 0)) + (export "0" (func 4)) + (export "1" (func 5)) + ) + (core instance (;7;) (instantiate 3 + (with "" (instance 6)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-preview1/component.wit.print b/crates/wit-component/tests/components/adapt-preview1/component.wit.print new file mode 100644 index 0000000000..617992bb3e --- /dev/null +++ b/crates/wit-component/tests/components/adapt-preview1/component.wit.print @@ -0,0 +1,8 @@ +package root:component + +world root { + import foo: interface { + foo: func() + } + import foo:foo/my-wasi +} diff --git a/crates/wit-component/tests/components/adapt-preview1/module.wat b/crates/wit-component/tests/components/adapt-preview1/module.wat new file mode 100644 index 0000000000..70449b7e35 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-preview1/module.wat @@ -0,0 +1,11 @@ +(module + ;; import something from an external interface + (import "foo" "foo" (func)) + + ;; import some wasi functions + (import "wasi-snapshot-preview1" "proc_exit" (func (param i32))) + (import "wasi-snapshot-preview1" "random_get" (func (param i32 i32) (result i32))) + + ;; required by wasi + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/adapt-preview1/module.wit b/crates/wit-component/tests/components/adapt-preview1/module.wit new file mode 100644 index 0000000000..7e0d241f3b --- /dev/null +++ b/crates/wit-component/tests/components/adapt-preview1/module.wit @@ -0,0 +1,7 @@ +package foo:foo; + +world module { + import foo: interface { + foo: func(); + } +} diff --git a/crates/wit-component/tests/components/adapt-unused/adapt-old.wat b/crates/wit-component/tests/components/adapt-unused/adapt-old.wat new file mode 100644 index 0000000000..deb5d349d6 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-unused/adapt-old.wat @@ -0,0 +1,4 @@ +(module + (import "new" "log" (func $log (param i32 i32))) + (export "log" (func $log)) +) diff --git a/crates/wit-component/tests/components/adapt-unused/adapt-old.wit b/crates/wit-component/tests/components/adapt-unused/adapt-old.wit new file mode 100644 index 0000000000..5e15bfaeb0 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-unused/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + log: func(s: string); + } +} diff --git a/crates/wit-component/tests/components/adapt-unused/component.wat b/crates/wit-component/tests/components/adapt-unused/component.wat new file mode 100644 index 0000000000..e40a4d41be --- /dev/null +++ b/crates/wit-component/tests/components/adapt-unused/component.wat @@ -0,0 +1,12 @@ +(component + (core module (;0;) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/adapt-unused/component.wit.print b/crates/wit-component/tests/components/adapt-unused/component.wit.print new file mode 100644 index 0000000000..bcd860d376 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-unused/component.wit.print @@ -0,0 +1,4 @@ +package root:component + +world root { +} diff --git a/crates/wit-component/tests/components/adapt-unused/module.wat b/crates/wit-component/tests/components/adapt-unused/module.wat new file mode 100644 index 0000000000..3af8f25454 --- /dev/null +++ b/crates/wit-component/tests/components/adapt-unused/module.wat @@ -0,0 +1 @@ +(module) diff --git a/crates/wit-component/tests/components/adapt-unused/module.wit b/crates/wit-component/tests/components/adapt-unused/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/adapt-unused/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/bare-funcs/component.wat b/crates/wit-component/tests/components/bare-funcs/component.wat new file mode 100644 index 0000000000..41b08eb88c --- /dev/null +++ b/crates/wit-component/tests/components/bare-funcs/component.wat @@ -0,0 +1,93 @@ +(component + (type (;0;) (func)) + (import "foo" (func (;0;) (type 0))) + (type (;1;) (func (result string))) + (import "bar" (func (;1;) (type 1))) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i32 i32) (result i32))) + (type (;3;) (func (param i32 i32 i32 i32) (result i32))) + (import "$root" "foo" (func (;0;) (type 0))) + (import "$root" "bar" (func (;1;) (type 1))) + (func (;2;) (type 0)) + (func (;3;) (type 2) (param i32 i32) (result i32) + unreachable + ) + (func (;4;) (type 1) (param i32) + unreachable + ) + (func (;5;) (type 3) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 1) + (export "baz" (func 2)) + (export "foo2" (func 3)) + (export "cabi_post_foo2" (func 4)) + (export "cabi_realloc" (func 5)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (func $indirect-$root-bar (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (table (;0;) 1 1 funcref) + (export "0" (func $indirect-$root-bar)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "$imports" (table (;0;) 1 1 funcref)) + (elem (;0;) (i32.const 0) func 0) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 1)) + (core func (;0;) (canon lower (func 0))) + (alias core export 0 "0" (core func (;1;))) + (core instance (;1;) + (export "foo" (func 0)) + (export "bar" (func 1)) + ) + (core instance (;2;) (instantiate 0 + (with "$root" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;2;))) + (alias core export 0 "$imports" (core table (;0;))) + (core func (;3;) (canon lower (func 1) (memory 0) (realloc 2) string-encoding=utf8)) + (core instance (;3;) + (export "$imports" (table 0)) + (export "0" (func 3)) + ) + (core instance (;4;) (instantiate 2 + (with "" (instance 3)) + ) + ) + (alias core export 2 "baz" (core func (;4;))) + (func (;2;) (type 0) (canon lift (core func 4))) + (export (;3;) "baz" (func 2)) + (type (;2;) (list u8)) + (type (;3;) (option 2)) + (type (;4;) (func (param "x" string) (result 3))) + (alias core export 2 "foo2" (core func (;5;))) + (alias core export 2 "cabi_post_foo2" (core func (;6;))) + (func (;4;) (type 4) (canon lift (core func 5) (memory 0) (realloc 2) string-encoding=utf8 (post-return 6))) + (export (;5;) "foo2" (func 4)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/bare-funcs/component.wit.print b/crates/wit-component/tests/components/bare-funcs/component.wit.print new file mode 100644 index 0000000000..34767c7ec0 --- /dev/null +++ b/crates/wit-component/tests/components/bare-funcs/component.wit.print @@ -0,0 +1,9 @@ +package root:component + +world root { + import foo: func() + import bar: func() -> string + + export baz: func() + export foo2: func(x: string) -> option> +} diff --git a/crates/wit-component/tests/components/bare-funcs/module.wat b/crates/wit-component/tests/components/bare-funcs/module.wat new file mode 100644 index 0000000000..e4d079e46d --- /dev/null +++ b/crates/wit-component/tests/components/bare-funcs/module.wat @@ -0,0 +1,13 @@ +(module + (import "$root" "foo" (func)) + (import "$root" "bar" (func (param i32))) + + (func (export "baz")) + + (func (export "foo2") (param i32 i32) (result i32) unreachable) + (func (export "cabi_post_foo2") (param i32) unreachable) + + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/bare-funcs/module.wit b/crates/wit-component/tests/components/bare-funcs/module.wit new file mode 100644 index 0000000000..69b0534e1b --- /dev/null +++ b/crates/wit-component/tests/components/bare-funcs/module.wit @@ -0,0 +1,7 @@ +package foo:foo; +world module { + import foo: func(); + import bar: func() -> string; + export baz: func(); + export foo2: func(x: string) -> option>; +} diff --git a/crates/wit-component/tests/components/empty/component.wat b/crates/wit-component/tests/components/empty/component.wat new file mode 100644 index 0000000000..e40a4d41be --- /dev/null +++ b/crates/wit-component/tests/components/empty/component.wat @@ -0,0 +1,12 @@ +(component + (core module (;0;) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/empty/component.wit.print b/crates/wit-component/tests/components/empty/component.wit.print new file mode 100644 index 0000000000..bcd860d376 --- /dev/null +++ b/crates/wit-component/tests/components/empty/component.wit.print @@ -0,0 +1,4 @@ +package root:component + +world root { +} diff --git a/crates/wit-component/tests/components/empty/module.wat b/crates/wit-component/tests/components/empty/module.wat new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/crates/wit-component/tests/components/empty/module.wat @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/crates/wit-component/tests/components/empty/module.wit b/crates/wit-component/tests/components/empty/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/empty/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/ensure-default-type-exports/component.wat b/crates/wit-component/tests/components/ensure-default-type-exports/component.wat new file mode 100644 index 0000000000..5c1b5670c5 --- /dev/null +++ b/crates/wit-component/tests/components/ensure-default-type-exports/component.wat @@ -0,0 +1,50 @@ +(component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "foo" (type (eq 0))) + (type (;2;) (record (field "x" 1))) + (export (;3;) "bar" (type (eq 2))) + (type (;4;) (func (param "b" 3))) + (export (;0;) "a" (func (type 4))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo:foo/foo" "a" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;2;) (type 0) (param i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 1)) + (export "a" (func 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "a" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;0;) + (export "a" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "foo:foo/foo" (instance 0)) + ) + ) + (alias core export 1 "memory" (core memory (;0;))) + (alias core export 1 "cabi_realloc" (core func (;1;))) + (type (;1;) (func (param "b" u8))) + (alias core export 1 "a" (core func (;2;))) + (func (;1;) (type 1) (canon lift (core func 2))) + (export (;2;) "a" (func 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/ensure-default-type-exports/component.wit.print b/crates/wit-component/tests/components/ensure-default-type-exports/component.wit.print new file mode 100644 index 0000000000..f207bfb86b --- /dev/null +++ b/crates/wit-component/tests/components/ensure-default-type-exports/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import foo:foo/foo + + export a: func(b: u8) +} diff --git a/crates/wit-component/tests/components/ensure-default-type-exports/module.wat b/crates/wit-component/tests/components/ensure-default-type-exports/module.wat new file mode 100644 index 0000000000..711b2a1449 --- /dev/null +++ b/crates/wit-component/tests/components/ensure-default-type-exports/module.wat @@ -0,0 +1,6 @@ +(module + (import "foo:foo/foo" "a" (func (param i32))) + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "a") (param i32) unreachable) +) diff --git a/crates/wit-component/tests/components/ensure-default-type-exports/module.wit b/crates/wit-component/tests/components/ensure-default-type-exports/module.wit new file mode 100644 index 0000000000..6a484a55b8 --- /dev/null +++ b/crates/wit-component/tests/components/ensure-default-type-exports/module.wit @@ -0,0 +1,17 @@ +package foo:foo; + +interface foo { + type foo = u8; + + record bar { + x: foo + } + + a: func(b: bar); +} + +world module { + import foo; + + export a: func(b: u8); +} diff --git a/crates/wit-component/tests/components/error-adapt-missing-memory/adapt-old.wat b/crates/wit-component/tests/components/error-adapt-missing-memory/adapt-old.wat new file mode 100644 index 0000000000..deb5d349d6 --- /dev/null +++ b/crates/wit-component/tests/components/error-adapt-missing-memory/adapt-old.wat @@ -0,0 +1,4 @@ +(module + (import "new" "log" (func $log (param i32 i32))) + (export "log" (func $log)) +) diff --git a/crates/wit-component/tests/components/error-adapt-missing-memory/adapt-old.wit b/crates/wit-component/tests/components/error-adapt-missing-memory/adapt-old.wit new file mode 100644 index 0000000000..5e15bfaeb0 --- /dev/null +++ b/crates/wit-component/tests/components/error-adapt-missing-memory/adapt-old.wit @@ -0,0 +1,5 @@ +world adapt-old { + import new: interface { + log: func(s: string); + } +} diff --git a/crates/wit-component/tests/components/error-adapt-missing-memory/error.txt b/crates/wit-component/tests/components/error-adapt-missing-memory/error.txt new file mode 100644 index 0000000000..33946ad755 --- /dev/null +++ b/crates/wit-component/tests/components/error-adapt-missing-memory/error.txt @@ -0,0 +1 @@ +module does not export a memory named `memory` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-adapt-missing-memory/module.wat b/crates/wit-component/tests/components/error-adapt-missing-memory/module.wat new file mode 100644 index 0000000000..1a705ff1a3 --- /dev/null +++ b/crates/wit-component/tests/components/error-adapt-missing-memory/module.wat @@ -0,0 +1,3 @@ +(module + (import "old" "log" (func (param i32 i32))) +) diff --git a/crates/wit-component/tests/components/error-adapt-missing-memory/module.wit b/crates/wit-component/tests/components/error-adapt-missing-memory/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/error-adapt-missing-memory/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt b/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt new file mode 100644 index 0000000000..b7a8e003cd --- /dev/null +++ b/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt @@ -0,0 +1 @@ +type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-default-export-sig-mismatch/module.wat b/crates/wit-component/tests/components/error-default-export-sig-mismatch/module.wat new file mode 100644 index 0000000000..38ea217899 --- /dev/null +++ b/crates/wit-component/tests/components/error-default-export-sig-mismatch/module.wat @@ -0,0 +1,3 @@ +(module + (func (export "a") unreachable) +) diff --git a/crates/wit-component/tests/components/error-default-export-sig-mismatch/module.wit b/crates/wit-component/tests/components/error-default-export-sig-mismatch/module.wit new file mode 100644 index 0000000000..2d67f95819 --- /dev/null +++ b/crates/wit-component/tests/components/error-default-export-sig-mismatch/module.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world module { + export a: func(x: string) -> string; +} diff --git a/crates/wit-component/tests/components/error-empty-module-import/error.txt b/crates/wit-component/tests/components/error-empty-module-import/error.txt new file mode 100644 index 0000000000..3fc2443a8a --- /dev/null +++ b/crates/wit-component/tests/components/error-empty-module-import/error.txt @@ -0,0 +1 @@ +no top-level imported function `foo` specified \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-empty-module-import/module.wat b/crates/wit-component/tests/components/error-empty-module-import/module.wat new file mode 100644 index 0000000000..1c1b1ac527 --- /dev/null +++ b/crates/wit-component/tests/components/error-empty-module-import/module.wat @@ -0,0 +1,3 @@ +(module + (import "$root" "foo" (func)) +) diff --git a/crates/wit-component/tests/components/error-empty-module-import/module.wit b/crates/wit-component/tests/components/error-empty-module-import/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/error-empty-module-import/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt b/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt new file mode 100644 index 0000000000..d2226ac3d9 --- /dev/null +++ b/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt @@ -0,0 +1,4 @@ +failed to validate exported interface `foo` + +Caused by: + type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-export-sig-mismatch/module.wat b/crates/wit-component/tests/components/error-export-sig-mismatch/module.wat new file mode 100644 index 0000000000..8a8e12b4ac --- /dev/null +++ b/crates/wit-component/tests/components/error-export-sig-mismatch/module.wat @@ -0,0 +1,3 @@ +(module + (func (export "foo#a") unreachable) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-export-sig-mismatch/module.wit b/crates/wit-component/tests/components/error-export-sig-mismatch/module.wit new file mode 100644 index 0000000000..f904f9271d --- /dev/null +++ b/crates/wit-component/tests/components/error-export-sig-mismatch/module.wit @@ -0,0 +1,7 @@ +package foo:foo; + +world module { + export foo: interface { + a: func(x: string) -> string; + } +} diff --git a/crates/wit-component/tests/components/error-import-resource-rep/error.txt b/crates/wit-component/tests/components/error-import-resource-rep/error.txt new file mode 100644 index 0000000000..5a9a5e1804 --- /dev/null +++ b/crates/wit-component/tests/components/error-import-resource-rep/error.txt @@ -0,0 +1 @@ +no top-level imported function `[resource-rep]a` specified \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-import-resource-rep/module.wat b/crates/wit-component/tests/components/error-import-resource-rep/module.wat new file mode 100644 index 0000000000..791c84cfb5 --- /dev/null +++ b/crates/wit-component/tests/components/error-import-resource-rep/module.wat @@ -0,0 +1,3 @@ +(module + (import "$root" "[resource-rep]a" (func (param i32) (result i32))) +) diff --git a/crates/wit-component/tests/components/error-import-resource-rep/module.wit b/crates/wit-component/tests/components/error-import-resource-rep/module.wit new file mode 100644 index 0000000000..1223c43e6c --- /dev/null +++ b/crates/wit-component/tests/components/error-import-resource-rep/module.wit @@ -0,0 +1,5 @@ +package foo:bar; + +world module { + resource a; +} diff --git a/crates/wit-component/tests/components/error-import-resource-wrong-signature/error.txt b/crates/wit-component/tests/components/error-import-resource-wrong-signature/error.txt new file mode 100644 index 0000000000..205e848e6a --- /dev/null +++ b/crates/wit-component/tests/components/error-import-resource-wrong-signature/error.txt @@ -0,0 +1 @@ +type mismatch for function `[resource-drop]a`: expected `[I32] -> []` but found `[I32] -> [I32]` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-import-resource-wrong-signature/module.wat b/crates/wit-component/tests/components/error-import-resource-wrong-signature/module.wat new file mode 100644 index 0000000000..c4423f75c3 --- /dev/null +++ b/crates/wit-component/tests/components/error-import-resource-wrong-signature/module.wat @@ -0,0 +1,3 @@ +(module + (import "$root" "[resource-drop]a" (func (param i32) (result i32))) +) diff --git a/crates/wit-component/tests/components/error-import-resource-wrong-signature/module.wit b/crates/wit-component/tests/components/error-import-resource-wrong-signature/module.wit new file mode 100644 index 0000000000..1223c43e6c --- /dev/null +++ b/crates/wit-component/tests/components/error-import-resource-wrong-signature/module.wit @@ -0,0 +1,5 @@ +package foo:bar; + +world module { + resource a; +} diff --git a/crates/wit-component/tests/components/error-import-sig-mismatch/error.txt b/crates/wit-component/tests/components/error-import-sig-mismatch/error.txt new file mode 100644 index 0000000000..7a6fd7d4e0 --- /dev/null +++ b/crates/wit-component/tests/components/error-import-sig-mismatch/error.txt @@ -0,0 +1,4 @@ +failed to validate import interface `foo` + +Caused by: + type mismatch for function `bar`: expected `[I32, I32] -> []` but found `[] -> []` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-import-sig-mismatch/module.wat b/crates/wit-component/tests/components/error-import-sig-mismatch/module.wat new file mode 100644 index 0000000000..96d3790b9c --- /dev/null +++ b/crates/wit-component/tests/components/error-import-sig-mismatch/module.wat @@ -0,0 +1,3 @@ +(module + (import "foo" "bar" (func)) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-import-sig-mismatch/module.wit b/crates/wit-component/tests/components/error-import-sig-mismatch/module.wit new file mode 100644 index 0000000000..2d963fb9e2 --- /dev/null +++ b/crates/wit-component/tests/components/error-import-sig-mismatch/module.wit @@ -0,0 +1,7 @@ +package foo:foo; + +world module { + import foo: interface { + bar: func(s: string); + } +} diff --git a/crates/wit-component/tests/components/error-invalid-module-import/error.txt b/crates/wit-component/tests/components/error-invalid-module-import/error.txt new file mode 100644 index 0000000000..9d9f35c0fa --- /dev/null +++ b/crates/wit-component/tests/components/error-invalid-module-import/error.txt @@ -0,0 +1 @@ +module is only allowed to import functions \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-invalid-module-import/module.wat b/crates/wit-component/tests/components/error-invalid-module-import/module.wat new file mode 100644 index 0000000000..2768b75dc4 --- /dev/null +++ b/crates/wit-component/tests/components/error-invalid-module-import/module.wat @@ -0,0 +1,3 @@ +(module + (import "" "" (table 1 funcref)) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-invalid-module-import/module.wit b/crates/wit-component/tests/components/error-invalid-module-import/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/error-invalid-module-import/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/error-link-duplicate-initializers/error.txt b/crates/wit-component/tests/components/error-link-duplicate-initializers/error.txt new file mode 100644 index 0000000000..86de6c15e1 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-initializers/error.txt @@ -0,0 +1 @@ +library foo exports both `__wasm_call_ctors` and `_initialize`; expected at most one of the two diff --git a/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-bar.wat b/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-bar.wat new file mode 100644 index 0000000000..d6be27aecb --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-bar.wat @@ -0,0 +1,12 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (needed "foo") + ) + (type (func (param i32) (result i32))) + (import "env" "foo" (func $import_foo (type 0))) + (func $bar (type 0) (param i32) (result i32) + unreachable + ) + (export "bar" (func $bar)) +) diff --git a/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-bar.wit b/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-bar.wit new file mode 100644 index 0000000000..ad16c9bf4c --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-bar.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-bar { } diff --git a/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-foo.wat b/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-foo.wat new file mode 100644 index 0000000000..a7395dfead --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-foo.wat @@ -0,0 +1,21 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (needed "bar") + ) + (type (func (param i32) (result i32))) + (type (func)) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (import "env" "foo" (func $import_foo2 (type 0))) + (import "env" "bar" (func $import_bar (type 0))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (func $_initialize (type 1) + unreachable + ) + (export "test:test/test#foo" (func $foo)) + (export "foo" (func $foo)) + (export "_initialize" (func $_initialize)) + (export "__wasm_call_ctors" (func $_initialize)) +) diff --git a/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-foo.wit b/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-foo.wit new file mode 100644 index 0000000000..576de43434 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-initializers/lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/error-link-duplicate-symbols/error.txt b/crates/wit-component/tests/components/error-link-duplicate-symbols/error.txt new file mode 100644 index 0000000000..1765e8e491 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-symbols/error.txt @@ -0,0 +1,3 @@ +duplicate symbol(s): + bar needs foo (function [I32] -> [I32]), provided by bar, foo + foo needs foo (function [I32] -> [I32]), provided by bar, foo \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-bar.wat b/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-bar.wat new file mode 100644 index 0000000000..6347ed0af5 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-bar.wat @@ -0,0 +1,13 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (needed "foo") + ) + (type (func (param i32) (result i32))) + (import "env" "foo" (func $import_foo (type 0))) + (func $bar (type 0) (param i32) (result i32) + unreachable + ) + (export "bar" (func $bar)) + (export "foo" (func $bar)) +) diff --git a/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-bar.wit b/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-bar.wit new file mode 100644 index 0000000000..ad16c9bf4c --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-bar.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-bar { } diff --git a/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-foo.wat b/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-foo.wat new file mode 100644 index 0000000000..bae469a0bf --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-foo.wat @@ -0,0 +1,15 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (needed "bar") + ) + (type (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (import "env" "foo" (func $import_foo2 (type 0))) + (import "env" "bar" (func $import_bar (type 0))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) + (export "foo" (func $foo)) +) diff --git a/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-foo.wit b/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-foo.wit new file mode 100644 index 0000000000..576de43434 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-duplicate-symbols/lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/error-link-missing-needed/error.txt b/crates/wit-component/tests/components/error-link-missing-needed/error.txt new file mode 100644 index 0000000000..508d1bd9c6 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-missing-needed/error.txt @@ -0,0 +1,2 @@ +missing libraries: + foo needs bar \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-link-missing-needed/lib-foo.wat b/crates/wit-component/tests/components/error-link-missing-needed/lib-foo.wat new file mode 100644 index 0000000000..bae469a0bf --- /dev/null +++ b/crates/wit-component/tests/components/error-link-missing-needed/lib-foo.wat @@ -0,0 +1,15 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (needed "bar") + ) + (type (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (import "env" "foo" (func $import_foo2 (type 0))) + (import "env" "bar" (func $import_bar (type 0))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) + (export "foo" (func $foo)) +) diff --git a/crates/wit-component/tests/components/error-link-missing-needed/lib-foo.wit b/crates/wit-component/tests/components/error-link-missing-needed/lib-foo.wit new file mode 100644 index 0000000000..576de43434 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-missing-needed/lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/error-link-missing-symbols/error.txt b/crates/wit-component/tests/components/error-link-missing-symbols/error.txt new file mode 100644 index 0000000000..c991edeebf --- /dev/null +++ b/crates/wit-component/tests/components/error-link-missing-symbols/error.txt @@ -0,0 +1,3 @@ +unresolved symbol(s): + foo needs bar (function [I32] -> [I32]) + foo needs foo (function [I32] -> [I32]) \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-link-missing-symbols/lib-foo.wat b/crates/wit-component/tests/components/error-link-missing-symbols/lib-foo.wat new file mode 100644 index 0000000000..0e47f33480 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-missing-symbols/lib-foo.wat @@ -0,0 +1,13 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (import "env" "foo" (func $import_foo2 (type 0))) + (import "env" "bar" (func $import_bar (type 0))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) +) diff --git a/crates/wit-component/tests/components/error-link-missing-symbols/lib-foo.wit b/crates/wit-component/tests/components/error-link-missing-symbols/lib-foo.wit new file mode 100644 index 0000000000..576de43434 --- /dev/null +++ b/crates/wit-component/tests/components/error-link-missing-symbols/lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/error-missing-default-export/error.txt b/crates/wit-component/tests/components/error-missing-default-export/error.txt new file mode 100644 index 0000000000..8368ada353 --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-default-export/error.txt @@ -0,0 +1 @@ +module does not export required function `a` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-default-export/module.wat b/crates/wit-component/tests/components/error-missing-default-export/module.wat new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-default-export/module.wat @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-default-export/module.wit b/crates/wit-component/tests/components/error-missing-default-export/module.wit new file mode 100644 index 0000000000..7ed84b55d7 --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-default-export/module.wit @@ -0,0 +1,4 @@ +package foo:foo; +world module { + export a: func(); +} diff --git a/crates/wit-component/tests/components/error-missing-export/error.txt b/crates/wit-component/tests/components/error-missing-export/error.txt new file mode 100644 index 0000000000..afcfb4e22f --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-export/error.txt @@ -0,0 +1,4 @@ +failed to validate exported interface `foo` + +Caused by: + module does not export required function `foo#a` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-export/module.wat b/crates/wit-component/tests/components/error-missing-export/module.wat new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-export/module.wat @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-export/module.wit b/crates/wit-component/tests/components/error-missing-export/module.wit new file mode 100644 index 0000000000..758adc097c --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-export/module.wit @@ -0,0 +1,7 @@ +package foo:foo; + +world module { + export foo: interface { + a: func(); + } +} diff --git a/crates/wit-component/tests/components/error-missing-import-func/error.txt b/crates/wit-component/tests/components/error-missing-import-func/error.txt new file mode 100644 index 0000000000..b4d2327fb5 --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-import-func/error.txt @@ -0,0 +1 @@ +module requires an import interface named `foo` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-import-func/module.wat b/crates/wit-component/tests/components/error-missing-import-func/module.wat new file mode 100644 index 0000000000..96d3790b9c --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-import-func/module.wat @@ -0,0 +1,3 @@ +(module + (import "foo" "bar" (func)) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-import-func/module.wit b/crates/wit-component/tests/components/error-missing-import-func/module.wit new file mode 100644 index 0000000000..4d21ad6e1b --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-import-func/module.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface foo { + a: func(); +} + +world module { + import foo; +} diff --git a/crates/wit-component/tests/components/error-missing-import/error.txt b/crates/wit-component/tests/components/error-missing-import/error.txt new file mode 100644 index 0000000000..b4d2327fb5 --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-import/error.txt @@ -0,0 +1 @@ +module requires an import interface named `foo` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-import/module.wat b/crates/wit-component/tests/components/error-missing-import/module.wat new file mode 100644 index 0000000000..96d3790b9c --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-import/module.wat @@ -0,0 +1,3 @@ +(module + (import "foo" "bar" (func)) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-import/module.wit b/crates/wit-component/tests/components/error-missing-import/module.wit new file mode 100644 index 0000000000..f5d68f90db --- /dev/null +++ b/crates/wit-component/tests/components/error-missing-import/module.wit @@ -0,0 +1,2 @@ +package foo:foo; +world module {} diff --git a/crates/wit-component/tests/components/export-interface-using-import/component.wat b/crates/wit-component/tests/components/export-interface-using-import/component.wat new file mode 100644 index 0000000000..27571287bb --- /dev/null +++ b/crates/wit-component/tests/components/export-interface-using-import/component.wat @@ -0,0 +1,36 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "f" u32))) + (export (;1;) "f" (type (eq 0))) + (type (;2;) (record (field "f" 1))) + (export (;3;) "r" (type (eq 2))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (core module (;0;) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias export 0 "f" (type (;1;))) + (alias export 0 "r" (type (;2;))) + (component (;0;) + (type (;0;) (record (field "f" u32))) + (import "import-type-f" (type (;1;) (eq 0))) + (type (;2;) (record (field "f" 1))) + (import "import-type-r" (type (;3;) (eq 2))) + (export (;4;) "r" (type 3)) + ) + (instance (;1;) (instantiate 0 + (with "import-type-f" (type 1)) + (with "import-type-r" (type 2)) + ) + ) + (export (;2;) "x" (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/export-interface-using-import/component.wit.print b/crates/wit-component/tests/components/export-interface-using-import/component.wit.print new file mode 100644 index 0000000000..7e05cc1df5 --- /dev/null +++ b/crates/wit-component/tests/components/export-interface-using-import/component.wit.print @@ -0,0 +1,9 @@ +package root:component + +world root { + import foo:foo/foo + + export x: interface { + use foo:foo/foo.{r} + } +} diff --git a/crates/wit-component/tests/components/export-interface-using-import/module.wat b/crates/wit-component/tests/components/export-interface-using-import/module.wat new file mode 100644 index 0000000000..3af8f25454 --- /dev/null +++ b/crates/wit-component/tests/components/export-interface-using-import/module.wat @@ -0,0 +1 @@ +(module) diff --git a/crates/wit-component/tests/components/export-interface-using-import/module.wit b/crates/wit-component/tests/components/export-interface-using-import/module.wit new file mode 100644 index 0000000000..4a771a6c39 --- /dev/null +++ b/crates/wit-component/tests/components/export-interface-using-import/module.wit @@ -0,0 +1,17 @@ +package foo:foo; + +interface foo { + record f { + f: u32, + } + + record r { + f: f, + } +} + +world module { + export x: interface { + use foo.{r}; + } +} diff --git a/crates/wit-component/tests/components/export-name-shuffling/component.wat b/crates/wit-component/tests/components/export-name-shuffling/component.wat new file mode 100644 index 0000000000..64c505a0fb --- /dev/null +++ b/crates/wit-component/tests/components/export-name-shuffling/component.wat @@ -0,0 +1,42 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param i32)) + (export "name#a" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (component (;0;) + (type (;0;) (record (field "f" u32))) + (export (;1;) "foo" (type 0)) + ) + (instance (;0;) (instantiate 0)) + (export (;1;) (interface "foo:foo/name") (instance 0)) + (alias export 1 "foo" (type (;0;))) + (type (;1;) (func (param "f" 0))) + (alias core export 0 "name#a" (core func (;0;))) + (func (;0;) (type 1) (canon lift (core func 0))) + (component (;1;) + (type (;0;) (record (field "f" u32))) + (import "import-type-foo" (type (;1;) (eq 0))) + (import "import-type-foo0" (type (;2;) (eq 1))) + (type (;3;) (func (param "f" 2))) + (import "import-func-a" (func (;0;) (type 3))) + (export (;4;) "foo" (type 1)) + (type (;5;) (func (param "f" 4))) + (export (;1;) "a" (func 0) (func (type 5))) + ) + (instance (;2;) (instantiate 1 + (with "import-func-a" (func 0)) + (with "import-type-foo" (type 0)) + (with "import-type-foo0" (type 0)) + ) + ) + (export (;3;) "name" (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/export-name-shuffling/component.wit.print b/crates/wit-component/tests/components/export-name-shuffling/component.wit.print new file mode 100644 index 0000000000..801ed92221 --- /dev/null +++ b/crates/wit-component/tests/components/export-name-shuffling/component.wit.print @@ -0,0 +1,10 @@ +package root:component + +world root { + export foo:foo/name + export name: interface { + use foo:foo/name.{foo} + + a: func(f: foo) + } +} diff --git a/crates/wit-component/tests/components/export-name-shuffling/module.wat b/crates/wit-component/tests/components/export-name-shuffling/module.wat new file mode 100644 index 0000000000..e78a1a7947 --- /dev/null +++ b/crates/wit-component/tests/components/export-name-shuffling/module.wat @@ -0,0 +1,3 @@ +(module + (func (export "name#a") (param i32)) +) diff --git a/crates/wit-component/tests/components/export-name-shuffling/module.wit b/crates/wit-component/tests/components/export-name-shuffling/module.wit new file mode 100644 index 0000000000..c38a7646ca --- /dev/null +++ b/crates/wit-component/tests/components/export-name-shuffling/module.wit @@ -0,0 +1,17 @@ +package foo:foo; + +interface name { + record foo { + f: u32, + } +} + +world module { + export name; + + export name: interface { + use name.{foo}; + + a: func(f: foo); + } +} diff --git a/crates/wit-component/tests/components/export-resource/component.wat b/crates/wit-component/tests/components/export-resource/component.wat new file mode 100644 index 0000000000..be46eae285 --- /dev/null +++ b/crates/wit-component/tests/components/export-resource/component.wat @@ -0,0 +1,102 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32))) + (type (;2;) (func (result i32))) + (import "[export]foo" "[resource-new]a" (func $new (;0;) (type 0))) + (import "[export]foo" "[resource-rep]a" (func (;1;) (type 0))) + (import "[export]foo" "[resource-drop]a" (func (;2;) (type 1))) + (func (;3;) (type 2) (result i32) + i32.const 100 + call $new + ) + (func (;4;) (type 2) (result i32) + i32.const 200 + call $new + ) + (func (;5;) (type 1) (param i32)) + (export "foo#[constructor]a" (func 3)) + (export "foo#[static]a.other-new" (func 4)) + (export "foo#[dtor]a" (func 5)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (func $#func0 (@name "dtor-[export]foo-a") (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (table (;0;) 1 1 funcref) + (export "0" (func $#func0)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "$imports" (table (;0;) 1 1 funcref)) + (elem (;0;) (i32.const 0) func 0) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 1)) + (alias core export 0 "0" (core func (;0;))) + (type (;0;) (resource (rep i32) (dtor (func 0)))) + (core func (;1;) (canon resource.drop 0)) + (core func (;2;) (canon resource.rep 0)) + (core func (;3;) (canon resource.new 0)) + (core instance (;1;) + (export "[resource-drop]a" (func 1)) + (export "[resource-rep]a" (func 2)) + (export "[resource-new]a" (func 3)) + ) + (core instance (;2;) (instantiate 0 + (with "[export]foo" (instance 1)) + ) + ) + (alias core export 0 "$imports" (core table (;0;))) + (alias core export 2 "foo#[dtor]a" (core func (;4;))) + (core instance (;3;) + (export "$imports" (table 0)) + (export "0" (func 4)) + ) + (core instance (;4;) (instantiate 2 + (with "" (instance 3)) + ) + ) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (alias core export 2 "foo#[constructor]a" (core func (;5;))) + (func (;0;) (type 2) (canon lift (core func 5))) + (alias core export 2 "foo#[static]a.other-new" (core func (;6;))) + (func (;1;) (type 2) (canon lift (core func 6))) + (component (;0;) + (import "import-type-a" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (import "import-constructor-a" (func (;0;) (type 2))) + (import "import-static-a-other-new" (func (;1;) (type 2))) + (export (;3;) "a" (type 0)) + (type (;4;) (own 3)) + (type (;5;) (func (result 4))) + (export (;2;) "[constructor]a" (func 0) (func (type 5))) + (export (;3;) "[static]a.other-new" (func 1) (func (type 5))) + ) + (instance (;0;) (instantiate 0 + (with "import-constructor-a" (func 0)) + (with "import-static-a-other-new" (func 1)) + (with "import-type-a" (type 0)) + ) + ) + (export (;1;) "foo" (instance 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/export-resource/component.wit.print b/crates/wit-component/tests/components/export-resource/component.wit.print new file mode 100644 index 0000000000..2c9acee66c --- /dev/null +++ b/crates/wit-component/tests/components/export-resource/component.wit.print @@ -0,0 +1,10 @@ +package root:component + +world root { + export foo: interface { + resource a { + constructor() + other-new: static func() -> a + } + } +} diff --git a/crates/wit-component/tests/components/export-resource/module.wat b/crates/wit-component/tests/components/export-resource/module.wat new file mode 100644 index 0000000000..d2f641c70e --- /dev/null +++ b/crates/wit-component/tests/components/export-resource/module.wat @@ -0,0 +1,15 @@ +(module + (import "[export]foo" "[resource-new]a" (func $new (param i32) (result i32))) + (import "[export]foo" "[resource-rep]a" (func (param i32) (result i32))) + (import "[export]foo" "[resource-drop]a" (func (param i32))) + + (func (export "foo#[constructor]a") (result i32) + (call $new (i32.const 100)) + ) + (func (export "foo#[static]a.other-new") (result i32) + (call $new (i32.const 200)) + ) + (func (export "foo#[dtor]a") (param i32) + ;; ... + ) +) diff --git a/crates/wit-component/tests/components/export-resource/module.wit b/crates/wit-component/tests/components/export-resource/module.wit new file mode 100644 index 0000000000..58d9f4c2f9 --- /dev/null +++ b/crates/wit-component/tests/components/export-resource/module.wit @@ -0,0 +1,11 @@ +package foo:bar; + +world module { + export foo: interface { + resource a { + constructor(); + + other-new: static func() -> a; + } + } +} diff --git a/crates/wit-component/tests/components/export-type-name-conflict/component.wat b/crates/wit-component/tests/components/export-type-name-conflict/component.wat new file mode 100644 index 0000000000..8864fd4c89 --- /dev/null +++ b/crates/wit-component/tests/components/export-type-name-conflict/component.wat @@ -0,0 +1,46 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "foo" (type (eq 0))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + unreachable + ) + (export "bar#foo" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias export 0 "foo" (type (;1;))) + (type (;2;) (func (result 1))) + (alias core export 0 "bar#foo" (core func (;0;))) + (func (;0;) (type 2) (canon lift (core func 0))) + (alias export 0 "foo" (type (;3;))) + (component (;0;) + (type (;0;) (record (field "f" u8))) + (import "import-type-foo" (type (;1;) (eq 0))) + (import "import-type-bar" (type (;2;) (eq 1))) + (type (;3;) (func (result 2))) + (import "import-func-foo" (func (;0;) (type 3))) + (export (;4;) "bar" (type 1)) + (type (;5;) (func (result 4))) + (export (;1;) "foo" (func 0) (func (type 5))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-foo" (func 0)) + (with "import-type-foo" (type 3)) + (with "import-type-bar" (type 1)) + ) + ) + (export (;2;) "bar" (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/export-type-name-conflict/component.wit.print b/crates/wit-component/tests/components/export-type-name-conflict/component.wit.print new file mode 100644 index 0000000000..6622505e46 --- /dev/null +++ b/crates/wit-component/tests/components/export-type-name-conflict/component.wit.print @@ -0,0 +1,11 @@ +package root:component + +world root { + import foo:foo/foo + + export bar: interface { + use foo:foo/foo.{foo as bar} + + foo: func() -> bar + } +} diff --git a/crates/wit-component/tests/components/export-type-name-conflict/module.wat b/crates/wit-component/tests/components/export-type-name-conflict/module.wat new file mode 100644 index 0000000000..8107d33759 --- /dev/null +++ b/crates/wit-component/tests/components/export-type-name-conflict/module.wat @@ -0,0 +1,5 @@ +(module + (func (export "bar#foo") (result i32) + unreachable + ) +) diff --git a/crates/wit-component/tests/components/export-type-name-conflict/module.wit b/crates/wit-component/tests/components/export-type-name-conflict/module.wit new file mode 100644 index 0000000000..dcd67e6755 --- /dev/null +++ b/crates/wit-component/tests/components/export-type-name-conflict/module.wit @@ -0,0 +1,15 @@ +package foo:foo; + +interface foo { + record foo { + f: u8, + } +} + +world module { + export bar: interface { + use foo.{foo as bar}; + + foo: func() -> bar; + } +} diff --git a/crates/wit-component/tests/components/export-with-type-alias/component.wat b/crates/wit-component/tests/components/export-with-type-alias/component.wat new file mode 100644 index 0000000000..b967713899 --- /dev/null +++ b/crates/wit-component/tests/components/export-with-type-alias/component.wat @@ -0,0 +1,40 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + unreachable + ) + (export "foo:foo/foo#c" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (type (;0;) u8) + (type (;1;) (func (param "a" 0) (result 0))) + (alias core export 0 "foo:foo/foo#c" (core func (;0;))) + (func (;0;) (type 1) (canon lift (core func 0))) + (component (;0;) + (type (;0;) u8) + (import "import-type-a" (type (;1;) (eq 0))) + (import "import-type-b" (type (;2;) (eq 1))) + (type (;3;) (func (param "a" 1) (result 2))) + (import "import-func-c" (func (;0;) (type 3))) + (type (;4;) u8) + (export (;5;) "a" (type 4)) + (export (;6;) "b" (type 5)) + (type (;7;) (func (param "a" 5) (result 6))) + (export (;1;) "c" (func 0) (func (type 7))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-c" (func 0)) + (with "import-type-a" (type 0)) + (with "import-type-b" (type 0)) + ) + ) + (export (;1;) (interface "foo:foo/foo") (instance 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/export-with-type-alias/component.wit.print b/crates/wit-component/tests/components/export-with-type-alias/component.wit.print new file mode 100644 index 0000000000..62a65899a8 --- /dev/null +++ b/crates/wit-component/tests/components/export-with-type-alias/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + export foo:foo/foo +} diff --git a/crates/wit-component/tests/components/export-with-type-alias/module.wat b/crates/wit-component/tests/components/export-with-type-alias/module.wat new file mode 100644 index 0000000000..196f9c956a --- /dev/null +++ b/crates/wit-component/tests/components/export-with-type-alias/module.wat @@ -0,0 +1,3 @@ +(module + (func (export "foo:foo/foo#c") (param i32) (result i32) unreachable) +) diff --git a/crates/wit-component/tests/components/export-with-type-alias/module.wit b/crates/wit-component/tests/components/export-with-type-alias/module.wit new file mode 100644 index 0000000000..4fa6a7c627 --- /dev/null +++ b/crates/wit-component/tests/components/export-with-type-alias/module.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface foo { + type a = u8; + type b = a; + c: func(a: a) -> b; +} + +world module { + export foo; +} diff --git a/crates/wit-component/tests/components/exports/component.wat b/crates/wit-component/tests/components/exports/component.wat new file mode 100644 index 0000000000..536ac4aa84 --- /dev/null +++ b/crates/wit-component/tests/components/exports/component.wat @@ -0,0 +1,139 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32 i32 i32 i64) (result i32))) + (type (;3;) (func (param i32))) + (type (;4;) (func (result i32))) + (type (;5;) (func (param i32 i32) (result i32))) + (type (;6;) (func (param i32 i64 i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;1;) (type 1) + unreachable + ) + (func (;2;) (type 2) (param i32 i32 i32 i64) (result i32) + unreachable + ) + (func (;3;) (type 3) (param i32) + unreachable + ) + (func (;4;) (type 4) (result i32) + unreachable + ) + (func (;5;) (type 1) + unreachable + ) + (func (;6;) (type 5) (param i32 i32) (result i32) + unreachable + ) + (func (;7;) (type 3) (param i32) + unreachable + ) + (func (;8;) (type 6) (param i32 i64 i32) (result i32) + unreachable + ) + (func (;9;) (type 3) (param i32) + unreachable + ) + (func (;10;) (type 3) (param i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 0)) + (export "a" (func 1)) + (export "b" (func 2)) + (export "cabi_post_b" (func 3)) + (export "c" (func 4)) + (export "foo#a" (func 5)) + (export "foo#b" (func 6)) + (export "cabi_post_foo#b" (func 7)) + (export "foo#c" (func 8)) + (export "cabi_post_foo#c" (func 9)) + (export "bar#a" (func 10)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "cabi_realloc" (core func (;0;))) + (type (;0;) (func)) + (alias core export 0 "a" (core func (;1;))) + (func (;0;) (type 0) (canon lift (core func 1))) + (export (;1;) "a" (func 0)) + (type (;1;) (func (param "a" s8) (param "b" s16) (param "c" s32) (param "d" s64) (result string))) + (alias core export 0 "b" (core func (;2;))) + (alias core export 0 "cabi_post_b" (core func (;3;))) + (func (;2;) (type 1) (canon lift (core func 2) (memory 0) string-encoding=utf8 (post-return 3))) + (export (;3;) "b" (func 2)) + (type (;2;) (tuple s8 s16 s32 s64)) + (type (;3;) (func (result 2))) + (alias core export 0 "c" (core func (;4;))) + (func (;4;) (type 3) (canon lift (core func 4) (memory 0))) + (export (;5;) "c" (func 4)) + (type (;4;) (flags "a" "b" "c")) + (type (;5;) (func (param "x" 4))) + (alias core export 0 "bar#a" (core func (;5;))) + (func (;6;) (type 5) (canon lift (core func 5))) + (component (;0;) + (type (;0;) (flags "a" "b" "c")) + (import "import-type-x" (type (;1;) (eq 0))) + (type (;2;) (func (param "x" 1))) + (import "import-func-a" (func (;0;) (type 2))) + (type (;3;) (flags "a" "b" "c")) + (export (;4;) "x" (type 3)) + (type (;5;) (func (param "x" 4))) + (export (;1;) "a" (func 0) (func (type 5))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-a" (func 6)) + (with "import-type-x" (type 4)) + ) + ) + (export (;1;) "bar" (instance 0)) + (type (;6;) (func)) + (alias core export 0 "foo#a" (core func (;6;))) + (func (;7;) (type 6) (canon lift (core func 6))) + (type (;7;) (variant (case "a") (case "b" string) (case "c" s64))) + (type (;8;) (func (param "x" string) (result 7))) + (alias core export 0 "foo#b" (core func (;7;))) + (alias core export 0 "cabi_post_foo#b" (core func (;8;))) + (func (;8;) (type 8) (canon lift (core func 7) (memory 0) (realloc 0) string-encoding=utf8 (post-return 8))) + (type (;9;) (func (param "x" 7) (result string))) + (alias core export 0 "foo#c" (core func (;9;))) + (alias core export 0 "cabi_post_foo#c" (core func (;10;))) + (func (;9;) (type 9) (canon lift (core func 9) (memory 0) (realloc 0) string-encoding=utf8 (post-return 10))) + (component (;1;) + (type (;0;) (func)) + (import "import-func-a" (func (;0;) (type 0))) + (type (;1;) (variant (case "a") (case "b" string) (case "c" s64))) + (import "import-type-x" (type (;2;) (eq 1))) + (type (;3;) (func (param "x" string) (result 2))) + (import "import-func-b" (func (;1;) (type 3))) + (type (;4;) (func (param "x" 2) (result string))) + (import "import-func-c" (func (;2;) (type 4))) + (type (;5;) (variant (case "a") (case "b" string) (case "c" s64))) + (export (;6;) "x" (type 5)) + (type (;7;) (func)) + (export (;3;) "a" (func 0) (func (type 7))) + (type (;8;) (func (param "x" string) (result 6))) + (export (;4;) "b" (func 1) (func (type 8))) + (type (;9;) (func (param "x" 6) (result string))) + (export (;5;) "c" (func 2) (func (type 9))) + ) + (instance (;2;) (instantiate 1 + (with "import-func-a" (func 7)) + (with "import-func-b" (func 8)) + (with "import-func-c" (func 9)) + (with "import-type-x" (type 7)) + ) + ) + (export (;3;) "foo" (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/exports/component.wit.print b/crates/wit-component/tests/components/exports/component.wit.print new file mode 100644 index 0000000000..022edaa3b8 --- /dev/null +++ b/crates/wit-component/tests/components/exports/component.wit.print @@ -0,0 +1,29 @@ +package root:component + +world root { + export a: func() + export b: func(a: s8, b: s16, c: s32, d: s64) -> string + export c: func() -> tuple + export bar: interface { + flags x { + a, + b, + c, + } + + a: func(x: x) + } + export foo: interface { + variant x { + a, + b(string), + c(s64), + } + + a: func() + + b: func(x: string) -> x + + c: func(x: x) -> string + } +} diff --git a/crates/wit-component/tests/components/exports/module.wat b/crates/wit-component/tests/components/exports/module.wat new file mode 100644 index 0000000000..9b27109234 --- /dev/null +++ b/crates/wit-component/tests/components/exports/module.wat @@ -0,0 +1,14 @@ +(module + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "a") unreachable) + (func (export "b") (param i32 i32 i32 i64) (result i32) unreachable) + (func (export "cabi_post_b") (param i32) unreachable) + (func (export "c") (result i32) unreachable) + (func (export "foo#a") unreachable) + (func (export "foo#b") (param i32 i32) (result i32) unreachable) + (func (export "cabi_post_foo#b") (param i32) unreachable) + (func (export "foo#c") (param i32 i64 i32) (result i32) unreachable) + (func (export "cabi_post_foo#c") (param i32) unreachable) + (func (export "bar#a") (param i32) unreachable) +) diff --git a/crates/wit-component/tests/components/exports/module.wit b/crates/wit-component/tests/components/exports/module.wit new file mode 100644 index 0000000000..9e972320d2 --- /dev/null +++ b/crates/wit-component/tests/components/exports/module.wit @@ -0,0 +1,29 @@ +package foo:foo; + +world module { + export a: func(); + export b: func(a: s8, b: s16, c: s32, d: s64) -> string; + export c: func() -> tuple; + + export bar: interface { + flags x { + a, + b, + c + } + + a: func(x: x); + } + + export foo: interface { + variant x { + a, + b(string), + c(s64) + } + + a: func(); + b: func(x: string) -> x; + c: func(x: x) -> string; + } +} diff --git a/crates/wit-component/tests/components/import-and-export-resource/component.wat b/crates/wit-component/tests/components/import-and-export-resource/component.wat new file mode 100644 index 0000000000..7b6d6d402e --- /dev/null +++ b/crates/wit-component/tests/components/import-and-export-resource/component.wat @@ -0,0 +1,53 @@ +(component + (type (;0;) + (instance + (export (;0;) "a" (type (sub resource))) + ) + ) + (import (interface "foo:bar/foo") (instance (;0;) (type 0))) + (alias export 0 "a" (type (;1;))) + (import "a" (type (;2;) (eq 1))) + (core module (;0;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32) (result i32))) + (import "foo:bar/foo" "[resource-drop]a" (func (;0;) (type 0))) + (import "[export]foo:bar/foo" "[resource-drop]a" (func (;1;) (type 0))) + (import "[export]foo:bar/foo" "[resource-rep]a" (func (;2;) (type 1))) + (import "[export]foo:bar/foo" "[resource-new]a" (func (;3;) (type 1))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "a" (type (;3;))) + (core func (;0;) (canon resource.drop 3)) + (core instance (;0;) + (export "[resource-drop]a" (func 0)) + ) + (type (;4;) (resource (rep i32))) + (core func (;1;) (canon resource.drop 4)) + (core func (;2;) (canon resource.rep 4)) + (core func (;3;) (canon resource.new 4)) + (core instance (;1;) + (export "[resource-drop]a" (func 1)) + (export "[resource-rep]a" (func 2)) + (export "[resource-new]a" (func 3)) + ) + (core instance (;2;) (instantiate 0 + (with "foo:bar/foo" (instance 0)) + (with "[export]foo:bar/foo" (instance 1)) + ) + ) + (component (;0;) + (import "import-type-a" (type (;0;) (sub resource))) + (export (;1;) "a" (type 0)) + ) + (instance (;1;) (instantiate 0 + (with "import-type-a" (type 4)) + ) + ) + (export (;2;) (interface "foo:bar/foo") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-and-export-resource/component.wit.print b/crates/wit-component/tests/components/import-and-export-resource/component.wit.print new file mode 100644 index 0000000000..3714cd5772 --- /dev/null +++ b/crates/wit-component/tests/components/import-and-export-resource/component.wit.print @@ -0,0 +1,8 @@ +package root:component + +world root { + import foo:bar/foo + use foo:bar/foo.{a} + + export foo:bar/foo +} diff --git a/crates/wit-component/tests/components/import-and-export-resource/module.wat b/crates/wit-component/tests/components/import-and-export-resource/module.wat new file mode 100644 index 0000000000..a764f164c4 --- /dev/null +++ b/crates/wit-component/tests/components/import-and-export-resource/module.wat @@ -0,0 +1,6 @@ +(module + (import "foo:bar/foo" "[resource-drop]a" (func (param i32))) + (import "[export]foo:bar/foo" "[resource-drop]a" (func (param i32))) + (import "[export]foo:bar/foo" "[resource-rep]a" (func (param i32) (result i32))) + (import "[export]foo:bar/foo" "[resource-new]a" (func (param i32) (result i32))) +) diff --git a/crates/wit-component/tests/components/import-and-export-resource/module.wit b/crates/wit-component/tests/components/import-and-export-resource/module.wit new file mode 100644 index 0000000000..20bbbada62 --- /dev/null +++ b/crates/wit-component/tests/components/import-and-export-resource/module.wit @@ -0,0 +1,12 @@ +package foo:bar; + +interface foo { + resource a; +} + +world module { + import foo; + use foo.{a}; + + export foo; +} diff --git a/crates/wit-component/tests/components/import-conflict/component.wat b/crates/wit-component/tests/components/import-conflict/component.wat new file mode 100644 index 0000000000..6025efadad --- /dev/null +++ b/crates/wit-component/tests/components/import-conflict/component.wat @@ -0,0 +1,118 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "x" u64) (param "y" string))) + (export (;0;) "a" (func (type 0))) + ) + ) + (import (interface "foo:foo/bar") (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (list u8)) + (type (;1;) (func (param "x" 0) (result 0))) + (export (;0;) "baz" (func (type 1))) + ) + ) + (import (interface "foo:foo/baz") (instance (;1;) (type 1))) + (type (;2;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + ) + ) + (import (interface "foo:foo/foo") (instance (;2;) (type 2))) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i64 i32 i32))) + (type (;2;) (func (param i32 i32 i32))) + (type (;3;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo:foo/foo" "a" (func (;0;) (type 0))) + (import "foo:foo/bar" "a" (func (;1;) (type 1))) + (import "foo:foo/baz" "baz" (func (;2;) (type 2))) + (func (;3;) (type 3) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 3)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i64 i32 i32))) + (type (;1;) (func (param i32 i32 i32))) + (func $indirect-foo:foo/bar-a (;0;) (type 0) (param i64 i32 i32) + local.get 0 + local.get 1 + local.get 2 + i32.const 0 + call_indirect (type 0) + ) + (func $indirect-foo:foo/baz-baz (;1;) (type 1) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-foo:foo/bar-a)) + (export "1" (func $indirect-foo:foo/baz-baz)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (type (;0;) (func (param i64 i32 i32))) + (type (;1;) (func (param i32 i32 i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 1)) + (alias export 2 "a" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;1;) + (export "a" (func 0)) + ) + (alias core export 0 "0" (core func (;1;))) + (core instance (;2;) + (export "a" (func 1)) + ) + (alias core export 0 "1" (core func (;2;))) + (core instance (;3;) + (export "baz" (func 2)) + ) + (core instance (;4;) (instantiate 0 + (with "foo:foo/foo" (instance 1)) + (with "foo:foo/bar" (instance 2)) + (with "foo:foo/baz" (instance 3)) + ) + ) + (alias core export 4 "memory" (core memory (;0;))) + (alias core export 4 "cabi_realloc" (core func (;3;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "a" (func (;1;))) + (core func (;4;) (canon lower (func 1) (memory 0) string-encoding=utf8)) + (alias export 1 "baz" (func (;2;))) + (core func (;5;) (canon lower (func 2) (memory 0) (realloc 3))) + (core instance (;5;) + (export "$imports" (table 0)) + (export "0" (func 4)) + (export "1" (func 5)) + ) + (core instance (;6;) (instantiate 2 + (with "" (instance 5)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-conflict/component.wit.print b/crates/wit-component/tests/components/import-conflict/component.wit.print new file mode 100644 index 0000000000..40cd5d91f8 --- /dev/null +++ b/crates/wit-component/tests/components/import-conflict/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import foo:foo/bar + import foo:foo/baz + import foo:foo/foo +} diff --git a/crates/wit-component/tests/components/import-conflict/module.wat b/crates/wit-component/tests/components/import-conflict/module.wat new file mode 100644 index 0000000000..b0b2aa640c --- /dev/null +++ b/crates/wit-component/tests/components/import-conflict/module.wat @@ -0,0 +1,7 @@ +(module + (import "foo:foo/foo" "a" (func)) + (import "foo:foo/bar" "a" (func (param i64 i32 i32))) + (import "foo:foo/baz" "baz" (func (param i32 i32 i32))) + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) +) diff --git a/crates/wit-component/tests/components/import-conflict/module.wit b/crates/wit-component/tests/components/import-conflict/module.wit new file mode 100644 index 0000000000..b835e5e1ce --- /dev/null +++ b/crates/wit-component/tests/components/import-conflict/module.wit @@ -0,0 +1,19 @@ +package foo:foo; + +interface foo { + a: func(); +} + +interface bar { + a: func(x: u64, y: string); +} + +interface baz { + baz: func(x: list) -> list; +} + +world module { + import bar; + import baz; + import foo; +} diff --git a/crates/wit-component/tests/components/import-empty-interface/component.wat b/crates/wit-component/tests/components/import-empty-interface/component.wat new file mode 100644 index 0000000000..e40a4d41be --- /dev/null +++ b/crates/wit-component/tests/components/import-empty-interface/component.wat @@ -0,0 +1,12 @@ +(component + (core module (;0;) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-empty-interface/component.wit.print b/crates/wit-component/tests/components/import-empty-interface/component.wit.print new file mode 100644 index 0000000000..bcd860d376 --- /dev/null +++ b/crates/wit-component/tests/components/import-empty-interface/component.wit.print @@ -0,0 +1,4 @@ +package root:component + +world root { +} diff --git a/crates/wit-component/tests/components/import-empty-interface/module.wat b/crates/wit-component/tests/components/import-empty-interface/module.wat new file mode 100644 index 0000000000..3af8f25454 --- /dev/null +++ b/crates/wit-component/tests/components/import-empty-interface/module.wat @@ -0,0 +1 @@ +(module) diff --git a/crates/wit-component/tests/components/import-empty-interface/module.wit b/crates/wit-component/tests/components/import-empty-interface/module.wit new file mode 100644 index 0000000000..6522d92add --- /dev/null +++ b/crates/wit-component/tests/components/import-empty-interface/module.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world module { + import foo: interface {} +} diff --git a/crates/wit-component/tests/components/import-export-same-iface-name/component.wat b/crates/wit-component/tests/components/import-export-same-iface-name/component.wat new file mode 100644 index 0000000000..d170851643 --- /dev/null +++ b/crates/wit-component/tests/components/import-export-same-iface-name/component.wat @@ -0,0 +1,59 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + ) + ) + (import (interface "foo:dep/the-name") (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + ) + ) + (import (interface "foo:foo/the-name") (instance (;1;) (type 1))) + (core module (;0;) + (type (;0;) (func)) + (import "foo:dep/the-name" "a" (func (;0;) (type 0))) + (import "foo:foo/the-name" "a" (func (;1;) (type 0))) + (func (;2;) (type 0)) + (export "foo:foo/the-name#a" (func 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "a" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;0;) + (export "a" (func 0)) + ) + (alias export 1 "a" (func (;1;))) + (core func (;1;) (canon lower (func 1))) + (core instance (;1;) + (export "a" (func 1)) + ) + (core instance (;2;) (instantiate 0 + (with "foo:dep/the-name" (instance 0)) + (with "foo:foo/the-name" (instance 1)) + ) + ) + (type (;2;) (func)) + (alias core export 2 "foo:foo/the-name#a" (core func (;2;))) + (func (;2;) (type 2) (canon lift (core func 2))) + (component (;0;) + (type (;0;) (func)) + (import "import-func-a" (func (;0;) (type 0))) + (type (;1;) (func)) + (export (;1;) "a" (func 0) (func (type 1))) + ) + (instance (;2;) (instantiate 0 + (with "import-func-a" (func 2)) + ) + ) + (export (;3;) (interface "foo:foo/the-name") (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-export-same-iface-name/component.wit.print b/crates/wit-component/tests/components/import-export-same-iface-name/component.wit.print new file mode 100644 index 0000000000..2841ebd4da --- /dev/null +++ b/crates/wit-component/tests/components/import-export-same-iface-name/component.wit.print @@ -0,0 +1,8 @@ +package root:component + +world root { + import foo:dep/the-name + import foo:foo/the-name + + export foo:foo/the-name +} diff --git a/crates/wit-component/tests/components/import-export-same-iface-name/deps/dep/foo.wit b/crates/wit-component/tests/components/import-export-same-iface-name/deps/dep/foo.wit new file mode 100644 index 0000000000..ae5aa7af19 --- /dev/null +++ b/crates/wit-component/tests/components/import-export-same-iface-name/deps/dep/foo.wit @@ -0,0 +1,5 @@ +package foo:dep; + +interface the-name { + a: func(); +} diff --git a/crates/wit-component/tests/components/import-export-same-iface-name/module.wat b/crates/wit-component/tests/components/import-export-same-iface-name/module.wat new file mode 100644 index 0000000000..4e9ece5084 --- /dev/null +++ b/crates/wit-component/tests/components/import-export-same-iface-name/module.wat @@ -0,0 +1,5 @@ +(module + (import "foo:dep/the-name" "a" (func)) + (import "foo:foo/the-name" "a" (func)) + (func (export "foo:foo/the-name#a")) +) diff --git a/crates/wit-component/tests/components/import-export-same-iface-name/module.wit b/crates/wit-component/tests/components/import-export-same-iface-name/module.wit new file mode 100644 index 0000000000..219e1b4d24 --- /dev/null +++ b/crates/wit-component/tests/components/import-export-same-iface-name/module.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface the-name { + a: func(); +} + +world module { + import foo:dep/the-name; + import the-name; + export the-name; +} diff --git a/crates/wit-component/tests/components/import-export/component.wat b/crates/wit-component/tests/components/import-export/component.wat new file mode 100644 index 0000000000..fb2643bdc8 --- /dev/null +++ b/crates/wit-component/tests/components/import-export/component.wat @@ -0,0 +1,124 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (result string))) + (export (;0;) "a" (func (type 0))) + ) + ) + (import "foo" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (type (;2;) (func (param i32 i32) (result i32))) + (type (;3;) (func)) + (type (;4;) (func (result i32))) + (import "foo" "a" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;2;) (type 2) (param i32 i32) (result i32) + unreachable + ) + (func (;3;) (type 0) (param i32) + unreachable + ) + (func (;4;) (type 3) + unreachable + ) + (func (;5;) (type 4) (result i32) + unreachable + ) + (func (;6;) (type 0) (param i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 1)) + (export "a" (func 2)) + (export "cabi_post_a" (func 3)) + (export "bar#a" (func 4)) + (export "bar#b" (func 5)) + (export "cabi_post_bar#b" (func 6)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32))) + (func $indirect-foo-a (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (table (;0;) 1 1 funcref) + (export "0" (func $indirect-foo-a)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "$imports" (table (;0;) 1 1 funcref)) + (elem (;0;) (i32.const 0) func 0) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 1)) + (alias core export 0 "0" (core func (;0;))) + (core instance (;1;) + (export "a" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "foo" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;1;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "a" (func (;0;))) + (core func (;2;) (canon lower (func 0) (memory 0) (realloc 1) string-encoding=utf8)) + (core instance (;3;) + (export "$imports" (table 0)) + (export "0" (func 2)) + ) + (core instance (;4;) (instantiate 2 + (with "" (instance 3)) + ) + ) + (type (;1;) (tuple string u32 string)) + (type (;2;) (func (param "x" string) (result 1))) + (alias core export 2 "a" (core func (;3;))) + (alias core export 2 "cabi_post_a" (core func (;4;))) + (func (;1;) (type 2) (canon lift (core func 3) (memory 0) (realloc 1) string-encoding=utf8 (post-return 4))) + (export (;2;) "a" (func 1)) + (type (;3;) (func)) + (alias core export 2 "bar#a" (core func (;5;))) + (func (;3;) (type 3) (canon lift (core func 5))) + (type (;4;) (func (result string))) + (alias core export 2 "bar#b" (core func (;6;))) + (alias core export 2 "cabi_post_bar#b" (core func (;7;))) + (func (;4;) (type 4) (canon lift (core func 6) (memory 0) string-encoding=utf8 (post-return 7))) + (component (;0;) + (type (;0;) (func)) + (import "import-func-a" (func (;0;) (type 0))) + (type (;1;) (func (result string))) + (import "import-func-b" (func (;1;) (type 1))) + (type (;2;) (func)) + (export (;2;) "a" (func 0) (func (type 2))) + (type (;3;) (func (result string))) + (export (;3;) "b" (func 1) (func (type 3))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-a" (func 3)) + (with "import-func-b" (func 4)) + ) + ) + (export (;2;) "bar" (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-export/component.wit.print b/crates/wit-component/tests/components/import-export/component.wit.print new file mode 100644 index 0000000000..7535b74110 --- /dev/null +++ b/crates/wit-component/tests/components/import-export/component.wit.print @@ -0,0 +1,14 @@ +package root:component + +world root { + import foo: interface { + a: func() -> string + } + + export a: func(x: string) -> tuple + export bar: interface { + a: func() + + b: func() -> string + } +} diff --git a/crates/wit-component/tests/components/import-export/module.wat b/crates/wit-component/tests/components/import-export/module.wat new file mode 100644 index 0000000000..611093d52e --- /dev/null +++ b/crates/wit-component/tests/components/import-export/module.wat @@ -0,0 +1,10 @@ +(module + (import "foo" "a" (func (param i32))) + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "a") (param i32 i32) (result i32) unreachable) + (func (export "cabi_post_a") (param i32) unreachable) + (func (export "bar#a") unreachable) + (func (export "bar#b") (result i32) unreachable) + (func (export "cabi_post_bar#b") (param i32) unreachable) +) diff --git a/crates/wit-component/tests/components/import-export/module.wit b/crates/wit-component/tests/components/import-export/module.wit new file mode 100644 index 0000000000..0f2538373e --- /dev/null +++ b/crates/wit-component/tests/components/import-export/module.wit @@ -0,0 +1,14 @@ +package foo:foo; + +world module { + import foo: interface { + a: func() -> string; + } + + export bar: interface { + a: func(); + b: func() -> string; + } + + export a: func(x: string) -> tuple; +} diff --git a/crates/wit-component/tests/components/import-in-adapter-and-main-module/adapt-old.wat b/crates/wit-component/tests/components/import-in-adapter-and-main-module/adapt-old.wat new file mode 100644 index 0000000000..56db4f5510 --- /dev/null +++ b/crates/wit-component/tests/components/import-in-adapter-and-main-module/adapt-old.wat @@ -0,0 +1,23 @@ +(module + (import "foo:shared-dependency/doc" "f1" (func $f1)) + (import "foo:shared-dependency/doc" "f3" (func $f3)) + + (import "foo:shared-dependency/doc" "g1" (func $g1 (param i32))) + (import "foo:shared-dependency/doc" "g3" (func $g3 (param i32))) + + (import "foo:shared-dependency/doc" "unused-in-adapter" (func)) + (import "env" "memory" (memory 0)) + + (import "adapter-dep" "foo" (func $foo (result i32))) + + (func (export "adapter-f1") + call $f1 + call $f3 + (call $g1 (i32.const 0)) + (call $g3 (i32.const 0)) + (drop (call $foo)) + ) + + (func (export "cabi_import_realloc") (param i32 i32 i32 i32) (result i32) + unreachable) +) diff --git a/crates/wit-component/tests/components/import-in-adapter-and-main-module/adapt-old.wit b/crates/wit-component/tests/components/import-in-adapter-and-main-module/adapt-old.wit new file mode 100644 index 0000000000..c1753320cf --- /dev/null +++ b/crates/wit-component/tests/components/import-in-adapter-and-main-module/adapt-old.wit @@ -0,0 +1,9 @@ +world adapt-old { + import foo:shared-dependency/doc; + + import adapter-dep: interface { + use foo:shared-dependency/types.{a-typedef}; + + foo: func() -> a-typedef; + } +} diff --git a/crates/wit-component/tests/components/import-in-adapter-and-main-module/component.wat b/crates/wit-component/tests/components/import-in-adapter-and-main-module/component.wat new file mode 100644 index 0000000000..8d0389271b --- /dev/null +++ b/crates/wit-component/tests/components/import-in-adapter-and-main-module/component.wat @@ -0,0 +1,220 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "f1" (func (type 0))) + (export (;1;) "f2" (func (type 0))) + (export (;2;) "f3" (func (type 0))) + (type (;1;) (func (result string))) + (export (;3;) "g1" (func (type 1))) + (export (;4;) "g2" (func (type 1))) + (export (;5;) "g3" (func (type 1))) + ) + ) + (import (interface "foo:shared-dependency/doc") (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) u32) + (export (;1;) "a-typedef" (type (eq 0))) + ) + ) + (import (interface "foo:shared-dependency/types") (instance (;1;) (type 1))) + (alias export 1 "a-typedef" (type (;2;))) + (type (;3;) + (instance + (alias outer 1 2 (type (;0;))) + (export (;1;) "a-typedef" (type (eq 0))) + (type (;2;) (func (result 1))) + (export (;0;) "foo" (func (type 2))) + ) + ) + (import "main-dep" (instance (;2;) (type 3))) + (alias export 1 "a-typedef" (type (;4;))) + (type (;5;) + (instance + (alias outer 1 4 (type (;0;))) + (export (;1;) "a-typedef" (type (eq 0))) + (type (;2;) (func (result 1))) + (export (;0;) "foo" (func (type 2))) + ) + ) + (import "adapter-dep" (instance (;3;) (type 5))) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo:shared-dependency/doc" "f1" (func (;0;) (type 0))) + (import "foo:shared-dependency/doc" "f2" (func (;1;) (type 0))) + (import "foo:shared-dependency/doc" "g1" (func (;2;) (type 1))) + (import "foo:shared-dependency/doc" "g2" (func (;3;) (type 1))) + (import "old" "adapter-f1" (func (;4;) (type 0))) + (import "main-dep" "foo" (func (;5;) (type 2))) + (func (;6;) (type 3) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 6)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo:shared-dependency/doc" "f1" (func $f1 (;0;) (type 0))) + (import "foo:shared-dependency/doc" "f3" (func $f3 (;1;) (type 0))) + (import "foo:shared-dependency/doc" "g1" (func $g1 (;2;) (type 1))) + (import "foo:shared-dependency/doc" "g3" (func $g3 (;3;) (type 1))) + (import "adapter-dep" "foo" (func $foo (;4;) (type 2))) + (func (;5;) (type 0) + call $f1 + call $f3 + i32.const 0 + call $g1 + i32.const 0 + call $g3 + call $foo + drop + ) + (func (;6;) (type 3) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (export "adapter-f1" (func 5)) + (export "cabi_import_realloc" (func 6)) + ) + (core module (;2;) + (type (;0;) (func (param i32))) + (type (;1;) (func)) + (func $indirect-foo:shared-dependency/doc-g1 (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $indirect-foo:shared-dependency/doc-g2 (;1;) (type 0) (param i32) + local.get 0 + i32.const 1 + call_indirect (type 0) + ) + (func $#func2 (@name "indirect-foo:shared-dependency/doc-g1") (;2;) (type 0) (param i32) + local.get 0 + i32.const 2 + call_indirect (type 0) + ) + (func $indirect-foo:shared-dependency/doc-g3 (;3;) (type 0) (param i32) + local.get 0 + i32.const 3 + call_indirect (type 0) + ) + (func $adapt-old-adapter-f1 (;4;) (type 1) + i32.const 4 + call_indirect (type 1) + ) + (table (;0;) 5 5 funcref) + (export "0" (func $indirect-foo:shared-dependency/doc-g1)) + (export "1" (func $indirect-foo:shared-dependency/doc-g2)) + (export "2" (func $#func2)) + (export "3" (func $indirect-foo:shared-dependency/doc-g3)) + (export "4" (func $adapt-old-adapter-f1)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;3;) + (type (;0;) (func (param i32))) + (type (;1;) (func)) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "2" (func (;2;) (type 0))) + (import "" "3" (func (;3;) (type 0))) + (import "" "4" (func (;4;) (type 1))) + (import "" "$imports" (table (;0;) 5 5 funcref)) + (elem (;0;) (i32.const 0) func 0 1 2 3 4) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 2)) + (alias export 0 "f1" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (alias export 0 "f2" (func (;1;))) + (core func (;1;) (canon lower (func 1))) + (alias core export 0 "0" (core func (;2;))) + (alias core export 0 "1" (core func (;3;))) + (core instance (;1;) + (export "f1" (func 0)) + (export "f2" (func 1)) + (export "g1" (func 2)) + (export "g2" (func 3)) + ) + (alias export 2 "foo" (func (;2;))) + (core func (;4;) (canon lower (func 2))) + (core instance (;2;) + (export "foo" (func 4)) + ) + (alias core export 0 "4" (core func (;5;))) + (core instance (;3;) + (export "adapter-f1" (func 5)) + ) + (core instance (;4;) (instantiate 0 + (with "foo:shared-dependency/doc" (instance 1)) + (with "main-dep" (instance 2)) + (with "old" (instance 3)) + ) + ) + (alias core export 4 "memory" (core memory (;0;))) + (alias core export 4 "cabi_realloc" (core func (;6;))) + (alias export 0 "f1" (func (;3;))) + (core func (;7;) (canon lower (func 3))) + (alias export 0 "f3" (func (;4;))) + (core func (;8;) (canon lower (func 4))) + (alias core export 0 "2" (core func (;9;))) + (alias core export 0 "3" (core func (;10;))) + (core instance (;5;) + (export "f1" (func 7)) + (export "f3" (func 8)) + (export "g1" (func 9)) + (export "g3" (func 10)) + ) + (alias export 3 "foo" (func (;5;))) + (core func (;11;) (canon lower (func 5))) + (core instance (;6;) + (export "foo" (func 11)) + ) + (core instance (;7;) (instantiate 1 + (with "foo:shared-dependency/doc" (instance 5)) + (with "adapter-dep" (instance 6)) + ) + ) + (alias core export 7 "cabi_import_realloc" (core func (;12;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "g1" (func (;6;))) + (core func (;13;) (canon lower (func 6) (memory 0) (realloc 6) string-encoding=utf8)) + (alias export 0 "g2" (func (;7;))) + (core func (;14;) (canon lower (func 7) (memory 0) (realloc 6) string-encoding=utf8)) + (alias export 0 "g1" (func (;8;))) + (core func (;15;) (canon lower (func 8) (memory 0) (realloc 12) string-encoding=utf8)) + (alias export 0 "g3" (func (;9;))) + (core func (;16;) (canon lower (func 9) (memory 0) (realloc 12) string-encoding=utf8)) + (alias core export 7 "adapter-f1" (core func (;17;))) + (core instance (;8;) + (export "$imports" (table 0)) + (export "0" (func 13)) + (export "1" (func 14)) + (export "2" (func 15)) + (export "3" (func 16)) + (export "4" (func 17)) + ) + (core instance (;9;) (instantiate 3 + (with "" (instance 8)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-in-adapter-and-main-module/component.wit.print b/crates/wit-component/tests/components/import-in-adapter-and-main-module/component.wit.print new file mode 100644 index 0000000000..f4c5c50a23 --- /dev/null +++ b/crates/wit-component/tests/components/import-in-adapter-and-main-module/component.wit.print @@ -0,0 +1,16 @@ +package root:component + +world root { + import foo:shared-dependency/doc + import foo:shared-dependency/types + import main-dep: interface { + use foo:shared-dependency/types.{a-typedef} + + foo: func() -> a-typedef + } + import adapter-dep: interface { + use foo:shared-dependency/types.{a-typedef} + + foo: func() -> a-typedef + } +} diff --git a/crates/wit-component/tests/components/import-in-adapter-and-main-module/deps/shared-dependency/doc.wit b/crates/wit-component/tests/components/import-in-adapter-and-main-module/deps/shared-dependency/doc.wit new file mode 100644 index 0000000000..621d98e4cc --- /dev/null +++ b/crates/wit-component/tests/components/import-in-adapter-and-main-module/deps/shared-dependency/doc.wit @@ -0,0 +1,13 @@ +package foo:shared-dependency; + +interface doc { + f1: func(); + f2: func(); + f3: func(); + + g1: func() -> string; + g2: func() -> string; + g3: func() -> string; + + unused-in-adapter: func(); +} diff --git a/crates/wit-component/tests/components/import-in-adapter-and-main-module/deps/shared-dependency/types.wit b/crates/wit-component/tests/components/import-in-adapter-and-main-module/deps/shared-dependency/types.wit new file mode 100644 index 0000000000..bf42b9e545 --- /dev/null +++ b/crates/wit-component/tests/components/import-in-adapter-and-main-module/deps/shared-dependency/types.wit @@ -0,0 +1,3 @@ +interface types { + type a-typedef = u32; +} diff --git a/crates/wit-component/tests/components/import-in-adapter-and-main-module/module.wat b/crates/wit-component/tests/components/import-in-adapter-and-main-module/module.wat new file mode 100644 index 0000000000..1f17565460 --- /dev/null +++ b/crates/wit-component/tests/components/import-in-adapter-and-main-module/module.wat @@ -0,0 +1,15 @@ +(module + (import "foo:shared-dependency/doc" "f1" (func)) + (import "foo:shared-dependency/doc" "f2" (func)) + + (import "foo:shared-dependency/doc" "g1" (func (param i32))) + (import "foo:shared-dependency/doc" "g2" (func (param i32))) + + (import "old" "adapter-f1" (func)) + + (import "main-dep" "foo" (func (result i32))) + + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) + unreachable) +) diff --git a/crates/wit-component/tests/components/import-in-adapter-and-main-module/module.wit b/crates/wit-component/tests/components/import-in-adapter-and-main-module/module.wit new file mode 100644 index 0000000000..8056f1e246 --- /dev/null +++ b/crates/wit-component/tests/components/import-in-adapter-and-main-module/module.wit @@ -0,0 +1,11 @@ +package foo:foo; + +world module { + import foo:shared-dependency/doc; + + import main-dep: interface { + use foo:shared-dependency/types.{a-typedef}; + + foo: func() -> a-typedef; + } +} diff --git a/crates/wit-component/tests/components/import-partial-export-full/component.wat b/crates/wit-component/tests/components/import-partial-export-full/component.wat new file mode 100644 index 0000000000..3c933901a2 --- /dev/null +++ b/crates/wit-component/tests/components/import-partial-export-full/component.wat @@ -0,0 +1,31 @@ +(component + (type (;0;) + (instance + (type (;0;) (list string)) + (type (;1;) (variant (case "strs" 0))) + (export (;2;) "name" (type (eq 1))) + ) + ) + (import (interface "a:b/name") (instance (;0;) (type 0))) + (alias export 0 "name" (type (;1;))) + (import "name" (type (;2;) (eq 1))) + (core module (;0;) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (component (;0;) + (type (;0;) (list string)) + (type (;1;) (variant (case "num" u16) (case "strs" 0))) + (export (;2;) "name2" (type 1)) + (type (;3;) (variant (case "strs" 0))) + (export (;4;) "name" (type 3)) + ) + (instance (;1;) (instantiate 0)) + (export (;2;) (interface "a:b/name") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-partial-export-full/component.wit.print b/crates/wit-component/tests/components/import-partial-export-full/component.wit.print new file mode 100644 index 0000000000..014f050ba9 --- /dev/null +++ b/crates/wit-component/tests/components/import-partial-export-full/component.wit.print @@ -0,0 +1,8 @@ +package root:component + +world root { + import a:b/name + use a:b/name.{name} + + export a:b/name +} diff --git a/crates/wit-component/tests/components/import-partial-export-full/module.wat b/crates/wit-component/tests/components/import-partial-export-full/module.wat new file mode 100644 index 0000000000..3af8f25454 --- /dev/null +++ b/crates/wit-component/tests/components/import-partial-export-full/module.wat @@ -0,0 +1 @@ +(module) diff --git a/crates/wit-component/tests/components/import-partial-export-full/module.wit b/crates/wit-component/tests/components/import-partial-export-full/module.wit new file mode 100644 index 0000000000..8d4fef5c97 --- /dev/null +++ b/crates/wit-component/tests/components/import-partial-export-full/module.wit @@ -0,0 +1,19 @@ +package a:b; + +interface name { + variant name2 { + num(u16), + strs(list), + } + + variant name { + strs(list), + } +} + +world module { + import name; + use name.{name}; + + export name; +} diff --git a/crates/wit-component/tests/components/import-resource-in-interface/component.wat b/crates/wit-component/tests/components/import-resource-in-interface/component.wat new file mode 100644 index 0000000000..4a716732c6 --- /dev/null +++ b/crates/wit-component/tests/components/import-resource-in-interface/component.wat @@ -0,0 +1,41 @@ +(component + (type (;0;) + (instance + (export (;0;) "a" (type (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (export (;0;) "[constructor]a" (func (type 2))) + (export (;1;) "[static]a.other-new" (func (type 2))) + ) + ) + (import "foo" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (import "foo" "[constructor]a" (func (;0;) (type 0))) + (import "foo" "[static]a.other-new" (func (;1;) (type 0))) + (import "foo" "[resource-drop]a" (func (;2;) (type 1))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "a" (type (;1;))) + (core func (;0;) (canon resource.drop 1)) + (alias export 0 "[constructor]a" (func (;0;))) + (core func (;1;) (canon lower (func 0))) + (alias export 0 "[static]a.other-new" (func (;1;))) + (core func (;2;) (canon lower (func 1))) + (core instance (;0;) + (export "[resource-drop]a" (func 0)) + (export "[constructor]a" (func 1)) + (export "[static]a.other-new" (func 2)) + ) + (core instance (;1;) (instantiate 0 + (with "foo" (instance 0)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-resource-in-interface/component.wit.print b/crates/wit-component/tests/components/import-resource-in-interface/component.wit.print new file mode 100644 index 0000000000..7192a217d7 --- /dev/null +++ b/crates/wit-component/tests/components/import-resource-in-interface/component.wit.print @@ -0,0 +1,10 @@ +package root:component + +world root { + import foo: interface { + resource a { + constructor() + other-new: static func() -> a + } + } +} diff --git a/crates/wit-component/tests/components/import-resource-in-interface/module.wat b/crates/wit-component/tests/components/import-resource-in-interface/module.wat new file mode 100644 index 0000000000..e0bba54b07 --- /dev/null +++ b/crates/wit-component/tests/components/import-resource-in-interface/module.wat @@ -0,0 +1,5 @@ +(module + (import "foo" "[constructor]a" (func (result i32))) + (import "foo" "[static]a.other-new" (func (result i32))) + (import "foo" "[resource-drop]a" (func (param i32))) +) diff --git a/crates/wit-component/tests/components/import-resource-in-interface/module.wit b/crates/wit-component/tests/components/import-resource-in-interface/module.wit new file mode 100644 index 0000000000..6d3c226605 --- /dev/null +++ b/crates/wit-component/tests/components/import-resource-in-interface/module.wit @@ -0,0 +1,11 @@ +package foo:bar; + +world module { + import foo: interface { + resource a { + constructor(); + + other-new: static func() -> a; + } + } +} diff --git a/crates/wit-component/tests/components/import-resource-simple/component.wat b/crates/wit-component/tests/components/import-resource-simple/component.wat new file mode 100644 index 0000000000..4b5a2864ee --- /dev/null +++ b/crates/wit-component/tests/components/import-resource-simple/component.wat @@ -0,0 +1,33 @@ +(component + (import "a" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (import "[constructor]a" (func (;0;) (type 2))) + (import "[static]a.other-new" (func (;1;) (type 2))) + (core module (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (import "$root" "[constructor]a" (func (;0;) (type 0))) + (import "$root" "[static]a.other-new" (func (;1;) (type 0))) + (import "$root" "[resource-drop]a" (func (;2;) (type 1))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core func (;0;) (canon resource.drop 0)) + (core func (;1;) (canon lower (func 0))) + (core func (;2;) (canon lower (func 1))) + (core instance (;0;) + (export "[resource-drop]a" (func 0)) + (export "[constructor]a" (func 1)) + (export "[static]a.other-new" (func 2)) + ) + (core instance (;1;) (instantiate 0 + (with "$root" (instance 0)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/import-resource-simple/component.wit.print b/crates/wit-component/tests/components/import-resource-simple/component.wit.print new file mode 100644 index 0000000000..04086257ba --- /dev/null +++ b/crates/wit-component/tests/components/import-resource-simple/component.wit.print @@ -0,0 +1,8 @@ +package root:component + +world root { + resource a { + constructor() + other-new: static func() -> a + } +} diff --git a/crates/wit-component/tests/components/import-resource-simple/module.wat b/crates/wit-component/tests/components/import-resource-simple/module.wat new file mode 100644 index 0000000000..640aa6320a --- /dev/null +++ b/crates/wit-component/tests/components/import-resource-simple/module.wat @@ -0,0 +1,5 @@ +(module + (import "$root" "[constructor]a" (func (result i32))) + (import "$root" "[static]a.other-new" (func (result i32))) + (import "$root" "[resource-drop]a" (func (param i32))) +) diff --git a/crates/wit-component/tests/components/import-resource-simple/module.wit b/crates/wit-component/tests/components/import-resource-simple/module.wit new file mode 100644 index 0000000000..6459ad5138 --- /dev/null +++ b/crates/wit-component/tests/components/import-resource-simple/module.wit @@ -0,0 +1,9 @@ +package foo:bar; + +world module { + resource a { + constructor(); + + other-new: static func() -> a; + } +} diff --git a/crates/wit-component/tests/components/imports/component.wat b/crates/wit-component/tests/components/imports/component.wat new file mode 100644 index 0000000000..8d5977d4ac --- /dev/null +++ b/crates/wit-component/tests/components/imports/component.wat @@ -0,0 +1,149 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "a" u8))) + (export (;1;) "x" (type (eq 0))) + (type (;2;) (func (param "x" string))) + (export (;0;) "bar1" (func (type 2))) + (type (;3;) (func (param "x" 1))) + (export (;1;) "bar2" (func (type 3))) + ) + ) + (import "bar" (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) s8) + (export (;1;) "x" (type (eq 0))) + (type (;2;) (list string)) + (type (;3;) (func (param "x" 2))) + (export (;0;) "baz1" (func (type 3))) + (type (;4;) (func)) + (export (;1;) "baz2" (func (type 4))) + (type (;5;) (func (param "x" 1))) + (export (;2;) "baz3" (func (type 5))) + ) + ) + (import "baz" (instance (;1;) (type 1))) + (type (;2;) + (instance + (type (;0;) (func)) + (export (;0;) "foo1" (func (type 0))) + (type (;1;) (func (param "x" u8))) + (export (;1;) "foo2" (func (type 1))) + (type (;2;) (func (param "x" float32))) + (export (;2;) "foo3" (func (type 2))) + ) + ) + (import "foo" (instance (;2;) (type 2))) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (param i32 i32))) + (type (;4;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo" "foo1" (func (;0;) (type 0))) + (import "foo" "foo2" (func (;1;) (type 1))) + (import "foo" "foo3" (func (;2;) (type 2))) + (import "bar" "bar1" (func (;3;) (type 3))) + (import "bar" "bar2" (func (;4;) (type 1))) + (import "baz" "baz1" (func (;5;) (type 3))) + (import "baz" "baz2" (func (;6;) (type 0))) + (import "baz" "baz3" (func (;7;) (type 1))) + (func (;8;) (type 4) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 8)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32 i32))) + (func $indirect-bar-bar1 (;0;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 0 + call_indirect (type 0) + ) + (func $indirect-baz-baz1 (;1;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 1 + call_indirect (type 0) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-bar-bar1)) + (export "1" (func $indirect-baz-baz1)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32 i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 1)) + (alias export 2 "foo1" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (alias export 2 "foo2" (func (;1;))) + (core func (;1;) (canon lower (func 1))) + (alias export 2 "foo3" (func (;2;))) + (core func (;2;) (canon lower (func 2))) + (core instance (;1;) + (export "foo1" (func 0)) + (export "foo2" (func 1)) + (export "foo3" (func 2)) + ) + (alias core export 0 "0" (core func (;3;))) + (alias export 0 "bar2" (func (;3;))) + (core func (;4;) (canon lower (func 3))) + (core instance (;2;) + (export "bar1" (func 3)) + (export "bar2" (func 4)) + ) + (alias core export 0 "1" (core func (;5;))) + (alias export 1 "baz2" (func (;4;))) + (core func (;6;) (canon lower (func 4))) + (alias export 1 "baz3" (func (;5;))) + (core func (;7;) (canon lower (func 5))) + (core instance (;3;) + (export "baz1" (func 5)) + (export "baz2" (func 6)) + (export "baz3" (func 7)) + ) + (core instance (;4;) (instantiate 0 + (with "foo" (instance 1)) + (with "bar" (instance 2)) + (with "baz" (instance 3)) + ) + ) + (alias core export 4 "memory" (core memory (;0;))) + (alias core export 4 "cabi_realloc" (core func (;8;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "bar1" (func (;6;))) + (core func (;9;) (canon lower (func 6) (memory 0) string-encoding=utf8)) + (alias export 1 "baz1" (func (;7;))) + (core func (;10;) (canon lower (func 7) (memory 0) string-encoding=utf8)) + (core instance (;5;) + (export "$imports" (table 0)) + (export "0" (func 9)) + (export "1" (func 10)) + ) + (core instance (;6;) (instantiate 2 + (with "" (instance 5)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/imports/component.wit.print b/crates/wit-component/tests/components/imports/component.wit.print new file mode 100644 index 0000000000..4ca4e77402 --- /dev/null +++ b/crates/wit-component/tests/components/imports/component.wit.print @@ -0,0 +1,29 @@ +package root:component + +world root { + import bar: interface { + record x { + a: u8, + } + + bar1: func(x: string) + + bar2: func(x: x) + } + import baz: interface { + type x = s8 + + baz1: func(x: list) + + baz2: func() + + baz3: func(x: x) + } + import foo: interface { + foo1: func() + + foo2: func(x: u8) + + foo3: func(x: float32) + } +} diff --git a/crates/wit-component/tests/components/imports/module.wat b/crates/wit-component/tests/components/imports/module.wat new file mode 100644 index 0000000000..8887f91189 --- /dev/null +++ b/crates/wit-component/tests/components/imports/module.wat @@ -0,0 +1,12 @@ +(module + (import "foo" "foo1" (func)) + (import "foo" "foo2" (func (param i32))) + (import "foo" "foo3" (func (param f32))) + (import "bar" "bar1" (func (param i32 i32))) + (import "bar" "bar2" (func (param i32))) + (import "baz" "baz1" (func (param i32 i32))) + (import "baz" "baz2" (func)) + (import "baz" "baz3" (func (param i32))) + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/imports/module.wit b/crates/wit-component/tests/components/imports/module.wit new file mode 100644 index 0000000000..de0e1f80d3 --- /dev/null +++ b/crates/wit-component/tests/components/imports/module.wit @@ -0,0 +1,33 @@ +package foo:foo; + +world module { + import bar: interface { + record x { + a: u8 + } + + bar1: func(x: string); + bar2: func(x: x); + } + + import baz: interface { + type x = s8; + + baz1: func(x: list); + baz2: func(); + baz3: func(x: x); + } + + import foo: interface { + foo1: func(); + foo2: func(x: u8); + foo3: func(x: float32); + unused: func(); + + // doesn't show up in the wit output despite being exported here since it's + // not actually used by anything + record unused-record { + f: u8, + } + } +} diff --git a/crates/wit-component/tests/components/lift-options/component.wat b/crates/wit-component/tests/components/lift-options/component.wat new file mode 100644 index 0000000000..f7095db90c --- /dev/null +++ b/crates/wit-component/tests/components/lift-options/component.wat @@ -0,0 +1,286 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32 i32))) + (type (;3;) (func (param i32 i32 i32))) + (type (;4;) (func (param i32))) + (type (;5;) (func (result i32))) + (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;1;) (type 1) + unreachable + ) + (func (;2;) (type 2) (param i32 i32) + unreachable + ) + (func (;3;) (type 2) (param i32 i32) + unreachable + ) + (func (;4;) (type 3) (param i32 i32 i32) + unreachable + ) + (func (;5;) (type 4) (param i32) + unreachable + ) + (func (;6;) (type 2) (param i32 i32) + unreachable + ) + (func (;7;) (type 2) (param i32 i32) + unreachable + ) + (func (;8;) (type 2) (param i32 i32) + unreachable + ) + (func (;9;) (type 2) (param i32 i32) + unreachable + ) + (func (;10;) (type 4) (param i32) + unreachable + ) + (func (;11;) (type 5) (result i32) + unreachable + ) + (func (;12;) (type 5) (result i32) + unreachable + ) + (func (;13;) (type 4) (param i32) + unreachable + ) + (func (;14;) (type 5) (result i32) + unreachable + ) + (func (;15;) (type 4) (param i32) + unreachable + ) + (func (;16;) (type 5) (result i32) + unreachable + ) + (func (;17;) (type 5) (result i32) + unreachable + ) + (func (;18;) (type 4) (param i32) + unreachable + ) + (func (;19;) (type 5) (result i32) + unreachable + ) + (func (;20;) (type 4) (param i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 0)) + (export "foo:foo/my-default#a" (func 1)) + (export "foo:foo/my-default#b" (func 2)) + (export "foo:foo/my-default#c" (func 3)) + (export "foo:foo/my-default#d" (func 4)) + (export "foo:foo/my-default#e" (func 5)) + (export "foo:foo/my-default#f" (func 6)) + (export "foo:foo/my-default#g" (func 7)) + (export "foo:foo/my-default#h" (func 8)) + (export "foo:foo/my-default#i" (func 9)) + (export "foo:foo/my-default#j" (func 10)) + (export "foo:foo/my-default#k" (func 11)) + (export "foo:foo/my-default#l" (func 12)) + (export "cabi_post_foo:foo/my-default#l" (func 13)) + (export "foo:foo/my-default#m" (func 14)) + (export "cabi_post_foo:foo/my-default#m" (func 15)) + (export "foo:foo/my-default#n" (func 16)) + (export "foo:foo/my-default#o" (func 17)) + (export "cabi_post_foo:foo/my-default#o" (func 18)) + (export "foo:foo/my-default#p" (func 19)) + (export "cabi_post_foo:foo/my-default#p" (func 20)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "cabi_realloc" (core func (;0;))) + (type (;0;) (func)) + (alias core export 0 "foo:foo/my-default#a" (core func (;1;))) + (func (;0;) (type 0) (canon lift (core func 1))) + (type (;1;) (list string)) + (type (;2;) (func (param "x" 1))) + (alias core export 0 "foo:foo/my-default#b" (core func (;2;))) + (func (;1;) (type 2) (canon lift (core func 2) (memory 0) (realloc 0) string-encoding=utf8)) + (type (;3;) (record (field "s" string))) + (type (;4;) (func (param "x" 3))) + (alias core export 0 "foo:foo/my-default#c" (core func (;3;))) + (func (;2;) (type 4) (canon lift (core func 3) (memory 0) (realloc 0) string-encoding=utf8)) + (type (;5;) (variant (case "s" string))) + (type (;6;) (func (param "x" 5))) + (alias core export 0 "foo:foo/my-default#d" (core func (;4;))) + (func (;3;) (type 6) (canon lift (core func 4) (memory 0) (realloc 0) string-encoding=utf8)) + (type (;7;) (record (field "s" u32))) + (type (;8;) (func (param "x" 7))) + (alias core export 0 "foo:foo/my-default#e" (core func (;5;))) + (func (;4;) (type 8) (canon lift (core func 5))) + (type (;9;) (variant (case "s" u32))) + (type (;10;) (func (param "x" 9))) + (alias core export 0 "foo:foo/my-default#f" (core func (;6;))) + (func (;5;) (type 10) (canon lift (core func 6))) + (type (;11;) (list 3)) + (type (;12;) (func (param "x" 11))) + (alias core export 0 "foo:foo/my-default#g" (core func (;7;))) + (func (;6;) (type 12) (canon lift (core func 7) (memory 0) (realloc 0) string-encoding=utf8)) + (type (;13;) (list 5)) + (type (;14;) (func (param "x" 13))) + (alias core export 0 "foo:foo/my-default#h" (core func (;8;))) + (func (;7;) (type 14) (canon lift (core func 8) (memory 0) (realloc 0) string-encoding=utf8)) + (type (;15;) (list u32)) + (type (;16;) (func (param "x" 15))) + (alias core export 0 "foo:foo/my-default#i" (core func (;9;))) + (func (;8;) (type 16) (canon lift (core func 9) (memory 0) (realloc 0))) + (type (;17;) (func (param "x" u32))) + (alias core export 0 "foo:foo/my-default#j" (core func (;10;))) + (func (;9;) (type 17) (canon lift (core func 10))) + (type (;18;) (tuple u32 u32)) + (type (;19;) (func (result 18))) + (alias core export 0 "foo:foo/my-default#k" (core func (;11;))) + (func (;10;) (type 19) (canon lift (core func 11) (memory 0))) + (type (;20;) (func (result string))) + (alias core export 0 "foo:foo/my-default#l" (core func (;12;))) + (alias core export 0 "cabi_post_foo:foo/my-default#l" (core func (;13;))) + (func (;11;) (type 20) (canon lift (core func 12) (memory 0) string-encoding=utf8 (post-return 13))) + (type (;21;) (func (result 15))) + (alias core export 0 "foo:foo/my-default#m" (core func (;14;))) + (alias core export 0 "cabi_post_foo:foo/my-default#m" (core func (;15;))) + (func (;12;) (type 21) (canon lift (core func 14) (memory 0) (post-return 15))) + (type (;22;) (func (result u32))) + (alias core export 0 "foo:foo/my-default#n" (core func (;16;))) + (func (;13;) (type 22) (canon lift (core func 16))) + (type (;23;) (func (result 5))) + (alias core export 0 "foo:foo/my-default#o" (core func (;17;))) + (alias core export 0 "cabi_post_foo:foo/my-default#o" (core func (;18;))) + (func (;14;) (type 23) (canon lift (core func 17) (memory 0) string-encoding=utf8 (post-return 18))) + (type (;24;) (list 9)) + (type (;25;) (func (result 24))) + (alias core export 0 "foo:foo/my-default#p" (core func (;19;))) + (alias core export 0 "cabi_post_foo:foo/my-default#p" (core func (;20;))) + (func (;15;) (type 25) (canon lift (core func 19) (memory 0) (post-return 20))) + (component (;0;) + (type (;0;) (func)) + (import "import-func-a" (func (;0;) (type 0))) + (type (;1;) (list string)) + (type (;2;) (func (param "x" 1))) + (import "import-func-b" (func (;1;) (type 2))) + (type (;3;) (record (field "s" string))) + (import "import-type-r" (type (;4;) (eq 3))) + (type (;5;) (func (param "x" 4))) + (import "import-func-c" (func (;2;) (type 5))) + (type (;6;) (variant (case "s" string))) + (import "import-type-v" (type (;7;) (eq 6))) + (type (;8;) (func (param "x" 7))) + (import "import-func-d" (func (;3;) (type 8))) + (type (;9;) (record (field "s" u32))) + (import "import-type-r-no-string" (type (;10;) (eq 9))) + (type (;11;) (func (param "x" 10))) + (import "import-func-e" (func (;4;) (type 11))) + (type (;12;) (variant (case "s" u32))) + (import "import-type-v-no-string" (type (;13;) (eq 12))) + (type (;14;) (func (param "x" 13))) + (import "import-func-f" (func (;5;) (type 14))) + (type (;15;) (list 4)) + (type (;16;) (func (param "x" 15))) + (import "import-func-g" (func (;6;) (type 16))) + (type (;17;) (list 7)) + (type (;18;) (func (param "x" 17))) + (import "import-func-h" (func (;7;) (type 18))) + (type (;19;) (list u32)) + (type (;20;) (func (param "x" 19))) + (import "import-func-i" (func (;8;) (type 20))) + (type (;21;) (func (param "x" u32))) + (import "import-func-j" (func (;9;) (type 21))) + (type (;22;) (tuple u32 u32)) + (type (;23;) (func (result 22))) + (import "import-func-k" (func (;10;) (type 23))) + (type (;24;) (func (result string))) + (import "import-func-l" (func (;11;) (type 24))) + (type (;25;) (func (result 19))) + (import "import-func-m" (func (;12;) (type 25))) + (type (;26;) (func (result u32))) + (import "import-func-n" (func (;13;) (type 26))) + (type (;27;) (func (result 7))) + (import "import-func-o" (func (;14;) (type 27))) + (type (;28;) (list 13)) + (type (;29;) (func (result 28))) + (import "import-func-p" (func (;15;) (type 29))) + (type (;30;) (record (field "s" string))) + (export (;31;) "r" (type 30)) + (type (;32;) (record (field "s" u32))) + (export (;33;) "r-no-string" (type 32)) + (type (;34;) (variant (case "s" string))) + (export (;35;) "v" (type 34)) + (type (;36;) (variant (case "s" u32))) + (export (;37;) "v-no-string" (type 36)) + (type (;38;) (func)) + (export (;16;) "a" (func 0) (func (type 38))) + (type (;39;) (list string)) + (type (;40;) (func (param "x" 39))) + (export (;17;) "b" (func 1) (func (type 40))) + (type (;41;) (func (param "x" 31))) + (export (;18;) "c" (func 2) (func (type 41))) + (type (;42;) (func (param "x" 35))) + (export (;19;) "d" (func 3) (func (type 42))) + (type (;43;) (func (param "x" 33))) + (export (;20;) "e" (func 4) (func (type 43))) + (type (;44;) (func (param "x" 37))) + (export (;21;) "f" (func 5) (func (type 44))) + (type (;45;) (list 31)) + (type (;46;) (func (param "x" 45))) + (export (;22;) "g" (func 6) (func (type 46))) + (type (;47;) (list 35)) + (type (;48;) (func (param "x" 47))) + (export (;23;) "h" (func 7) (func (type 48))) + (type (;49;) (list u32)) + (type (;50;) (func (param "x" 49))) + (export (;24;) "i" (func 8) (func (type 50))) + (type (;51;) (func (param "x" u32))) + (export (;25;) "j" (func 9) (func (type 51))) + (type (;52;) (tuple u32 u32)) + (type (;53;) (func (result 52))) + (export (;26;) "k" (func 10) (func (type 53))) + (type (;54;) (func (result string))) + (export (;27;) "l" (func 11) (func (type 54))) + (type (;55;) (func (result 49))) + (export (;28;) "m" (func 12) (func (type 55))) + (type (;56;) (func (result u32))) + (export (;29;) "n" (func 13) (func (type 56))) + (type (;57;) (func (result 35))) + (export (;30;) "o" (func 14) (func (type 57))) + (type (;58;) (list 37)) + (type (;59;) (func (result 58))) + (export (;31;) "p" (func 15) (func (type 59))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-a" (func 0)) + (with "import-func-b" (func 1)) + (with "import-func-c" (func 2)) + (with "import-func-d" (func 3)) + (with "import-func-e" (func 4)) + (with "import-func-f" (func 5)) + (with "import-func-g" (func 6)) + (with "import-func-h" (func 7)) + (with "import-func-i" (func 8)) + (with "import-func-j" (func 9)) + (with "import-func-k" (func 10)) + (with "import-func-l" (func 11)) + (with "import-func-m" (func 12)) + (with "import-func-n" (func 13)) + (with "import-func-o" (func 14)) + (with "import-func-p" (func 15)) + (with "import-type-r" (type 3)) + (with "import-type-v" (type 5)) + (with "import-type-r-no-string" (type 7)) + (with "import-type-v-no-string" (type 9)) + ) + ) + (export (;1;) (interface "foo:foo/my-default") (instance 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/lift-options/component.wit.print b/crates/wit-component/tests/components/lift-options/component.wit.print new file mode 100644 index 0000000000..eef89f13fc --- /dev/null +++ b/crates/wit-component/tests/components/lift-options/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + export foo:foo/my-default +} diff --git a/crates/wit-component/tests/components/lift-options/module.wat b/crates/wit-component/tests/components/lift-options/module.wat new file mode 100644 index 0000000000..242c2057af --- /dev/null +++ b/crates/wit-component/tests/components/lift-options/module.wat @@ -0,0 +1,24 @@ +(module + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "foo:foo/my-default#a") unreachable) + (func (export "foo:foo/my-default#b") (param i32 i32) unreachable) + (func (export "foo:foo/my-default#c") (param i32 i32) unreachable) + (func (export "foo:foo/my-default#d") (param i32 i32 i32) unreachable) + (func (export "foo:foo/my-default#e") (param i32) unreachable) + (func (export "foo:foo/my-default#f") (param i32 i32) unreachable) + (func (export "foo:foo/my-default#g") (param i32 i32) unreachable) + (func (export "foo:foo/my-default#h") (param i32 i32) unreachable) + (func (export "foo:foo/my-default#i") (param i32 i32) unreachable) + (func (export "foo:foo/my-default#j") (param i32) unreachable) + (func (export "foo:foo/my-default#k") (result i32) unreachable) + (func (export "foo:foo/my-default#l") (result i32) unreachable) + (func (export "cabi_post_foo:foo/my-default#l") (param i32) unreachable) + (func (export "foo:foo/my-default#m") (result i32) unreachable) + (func (export "cabi_post_foo:foo/my-default#m") (param i32) unreachable) + (func (export "foo:foo/my-default#n") (result i32) unreachable) + (func (export "foo:foo/my-default#o") (result i32) unreachable) + (func (export "cabi_post_foo:foo/my-default#o") (param i32) unreachable) + (func (export "foo:foo/my-default#p") (result i32) unreachable) + (func (export "cabi_post_foo:foo/my-default#p") (param i32) unreachable) +) diff --git a/crates/wit-component/tests/components/lift-options/module.wit b/crates/wit-component/tests/components/lift-options/module.wit new file mode 100644 index 0000000000..0666dd7115 --- /dev/null +++ b/crates/wit-component/tests/components/lift-options/module.wit @@ -0,0 +1,40 @@ +package foo:foo; + +interface my-default { + record r { + s: string + } + + record r-no-string { + s: u32 + } + + variant v { + s(string) + } + + variant v-no-string { + s(u32) + } + + a: func(); + b: func(x: list); + c: func(x: r); + d: func(x: v); + e: func(x: r-no-string); + f: func(x: v-no-string); + g: func(x: list); + h: func(x: list); + i: func(x: list); + j: func(x: u32); + k: func() -> tuple; + l: func() -> string; + m: func() -> list; + n: func() -> u32; + o: func() -> v; + p: func() -> list; +} + +world module { + export my-default; +} diff --git a/crates/wit-component/tests/components/link-bare-funcs/component.wat b/crates/wit-component/tests/components/link-bare-funcs/component.wat new file mode 100644 index 0000000000..f2849f911b --- /dev/null +++ b/crates/wit-component/tests/components/link-bare-funcs/component.wat @@ -0,0 +1,244 @@ +(component + (type (;0;) (func)) + (import "foo1" (func (;0;) (type 0))) + (type (;1;) (func (result string))) + (import "bar" (func (;1;) (type 1))) + (core module (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo" "cabi_realloc" (func (;0;) (type 0))) + (table (;0;) 0 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048592) + (global (;2;) i32 i32.const 0) + (global (;3;) i32 i32.const 1048592) + (global (;4;) i32 i32.const 0) + (global (;5;) (mut i32) i32.const 1048608) + (global (;6;) (mut i32) i32.const 1114112) + (export "cabi_realloc" (func 0)) + (export "__stack_pointer" (global 0)) + (export "c:memory_base" (global 1)) + (export "c:table_base" (global 2)) + (export "foo:memory_base" (global 3)) + (export "foo:table_base" (global 4)) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (import "GOT.mem" "__heap_base" (global $__heap_base (;0;) (mut i32))) + (import "GOT.mem" "__heap_end" (global $__heap_end (;1;) (mut i32))) + (func $start (;0;) (type 0) + global.get $__heap_base + global.set $heap + ) + (func $malloc (;1;) (type 1) (param i32) (result i32) + global.get $heap + global.get $heap + local.get 0 + i32.add + global.set $heap + ) + (func $abort (;2;) (type 0) + unreachable + ) + (global $heap (;2;) (mut i32) i32.const 0) + (export "malloc" (func $malloc)) + (export "abort" (func $abort)) + (start $start) + ) + (core module (;2;) + (@dylink.0 + (mem-info (memory 4 4)) + (needed "c") + ) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i32 i32) (result i32))) + (type (;3;) (func (param i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory (;0;) 1)) + (import "$root" "foo1" (func (;0;) (type 0))) + (import "$root" "bar" (func (;1;) (type 1))) + (func (;2;) (type 0)) + (func (;3;) (type 2) (param i32 i32) (result i32) + unreachable + ) + (func (;4;) (type 1) (param i32) + unreachable + ) + (func (;5;) (type 3) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;6;) (type 3) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;7;) (type 3) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (export "baz" (func 2)) + (export "foo2" (func 3)) + (export "cabi_post_foo2" (func 4)) + (export "cabi_realloc" (func 5)) + (export "cabi_import_realloc" (func 6)) + (export "cabi_export_realloc" (func 7)) + ) + (core module (;3;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (func (;0;) (type 0)) + (start 0) + (elem (;0;) (i32.const 0) func) + (elem (;1;) (i32.const 0) func) + (data (;0;) (i32.const 1048576) "\00\00\00\00\00\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;4;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (func $indirect-$root-bar (;0;) (type 0) (param i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (func $adapt-foo-cabi_realloc (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + i32.const 1 + call_indirect (type 1) + ) + (table (;0;) 2 2 funcref) + (export "0" (func $indirect-$root-bar)) + (export "1" (func $adapt-foo-cabi_realloc)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;5;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 1))) + (import "" "$imports" (table (;0;) 2 2 funcref)) + (elem (;0;) (i32.const 0) func 0 1) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 4)) + (alias core export 0 "1" (core func (;0;))) + (core instance (;1;) + (export "cabi_realloc" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "foo" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;1;))) + (alias core export 2 "__heap_base" (core global (;0;))) + (alias core export 2 "__heap_end" (core global (;1;))) + (core instance (;3;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;4;)) + (alias core export 2 "memory" (core memory (;1;))) + (alias core export 2 "__indirect_function_table" (core table (;0;))) + (alias core export 2 "__stack_pointer" (core global (;2;))) + (alias core export 2 "c:memory_base" (core global (;3;))) + (alias core export 2 "c:table_base" (core global (;4;))) + (core instance (;5;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + ) + (core instance (;6;) (instantiate 1 + (with "GOT.mem" (instance 3)) + (with "GOT.func" (instance 4)) + (with "env" (instance 5)) + ) + ) + (alias core export 2 "__heap_base" (core global (;5;))) + (alias core export 2 "__heap_end" (core global (;6;))) + (core instance (;7;) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + ) + (core instance (;8;)) + (alias core export 2 "memory" (core memory (;2;))) + (alias core export 2 "__indirect_function_table" (core table (;1;))) + (alias core export 2 "__stack_pointer" (core global (;7;))) + (alias core export 2 "foo:memory_base" (core global (;8;))) + (alias core export 2 "foo:table_base" (core global (;9;))) + (core instance (;9;) + (export "memory" (memory 2)) + (export "__indirect_function_table" (table 1)) + (export "__stack_pointer" (global 7)) + (export "__memory_base" (global 8)) + (export "__table_base" (global 9)) + ) + (core func (;2;) (canon lower (func 0))) + (alias core export 0 "0" (core func (;3;))) + (core instance (;10;) + (export "foo1" (func 2)) + (export "bar" (func 3)) + ) + (core instance (;11;) (instantiate 2 + (with "GOT.mem" (instance 7)) + (with "GOT.func" (instance 8)) + (with "env" (instance 9)) + (with "$root" (instance 10)) + ) + ) + (alias core export 11 "cabi_export_realloc" (core func (;4;))) + (alias core export 11 "cabi_import_realloc" (core func (;5;))) + (alias core export 0 "$imports" (core table (;2;))) + (core func (;6;) (canon lower (func 1) (memory 0) (realloc 5) string-encoding=utf8)) + (alias core export 11 "cabi_realloc" (core func (;7;))) + (core instance (;12;) + (export "$imports" (table 2)) + (export "0" (func 6)) + (export "1" (func 7)) + ) + (core instance (;13;) (instantiate 5 + (with "" (instance 12)) + ) + ) + (core instance (;14;) (instantiate 3 + (with "env" (instance 2)) + (with "c" (instance 6)) + (with "foo" (instance 11)) + ) + ) + (alias core export 11 "baz" (core func (;8;))) + (func (;2;) (type 0) (canon lift (core func 8))) + (export (;3;) "baz" (func 2)) + (type (;2;) (list u8)) + (type (;3;) (option 2)) + (type (;4;) (func (param "x" string) (result 3))) + (alias core export 11 "foo2" (core func (;9;))) + (alias core export 11 "cabi_post_foo2" (core func (;10;))) + (func (;4;) (type 4) (canon lift (core func 9) (memory 0) (realloc 4) string-encoding=utf8 (post-return 10))) + (export (;5;) "foo2" (func 4)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link-bare-funcs/component.wit.print b/crates/wit-component/tests/components/link-bare-funcs/component.wit.print new file mode 100644 index 0000000000..faea89c97d --- /dev/null +++ b/crates/wit-component/tests/components/link-bare-funcs/component.wit.print @@ -0,0 +1,9 @@ +package root:component + +world root { + import foo1: func() + import bar: func() -> string + + export baz: func() + export foo2: func(x: string) -> option> +} diff --git a/crates/wit-component/tests/components/link-bare-funcs/lib-c.wat b/crates/wit-component/tests/components/link-bare-funcs/lib-c.wat new file mode 100644 index 0000000000..7798b7d6dd --- /dev/null +++ b/crates/wit-component/tests/components/link-bare-funcs/lib-c.wat @@ -0,0 +1,27 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func)) + (type (func (param i32) (result i32))) + (import "GOT.mem" "__heap_base" (global $__heap_base (mut i32))) + (import "GOT.mem" "__heap_end" (global $__heap_end (mut i32))) + (global $heap (mut i32) i32.const 0) + (func $start (type 0) + global.get $__heap_base + global.set $heap + ) + (func $malloc (type 1) (param i32) (result i32) + global.get $heap + global.get $heap + local.get 0 + i32.add + global.set $heap + ) + (func $abort (type 0) + unreachable + ) + (export "malloc" (func $malloc)) + (export "abort" (func $abort)) + (start $start) +) diff --git a/crates/wit-component/tests/components/link-bare-funcs/lib-c.wit b/crates/wit-component/tests/components/link-bare-funcs/lib-c.wit new file mode 100644 index 0000000000..262c853de3 --- /dev/null +++ b/crates/wit-component/tests/components/link-bare-funcs/lib-c.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-c { } diff --git a/crates/wit-component/tests/components/link-bare-funcs/lib-foo.wat b/crates/wit-component/tests/components/link-bare-funcs/lib-foo.wat new file mode 100644 index 0000000000..7f3eaf85ca --- /dev/null +++ b/crates/wit-component/tests/components/link-bare-funcs/lib-foo.wat @@ -0,0 +1,18 @@ +(module + (@dylink.0 + (mem-info (memory 4 4)) + (needed "c") + ) + (import "env" "memory" (memory 1)) + (import "$root" "foo1" (func)) + (import "$root" "bar" (func (param i32))) + + (func (export "baz")) + + (func (export "foo2") (param i32 i32) (result i32) unreachable) + (func (export "cabi_post_foo2") (param i32) unreachable) + + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "cabi_import_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "cabi_export_realloc") (param i32 i32 i32 i32) (result i32) unreachable) +) diff --git a/crates/wit-component/tests/components/link-bare-funcs/lib-foo.wit b/crates/wit-component/tests/components/link-bare-funcs/lib-foo.wit new file mode 100644 index 0000000000..0406d9fb02 --- /dev/null +++ b/crates/wit-component/tests/components/link-bare-funcs/lib-foo.wit @@ -0,0 +1,7 @@ +package test:test; +world lib-foo { + import foo1: func(); + import bar: func() -> string; + export baz: func(); + export foo2: func(x: string) -> option>; +} diff --git a/crates/wit-component/tests/components/link-circular/component.wat b/crates/wit-component/tests/components/link-circular/component.wat new file mode 100644 index 0000000000..236337722a --- /dev/null +++ b/crates/wit-component/tests/components/link-circular/component.wat @@ -0,0 +1,169 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "v" s32) (result s32))) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import (interface "test:test/test") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (table (;0;) 1 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048592) + (global (;2;) i32 i32.const 0) + (global (;3;) i32 i32.const 1048592) + (global (;4;) i32 i32.const 0) + (global (;5;) (mut i32) i32.const 1048592) + (global (;6;) (mut i32) i32.const 1114112) + (export "__stack_pointer" (global 0)) + (export "bar:memory_base" (global 1)) + (export "bar:table_base" (global 2)) + (export "foo:memory_base" (global 3)) + (export "foo:table_base" (global 4)) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + (export "foo" (func 0)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (@dylink.0 + (mem-info (memory 0 4)) + (needed "foo") + ) + (type (;0;) (func (param i32) (result i32))) + (import "env" "foo" (func $import_foo (;0;) (type 0))) + (func $bar (;1;) (type 0) (param i32) (result i32) + unreachable + ) + (export "bar" (func $bar)) + ) + (core module (;2;) + (@dylink.0 + (mem-info (memory 0 4)) + (needed "bar") + ) + (type (;0;) (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (;0;) (type 0))) + (import "env" "foo" (func $import_foo2 (;1;) (type 0))) + (import "env" "bar" (func $import_bar (;2;) (type 0))) + (func $foo (;3;) (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) + (export "foo" (func $foo)) + ) + (core module (;3;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i32) (result i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "foo" "foo" (func (;0;) (type 2))) + (func (;1;) (type 0)) + (start 1) + (elem (;0;) (i32.const 0) func) + (elem (;1;) (i32.const 0) func 0) + (data (;0;) (i32.const 1048576) "\00\00\00\00\00\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "__heap_base" (core global (;0;))) + (alias core export 0 "__heap_end" (core global (;1;))) + (core instance (;1;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;2;)) + (alias core export 0 "memory" (core memory (;1;))) + (alias core export 0 "__indirect_function_table" (core table (;0;))) + (alias core export 0 "__stack_pointer" (core global (;2;))) + (alias core export 0 "bar:memory_base" (core global (;3;))) + (alias core export 0 "bar:table_base" (core global (;4;))) + (alias core export 0 "foo" (core func (;0;))) + (core instance (;3;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + (export "foo" (func 0)) + ) + (core instance (;4;) (instantiate 1 + (with "GOT.mem" (instance 1)) + (with "GOT.func" (instance 2)) + (with "env" (instance 3)) + ) + ) + (alias core export 0 "__heap_base" (core global (;5;))) + (alias core export 0 "__heap_end" (core global (;6;))) + (core instance (;5;) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + ) + (core instance (;6;)) + (alias core export 0 "memory" (core memory (;2;))) + (alias core export 0 "__indirect_function_table" (core table (;1;))) + (alias core export 0 "__stack_pointer" (core global (;7;))) + (alias core export 0 "foo:memory_base" (core global (;8;))) + (alias core export 0 "foo:table_base" (core global (;9;))) + (alias core export 4 "bar" (core func (;1;))) + (alias core export 0 "foo" (core func (;2;))) + (core instance (;7;) + (export "memory" (memory 2)) + (export "__indirect_function_table" (table 1)) + (export "__stack_pointer" (global 7)) + (export "__memory_base" (global 8)) + (export "__table_base" (global 9)) + (export "bar" (func 1)) + (export "foo" (func 2)) + ) + (alias export 0 "foo" (func (;0;))) + (core func (;3;) (canon lower (func 0))) + (core instance (;8;) + (export "foo" (func 3)) + ) + (core instance (;9;) (instantiate 2 + (with "GOT.mem" (instance 5)) + (with "GOT.func" (instance 6)) + (with "env" (instance 7)) + (with "test:test/test" (instance 8)) + ) + ) + (core instance (;10;) (instantiate 3 + (with "env" (instance 0)) + (with "bar" (instance 4)) + (with "foo" (instance 9)) + ) + ) + (type (;1;) (func (param "v" s32) (result s32))) + (alias core export 9 "test:test/test#foo" (core func (;4;))) + (func (;1;) (type 1) (canon lift (core func 4))) + (component (;0;) + (type (;0;) (func (param "v" s32) (result s32))) + (import "import-func-foo" (func (;0;) (type 0))) + (type (;1;) (func (param "v" s32) (result s32))) + (export (;1;) "foo" (func 0) (func (type 1))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-foo" (func 1)) + ) + ) + (export (;2;) (interface "test:test/test") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link-circular/component.wit.print b/crates/wit-component/tests/components/link-circular/component.wit.print new file mode 100644 index 0000000000..d02a685b6f --- /dev/null +++ b/crates/wit-component/tests/components/link-circular/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import test:test/test + + export test:test/test +} diff --git a/crates/wit-component/tests/components/link-circular/lib-bar.wat b/crates/wit-component/tests/components/link-circular/lib-bar.wat new file mode 100644 index 0000000000..d6be27aecb --- /dev/null +++ b/crates/wit-component/tests/components/link-circular/lib-bar.wat @@ -0,0 +1,12 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (needed "foo") + ) + (type (func (param i32) (result i32))) + (import "env" "foo" (func $import_foo (type 0))) + (func $bar (type 0) (param i32) (result i32) + unreachable + ) + (export "bar" (func $bar)) +) diff --git a/crates/wit-component/tests/components/link-circular/lib-bar.wit b/crates/wit-component/tests/components/link-circular/lib-bar.wit new file mode 100644 index 0000000000..ad16c9bf4c --- /dev/null +++ b/crates/wit-component/tests/components/link-circular/lib-bar.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-bar { } diff --git a/crates/wit-component/tests/components/link-circular/lib-foo.wat b/crates/wit-component/tests/components/link-circular/lib-foo.wat new file mode 100644 index 0000000000..bae469a0bf --- /dev/null +++ b/crates/wit-component/tests/components/link-circular/lib-foo.wat @@ -0,0 +1,15 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (needed "bar") + ) + (type (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (import "env" "foo" (func $import_foo2 (type 0))) + (import "env" "bar" (func $import_bar (type 0))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) + (export "foo" (func $foo)) +) diff --git a/crates/wit-component/tests/components/link-circular/lib-foo.wit b/crates/wit-component/tests/components/link-circular/lib-foo.wit new file mode 100644 index 0000000000..576de43434 --- /dev/null +++ b/crates/wit-component/tests/components/link-circular/lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/link-dl-openable/component.wat b/crates/wit-component/tests/components/link-dl-openable/component.wat new file mode 100644 index 0000000000..2ce93d8fd4 --- /dev/null +++ b/crates/wit-component/tests/components/link-dl-openable/component.wat @@ -0,0 +1,126 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "v" s32) (result s32))) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import (interface "test:test/test") (instance (;0;) (type 0))) + (core module (;0;) + (table (;0;) 3 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048688) + (global (;2;) i32 i32.const 3) + (global (;3;) (mut i32) i32.const 1048688) + (global (;4;) (mut i32) i32.const 1114112) + (export "__stack_pointer" (global 0)) + (export "foo:memory_base" (global 1)) + (export "foo:table_base" (global 2)) + (export "__heap_base" (global 3)) + (export "__heap_end" (global 4)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (;0;) (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (;0;) (type 0))) + (func $foo (;1;) (type 0) (param i32) (result i32) + unreachable + ) + (global $what (;0;) i32 i32.const 42) + (export "test:test/test#foo" (func $foo)) + (export "bar" (func $foo)) + (export "baz" (func $foo)) + (export "what" (global $what)) + ) + (core module (;2;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i32) (result i32))) + (type (;4;) (func (param i32) (result i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "env" "foo:memory_base" (global (;0;) i32)) + (import "foo" "what" (global (;1;) i32)) + (import "foo" "bar" (func (;0;) (type 2))) + (import "foo" "baz" (func (;1;) (type 3))) + (import "foo" "test:test/test#foo" (func (;2;) (type 4))) + (func (;3;) (type 0) + i32.const 1048656 + global.get 0 + global.get 1 + i32.add + i32.store + ) + (start 3) + (elem (;0;) (i32.const 0) func 0 1 2) + (elem (;1;) (i32.const 3) func) + (data (;0;) (i32.const 1048576) "foo\00bar\00baz\00test:test/test#foo\00\00what\03\00\00\00\04\00\10\00\00\00\00\00\03\00\00\00\08\00\10\00\01\00\00\00\12\00\00\00\0c\00\10\00\02\00\00\00\04\00\00\00 \00\10\00\00\00\00\00\03\00\00\00\00\00\10\00\04\00\00\00$\00\10\00\01\00\00\00T\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "__heap_base" (core global (;0;))) + (alias core export 0 "__heap_end" (core global (;1;))) + (core instance (;1;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;2;)) + (alias core export 0 "memory" (core memory (;1;))) + (alias core export 0 "__indirect_function_table" (core table (;0;))) + (alias core export 0 "__stack_pointer" (core global (;2;))) + (alias core export 0 "foo:memory_base" (core global (;3;))) + (alias core export 0 "foo:table_base" (core global (;4;))) + (core instance (;3;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + ) + (alias export 0 "foo" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;4;) + (export "foo" (func 0)) + ) + (core instance (;5;) (instantiate 1 + (with "GOT.mem" (instance 1)) + (with "GOT.func" (instance 2)) + (with "env" (instance 3)) + (with "test:test/test" (instance 4)) + ) + ) + (core instance (;6;) (instantiate 2 + (with "env" (instance 0)) + (with "foo" (instance 5)) + ) + ) + (type (;1;) (func (param "v" s32) (result s32))) + (alias core export 5 "test:test/test#foo" (core func (;1;))) + (func (;1;) (type 1) (canon lift (core func 1))) + (component (;0;) + (type (;0;) (func (param "v" s32) (result s32))) + (import "import-func-foo" (func (;0;) (type 0))) + (type (;1;) (func (param "v" s32) (result s32))) + (export (;1;) "foo" (func 0) (func (type 1))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-foo" (func 1)) + ) + ) + (export (;2;) (interface "test:test/test") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link-dl-openable/component.wit.print b/crates/wit-component/tests/components/link-dl-openable/component.wit.print new file mode 100644 index 0000000000..d02a685b6f --- /dev/null +++ b/crates/wit-component/tests/components/link-dl-openable/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import test:test/test + + export test:test/test +} diff --git a/crates/wit-component/tests/components/link-dl-openable/dlopen-lib-foo.wat b/crates/wit-component/tests/components/link-dl-openable/dlopen-lib-foo.wat new file mode 100644 index 0000000000..66c6459ce0 --- /dev/null +++ b/crates/wit-component/tests/components/link-dl-openable/dlopen-lib-foo.wat @@ -0,0 +1,15 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (global $what i32 i32.const 42) + (export "test:test/test#foo" (func $foo)) + (export "bar" (func $foo)) + (export "baz" (func $foo)) + (export "what" (global $what)) +) diff --git a/crates/wit-component/tests/components/link-dl-openable/dlopen-lib-foo.wit b/crates/wit-component/tests/components/link-dl-openable/dlopen-lib-foo.wit new file mode 100644 index 0000000000..41eb6cf477 --- /dev/null +++ b/crates/wit-component/tests/components/link-dl-openable/dlopen-lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world dlopen-lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/link-got-func/component.wat b/crates/wit-component/tests/components/link-got-func/component.wat new file mode 100644 index 0000000000..10cff03621 --- /dev/null +++ b/crates/wit-component/tests/components/link-got-func/component.wat @@ -0,0 +1,163 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "v" s32) (result s32))) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import (interface "test:test/test") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.const 0 + call_indirect (type 0) + ) + (table (;0;) 1 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048592) + (global (;2;) i32 i32.const 0) + (global (;3;) i32 i32.const 1048592) + (global (;4;) i32 i32.const 0) + (global (;5;) (mut i32) i32.const 0) + (global (;6;) (mut i32) i32.const 1048592) + (global (;7;) (mut i32) i32.const 1114112) + (export "__stack_pointer" (global 0)) + (export "bar:memory_base" (global 1)) + (export "bar:table_base" (global 2)) + (export "foo:memory_base" (global 3)) + (export "foo:table_base" (global 4)) + (export "foo:foo" (global 5)) + (export "__heap_base" (global 6)) + (export "__heap_end" (global 7)) + (export "foo" (func 0)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (;0;) (func (param i32) (result i32))) + (func $foo (;0;) (type 0) (param i32) (result i32) + unreachable + ) + (export "foo" (func $foo)) + ) + (core module (;2;) + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (;0;) (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (;0;) (type 0))) + (import "env" "foo" (func $import_foo2 (;1;) (type 0))) + (import "GOT.func" "foo" (global $import_foo2_address (;0;) (mut i32))) + (export "test:test/test#foo" (func $import_foo2)) + ) + (core module (;3;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i32) (result i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "bar" "foo" (func (;0;) (type 2))) + (func (;1;) (type 0)) + (start 1) + (elem (;0;) (i32.const 0) func) + (elem (;1;) (i32.const 0) func 0) + (data (;0;) (i32.const 1048576) "\00\00\00\00\00\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "__heap_base" (core global (;0;))) + (alias core export 0 "__heap_end" (core global (;1;))) + (core instance (;1;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;2;)) + (alias core export 0 "memory" (core memory (;1;))) + (alias core export 0 "__indirect_function_table" (core table (;0;))) + (alias core export 0 "__stack_pointer" (core global (;2;))) + (alias core export 0 "bar:memory_base" (core global (;3;))) + (alias core export 0 "bar:table_base" (core global (;4;))) + (core instance (;3;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + ) + (core instance (;4;) (instantiate 1 + (with "GOT.mem" (instance 1)) + (with "GOT.func" (instance 2)) + (with "env" (instance 3)) + ) + ) + (alias core export 0 "__heap_base" (core global (;5;))) + (alias core export 0 "__heap_end" (core global (;6;))) + (core instance (;5;) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + ) + (alias core export 0 "foo:foo" (core global (;7;))) + (core instance (;6;) + (export "foo" (global 7)) + ) + (alias core export 0 "memory" (core memory (;2;))) + (alias core export 0 "__indirect_function_table" (core table (;1;))) + (alias core export 0 "__stack_pointer" (core global (;8;))) + (alias core export 0 "foo:memory_base" (core global (;9;))) + (alias core export 0 "foo:table_base" (core global (;10;))) + (alias core export 4 "foo" (core func (;0;))) + (core instance (;7;) + (export "memory" (memory 2)) + (export "__indirect_function_table" (table 1)) + (export "__stack_pointer" (global 8)) + (export "__memory_base" (global 9)) + (export "__table_base" (global 10)) + (export "foo" (func 0)) + ) + (alias export 0 "foo" (func (;0;))) + (core func (;1;) (canon lower (func 0))) + (core instance (;8;) + (export "foo" (func 1)) + ) + (core instance (;9;) (instantiate 2 + (with "GOT.mem" (instance 5)) + (with "GOT.func" (instance 6)) + (with "env" (instance 7)) + (with "test:test/test" (instance 8)) + ) + ) + (core instance (;10;) (instantiate 3 + (with "env" (instance 0)) + (with "bar" (instance 4)) + (with "foo" (instance 9)) + ) + ) + (type (;1;) (func (param "v" s32) (result s32))) + (alias core export 9 "test:test/test#foo" (core func (;2;))) + (func (;1;) (type 1) (canon lift (core func 2))) + (component (;0;) + (type (;0;) (func (param "v" s32) (result s32))) + (import "import-func-foo" (func (;0;) (type 0))) + (type (;1;) (func (param "v" s32) (result s32))) + (export (;1;) "foo" (func 0) (func (type 1))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-foo" (func 1)) + ) + ) + (export (;2;) (interface "test:test/test") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link-got-func/component.wit.print b/crates/wit-component/tests/components/link-got-func/component.wit.print new file mode 100644 index 0000000000..d02a685b6f --- /dev/null +++ b/crates/wit-component/tests/components/link-got-func/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import test:test/test + + export test:test/test +} diff --git a/crates/wit-component/tests/components/link-got-func/lib-bar.wat b/crates/wit-component/tests/components/link-got-func/lib-bar.wat new file mode 100644 index 0000000000..0b76c23ea7 --- /dev/null +++ b/crates/wit-component/tests/components/link-got-func/lib-bar.wat @@ -0,0 +1,10 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func (param i32) (result i32))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (export "foo" (func $foo)) +) diff --git a/crates/wit-component/tests/components/link-got-func/lib-bar.wit b/crates/wit-component/tests/components/link-got-func/lib-bar.wit new file mode 100644 index 0000000000..ad16c9bf4c --- /dev/null +++ b/crates/wit-component/tests/components/link-got-func/lib-bar.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-bar { } diff --git a/crates/wit-component/tests/components/link-got-func/lib-foo.wat b/crates/wit-component/tests/components/link-got-func/lib-foo.wat new file mode 100644 index 0000000000..26f9535cae --- /dev/null +++ b/crates/wit-component/tests/components/link-got-func/lib-foo.wat @@ -0,0 +1,10 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (import "env" "foo" (func $import_foo2 (type 0))) + (import "GOT.func" "foo" (global $import_foo2_address (mut i32))) + (export "test:test/test#foo" (func $import_foo2)) +) diff --git a/crates/wit-component/tests/components/link-got-func/lib-foo.wit b/crates/wit-component/tests/components/link-got-func/lib-foo.wit new file mode 100644 index 0000000000..576de43434 --- /dev/null +++ b/crates/wit-component/tests/components/link-got-func/lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/link-initialize/component.wat b/crates/wit-component/tests/components/link-initialize/component.wat new file mode 100644 index 0000000000..bb3828621a --- /dev/null +++ b/crates/wit-component/tests/components/link-initialize/component.wat @@ -0,0 +1,300 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "v" s32) (result s32))) + (export (;0;) "bar" (func (type 0))) + ) + ) + (import (interface "test:test/test") (instance (;0;) (type 0))) + (core module (;0;) + (table (;0;) 0 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048592) + (global (;2;) i32 i32.const 0) + (global (;3;) (mut i32) i32.const 0) + (global (;4;) i32 i32.const 1048624) + (global (;5;) i32 i32.const 0) + (global (;6;) i32 i32.const 1048624) + (global (;7;) i32 i32.const 0) + (global (;8;) (mut i32) i32.const 0) + (global (;9;) (mut i32) i32.const 1048640) + (global (;10;) (mut i32) i32.const 1114112) + (export "__stack_pointer" (global 0)) + (export "bar:memory_base" (global 1)) + (export "bar:table_base" (global 2)) + (export "bar:well" (global 3)) + (export "c:memory_base" (global 4)) + (export "c:table_base" (global 5)) + (export "foo:memory_base" (global 6)) + (export "foo:table_base" (global 7)) + (export "foo:um" (global 8)) + (export "__heap_base" (global 9)) + (export "__heap_end" (global 10)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (import "GOT.mem" "__heap_base" (global $__heap_base (;0;) (mut i32))) + (import "GOT.mem" "__heap_end" (global $__heap_end (;1;) (mut i32))) + (func $start (;0;) (type 0) + global.get $__heap_base + global.set $heap + ) + (func $malloc (;1;) (type 1) (param i32) (result i32) + global.get $heap + global.get $heap + local.get 0 + i32.add + global.set $heap + ) + (func $abort (;2;) (type 0) + unreachable + ) + (global $heap (;2;) (mut i32) i32.const 0) + (export "malloc" (func $malloc)) + (export "abort" (func $abort)) + (start $start) + ) + (core module (;2;) + (@dylink.0 + (mem-info (memory 4 4)) + (needed "c") + ) + (type $.data (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (import "env" "memory" (memory (;0;) 1)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "env" "__stack_pointer" (global $__stack_pointer (;0;) (mut i32))) + (import "env" "__memory_base" (global $__memory_base (;1;) i32)) + (import "env" "__table_base" (global $__table_base (;2;) i32)) + (import "env" "malloc" (func $malloc (;0;) (type 1))) + (import "env" "abort" (func $abort (;1;) (type $.data))) + (import "GOT.mem" "um" (global $um (;3;) (mut i32))) + (import "test:test/test" "bar" (func $bar (;2;) (type 1))) + (func $_initialize (;3;) (type $.data)) + (func $__wasm_apply_data_relocs (;4;) (type $.data)) + (func $foo (;5;) (type 1) (param i32) (result i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + global.set $__stack_pointer + i32.const 4 + call $malloc + i32.const 0 + i32.eq + if ;; label = @1 + call $abort + unreachable + end + local.get 0 + global.get $um + i32.load offset=16 + i32.add + i32.const 42 + i32.add + call $bar + global.get $__stack_pointer + i32.const 16 + i32.add + global.set $__stack_pointer + ) + (global (;4;) i32 i32.const 0) + (export "_initialize" (func $_initialize)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "foo" (func $foo)) + (export "well" (global 4)) + (data (;0;) (global.get $__memory_base) "\04\00\00\00") + ) + (core module (;3;) + (@dylink.0 + (mem-info (memory 20 4)) + (needed "foo") + ) + (type $.data (;0;) (func (param i32) (result i32))) + (type (;1;) (func)) + (import "env" "memory" (memory (;0;) 1)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "env" "__memory_base" (global $__memory_base (;0;) i32)) + (import "env" "__table_base" (global $__table_base (;1;) i32)) + (import "env" "foo" (func $foo (;0;) (type $.data))) + (import "GOT.mem" "well" (global $well (;2;) (mut i32))) + (func $_initialize (;1;) (type 1)) + (func $__wasm_apply_data_relocs (;2;) (type 1)) + (func $bar (;3;) (type $.data) (param i32) (result i32) + local.get 0 + call $foo + global.get $well + i32.load + i32.add + ) + (global (;3;) i32 i32.const 0) + (export "_initialize" (func $_initialize)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "test:test/test#bar" (func $bar)) + (export "um" (global 3)) + (data (;0;) (global.get $__memory_base) "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00") + ) + (core module (;4;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "bar" "__wasm_apply_data_relocs" (func (;0;) (type 0))) + (import "bar" "_initialize" (func (;1;) (type 0))) + (import "env" "foo:memory_base" (global (;0;) i32)) + (import "foo" "well" (global (;1;) i32)) + (import "env" "bar:well" (global (;2;) (mut i32))) + (import "foo" "__wasm_apply_data_relocs" (func (;2;) (type 0))) + (import "foo" "_initialize" (func (;3;) (type 0))) + (import "env" "bar:memory_base" (global (;3;) i32)) + (import "bar" "um" (global (;4;) i32)) + (import "env" "foo:um" (global (;5;) (mut i32))) + (func (;4;) (type 0) + global.get 0 + global.get 1 + i32.add + global.set 2 + global.get 3 + global.get 4 + i32.add + global.set 5 + call 0 + call 2 + call 1 + call 3 + ) + (start 4) + (elem (;0;) (i32.const 0) func) + (elem (;1;) (i32.const 0) func) + (data (;0;) (i32.const 1048576) "\00\00\00\00\00\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "__heap_base" (core global (;0;))) + (alias core export 0 "__heap_end" (core global (;1;))) + (core instance (;1;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;2;)) + (alias core export 0 "memory" (core memory (;1;))) + (alias core export 0 "__indirect_function_table" (core table (;0;))) + (alias core export 0 "__stack_pointer" (core global (;2;))) + (alias core export 0 "c:memory_base" (core global (;3;))) + (alias core export 0 "c:table_base" (core global (;4;))) + (core instance (;3;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + ) + (core instance (;4;) (instantiate 1 + (with "GOT.mem" (instance 1)) + (with "GOT.func" (instance 2)) + (with "env" (instance 3)) + ) + ) + (alias core export 0 "foo:um" (core global (;5;))) + (alias core export 0 "__heap_base" (core global (;6;))) + (alias core export 0 "__heap_end" (core global (;7;))) + (core instance (;5;) + (export "um" (global 5)) + (export "__heap_base" (global 6)) + (export "__heap_end" (global 7)) + ) + (core instance (;6;)) + (alias core export 0 "memory" (core memory (;2;))) + (alias core export 0 "__indirect_function_table" (core table (;1;))) + (alias core export 0 "__stack_pointer" (core global (;8;))) + (alias core export 0 "foo:memory_base" (core global (;9;))) + (alias core export 0 "foo:table_base" (core global (;10;))) + (alias core export 4 "abort" (core func (;0;))) + (alias core export 4 "malloc" (core func (;1;))) + (core instance (;7;) + (export "memory" (memory 2)) + (export "__indirect_function_table" (table 1)) + (export "__stack_pointer" (global 8)) + (export "__memory_base" (global 9)) + (export "__table_base" (global 10)) + (export "abort" (func 0)) + (export "malloc" (func 1)) + ) + (alias export 0 "bar" (func (;0;))) + (core func (;2;) (canon lower (func 0))) + (core instance (;8;) + (export "bar" (func 2)) + ) + (core instance (;9;) (instantiate 2 + (with "GOT.mem" (instance 5)) + (with "GOT.func" (instance 6)) + (with "env" (instance 7)) + (with "test:test/test" (instance 8)) + ) + ) + (alias core export 0 "bar:well" (core global (;11;))) + (alias core export 0 "__heap_base" (core global (;12;))) + (alias core export 0 "__heap_end" (core global (;13;))) + (core instance (;10;) + (export "well" (global 11)) + (export "__heap_base" (global 12)) + (export "__heap_end" (global 13)) + ) + (core instance (;11;)) + (alias core export 0 "memory" (core memory (;3;))) + (alias core export 0 "__indirect_function_table" (core table (;2;))) + (alias core export 0 "__stack_pointer" (core global (;14;))) + (alias core export 0 "bar:memory_base" (core global (;15;))) + (alias core export 0 "bar:table_base" (core global (;16;))) + (alias core export 9 "foo" (core func (;3;))) + (core instance (;12;) + (export "memory" (memory 3)) + (export "__indirect_function_table" (table 2)) + (export "__stack_pointer" (global 14)) + (export "__memory_base" (global 15)) + (export "__table_base" (global 16)) + (export "foo" (func 3)) + ) + (core instance (;13;) (instantiate 3 + (with "GOT.mem" (instance 10)) + (with "GOT.func" (instance 11)) + (with "env" (instance 12)) + ) + ) + (core instance (;14;) (instantiate 4 + (with "env" (instance 0)) + (with "bar" (instance 13)) + (with "c" (instance 4)) + (with "foo" (instance 9)) + ) + ) + (type (;1;) (func (param "v" s32) (result s32))) + (alias core export 13 "test:test/test#bar" (core func (;4;))) + (func (;1;) (type 1) (canon lift (core func 4))) + (component (;0;) + (type (;0;) (func (param "v" s32) (result s32))) + (import "import-func-bar" (func (;0;) (type 0))) + (type (;1;) (func (param "v" s32) (result s32))) + (export (;1;) "bar" (func 0) (func (type 1))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-bar" (func 1)) + ) + ) + (export (;2;) (interface "test:test/test") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link-initialize/component.wit.print b/crates/wit-component/tests/components/link-initialize/component.wit.print new file mode 100644 index 0000000000..d02a685b6f --- /dev/null +++ b/crates/wit-component/tests/components/link-initialize/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import test:test/test + + export test:test/test +} diff --git a/crates/wit-component/tests/components/link-initialize/lib-bar.wat b/crates/wit-component/tests/components/link-initialize/lib-bar.wat new file mode 100644 index 0000000000..776295c23e --- /dev/null +++ b/crates/wit-component/tests/components/link-initialize/lib-bar.wat @@ -0,0 +1,29 @@ +(module + (@dylink.0 + (mem-info (memory 20 4)) + (needed "foo") + ) + (type (func (param i32) (result i32))) + (type (func)) + (import "env" "memory" (memory 1)) + (import "env" "__indirect_function_table" (table 0 funcref)) + (import "env" "__memory_base" (global $__memory_base i32)) + (import "env" "__table_base" (global $__table_base i32)) + (import "env" "foo" (func $foo (type 0))) + (import "GOT.mem" "well" (global $well (mut i32))) + (func $_initialize (type 1)) + (func $__wasm_apply_data_relocs (type 1)) + (func $bar (type 0) (param i32) (result i32) + local.get 0 + call $foo + global.get $well + i32.load + i32.add + ) + (global i32 i32.const 0) + (export "_initialize" (func $_initialize)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "test:test/test#bar" (func $bar)) + (export "um" (global 3)) + (data $.data (global.get $__memory_base) "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00") +) diff --git a/crates/wit-component/tests/components/link-initialize/lib-bar.wit b/crates/wit-component/tests/components/link-initialize/lib-bar.wit new file mode 100644 index 0000000000..9cab0b5e2e --- /dev/null +++ b/crates/wit-component/tests/components/link-initialize/lib-bar.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + bar: func(v: s32) -> s32; +} + +world lib-bar { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/link-initialize/lib-c.wat b/crates/wit-component/tests/components/link-initialize/lib-c.wat new file mode 100644 index 0000000000..7798b7d6dd --- /dev/null +++ b/crates/wit-component/tests/components/link-initialize/lib-c.wat @@ -0,0 +1,27 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func)) + (type (func (param i32) (result i32))) + (import "GOT.mem" "__heap_base" (global $__heap_base (mut i32))) + (import "GOT.mem" "__heap_end" (global $__heap_end (mut i32))) + (global $heap (mut i32) i32.const 0) + (func $start (type 0) + global.get $__heap_base + global.set $heap + ) + (func $malloc (type 1) (param i32) (result i32) + global.get $heap + global.get $heap + local.get 0 + i32.add + global.set $heap + ) + (func $abort (type 0) + unreachable + ) + (export "malloc" (func $malloc)) + (export "abort" (func $abort)) + (start $start) +) diff --git a/crates/wit-component/tests/components/link-initialize/lib-c.wit b/crates/wit-component/tests/components/link-initialize/lib-c.wit new file mode 100644 index 0000000000..262c853de3 --- /dev/null +++ b/crates/wit-component/tests/components/link-initialize/lib-c.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-c { } diff --git a/crates/wit-component/tests/components/link-initialize/lib-foo.wat b/crates/wit-component/tests/components/link-initialize/lib-foo.wat new file mode 100644 index 0000000000..4fdebe2275 --- /dev/null +++ b/crates/wit-component/tests/components/link-initialize/lib-foo.wat @@ -0,0 +1,55 @@ +(module + (@dylink.0 + (mem-info (memory 4 4)) + (needed "c") + ) + (type (func)) + (type (func (param i32) (result i32))) + (import "env" "memory" (memory 1)) + (import "env" "__indirect_function_table" (table 0 funcref)) + (import "env" "__stack_pointer" (global $__stack_pointer (mut i32))) + (import "env" "__memory_base" (global $__memory_base i32)) + (import "env" "__table_base" (global $__table_base i32)) + (import "env" "malloc" (func $malloc (type 1))) + (import "env" "abort" (func $abort (type 0))) + (import "GOT.mem" "um" (global $um (mut i32))) + (import "test:test/test" "bar" (func $bar (type 1))) + (func $_initialize (type 0)) + (func $__wasm_apply_data_relocs (type 0)) + (func $foo (type 1) (param i32) (result i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + global.set $__stack_pointer + + i32.const 4 + call $malloc + + i32.const 0 + i32.eq + if + call $abort + unreachable + end + + local.get 0 + global.get $um + i32.load offset=16 + i32.add + i32.const 42 + i32.add + + call $bar + + global.get $__stack_pointer + i32.const 16 + i32.add + global.set $__stack_pointer + ) + (global i32 i32.const 0) + (export "_initialize" (func $_initialize)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "foo" (func $foo)) + (export "well" (global 4)) + (data $.data (global.get $__memory_base) "\04\00\00\00") +) diff --git a/crates/wit-component/tests/components/link-initialize/lib-foo.wit b/crates/wit-component/tests/components/link-initialize/lib-foo.wit new file mode 100644 index 0000000000..3171fc9990 --- /dev/null +++ b/crates/wit-component/tests/components/link-initialize/lib-foo.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-foo { } diff --git a/crates/wit-component/tests/components/link-resources/component.wat b/crates/wit-component/tests/components/link-resources/component.wat new file mode 100644 index 0000000000..8794c06701 --- /dev/null +++ b/crates/wit-component/tests/components/link-resources/component.wat @@ -0,0 +1,196 @@ +(component + (core module (;0;) + (table (;0;) 0 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048592) + (global (;2;) i32 i32.const 0) + (global (;3;) i32 i32.const 1048592) + (global (;4;) i32 i32.const 0) + (global (;5;) (mut i32) i32.const 1048592) + (global (;6;) (mut i32) i32.const 1114112) + (export "__stack_pointer" (global 0)) + (export "bar:memory_base" (global 1)) + (export "bar:table_base" (global 2)) + (export "foo:memory_base" (global 3)) + (export "foo:table_base" (global 4)) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (;0;) (func (param i32) (result i32))) + (func $foo (;0;) (type 0) (param i32) (result i32) + unreachable + ) + (func $x_ctor (;1;) (type 0) (param i32) (result i32) + unreachable + ) + (func $x_get (;2;) (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/foo#[constructor]x" (func $x_ctor)) + (export "test:test/foo#[method]x.get" (func $x_get)) + ) + (core module (;2;) + (@dylink.0 + (mem-info (memory 0 4)) + (needed "foo") + ) + (type (;0;) (func (param i32) (result i32))) + (func $x_ctor (;0;) (type 0) (param i32) (result i32) + unreachable + ) + (func $x_get (;1;) (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/bar#[constructor]x" (func $x_ctor)) + (export "test:test/bar#[method]x.get" (func $x_get)) + ) + (core module (;3;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (func (;0;) (type 0)) + (start 0) + (elem (;0;) (i32.const 0) func) + (elem (;1;) (i32.const 0) func) + (data (;0;) (i32.const 1048576) "\00\00\00\00\00\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "__heap_base" (core global (;0;))) + (alias core export 0 "__heap_end" (core global (;1;))) + (core instance (;1;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;2;)) + (alias core export 0 "memory" (core memory (;1;))) + (alias core export 0 "__indirect_function_table" (core table (;0;))) + (alias core export 0 "__stack_pointer" (core global (;2;))) + (alias core export 0 "foo:memory_base" (core global (;3;))) + (alias core export 0 "foo:table_base" (core global (;4;))) + (core instance (;3;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + ) + (type (;0;) (resource (rep i32))) + (core instance (;4;) (instantiate 1 + (with "GOT.mem" (instance 1)) + (with "GOT.func" (instance 2)) + (with "env" (instance 3)) + ) + ) + (alias core export 0 "__heap_base" (core global (;5;))) + (alias core export 0 "__heap_end" (core global (;6;))) + (core instance (;5;) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + ) + (core instance (;6;)) + (alias core export 0 "memory" (core memory (;2;))) + (alias core export 0 "__indirect_function_table" (core table (;1;))) + (alias core export 0 "__stack_pointer" (core global (;7;))) + (alias core export 0 "bar:memory_base" (core global (;8;))) + (alias core export 0 "bar:table_base" (core global (;9;))) + (core instance (;7;) + (export "memory" (memory 2)) + (export "__indirect_function_table" (table 1)) + (export "__stack_pointer" (global 7)) + (export "__memory_base" (global 8)) + (export "__table_base" (global 9)) + ) + (type (;1;) (resource (rep i32))) + (core instance (;8;) (instantiate 2 + (with "GOT.mem" (instance 5)) + (with "GOT.func" (instance 6)) + (with "env" (instance 7)) + ) + ) + (core instance (;9;) (instantiate 3 + (with "env" (instance 0)) + (with "bar" (instance 8)) + (with "foo" (instance 4)) + ) + ) + (type (;2;) (own 0)) + (type (;3;) (func (param "v" u32) (result 2))) + (alias core export 4 "test:test/foo#[constructor]x" (core func (;0;))) + (func (;0;) (type 3) (canon lift (core func 0))) + (type (;4;) (borrow 0)) + (type (;5;) (func (param "self" 4) (result u32))) + (alias core export 4 "test:test/foo#[method]x.get" (core func (;1;))) + (func (;1;) (type 5) (canon lift (core func 1))) + (component (;0;) + (import "import-type-x" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (param "v" u32) (result 1))) + (import "import-constructor-x" (func (;0;) (type 2))) + (type (;3;) (borrow 0)) + (type (;4;) (func (param "self" 3) (result u32))) + (import "import-method-x-get" (func (;1;) (type 4))) + (export (;5;) "x" (type 0)) + (type (;6;) (own 5)) + (type (;7;) (func (param "v" u32) (result 6))) + (export (;2;) "[constructor]x" (func 0) (func (type 7))) + (type (;8;) (borrow 5)) + (type (;9;) (func (param "self" 8) (result u32))) + (export (;3;) "[method]x.get" (func 1) (func (type 9))) + ) + (instance (;0;) (instantiate 0 + (with "import-constructor-x" (func 0)) + (with "import-method-x-get" (func 1)) + (with "import-type-x" (type 0)) + ) + ) + (export (;1;) (interface "test:test/foo") (instance 0)) + (type (;6;) (own 1)) + (type (;7;) (func (param "v" u32) (result 6))) + (alias core export 8 "test:test/bar#[constructor]x" (core func (;2;))) + (func (;2;) (type 7) (canon lift (core func 2))) + (type (;8;) (borrow 1)) + (type (;9;) (func (param "self" 8) (result u32))) + (alias core export 8 "test:test/bar#[method]x.get" (core func (;3;))) + (func (;3;) (type 9) (canon lift (core func 3))) + (component (;1;) + (import "import-type-x" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (param "v" u32) (result 1))) + (import "import-constructor-x" (func (;0;) (type 2))) + (type (;3;) (borrow 0)) + (type (;4;) (func (param "self" 3) (result u32))) + (import "import-method-x-get" (func (;1;) (type 4))) + (export (;5;) "x" (type 0)) + (type (;6;) (own 5)) + (type (;7;) (func (param "v" u32) (result 6))) + (export (;2;) "[constructor]x" (func 0) (func (type 7))) + (type (;8;) (borrow 5)) + (type (;9;) (func (param "self" 8) (result u32))) + (export (;3;) "[method]x.get" (func 1) (func (type 9))) + ) + (instance (;2;) (instantiate 1 + (with "import-constructor-x" (func 2)) + (with "import-method-x-get" (func 3)) + (with "import-type-x" (type 1)) + ) + ) + (export (;3;) (interface "test:test/bar") (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link-resources/component.wit.print b/crates/wit-component/tests/components/link-resources/component.wit.print new file mode 100644 index 0000000000..273010a424 --- /dev/null +++ b/crates/wit-component/tests/components/link-resources/component.wit.print @@ -0,0 +1,6 @@ +package root:component + +world root { + export test:test/foo + export test:test/bar +} diff --git a/crates/wit-component/tests/components/link-resources/lib-bar.wat b/crates/wit-component/tests/components/link-resources/lib-bar.wat new file mode 100644 index 0000000000..53ce67f6ca --- /dev/null +++ b/crates/wit-component/tests/components/link-resources/lib-bar.wat @@ -0,0 +1,15 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (needed "foo") + ) + (type (func (param i32) (result i32))) + (func $x_ctor (type 0) (param i32) (result i32) + unreachable + ) + (func $x_get (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/bar#[constructor]x" (func $x_ctor)) + (export "test:test/bar#[method]x.get" (func $x_get)) +) diff --git a/crates/wit-component/tests/components/link-resources/lib-bar.wit b/crates/wit-component/tests/components/link-resources/lib-bar.wit new file mode 100644 index 0000000000..3fae33ddc0 --- /dev/null +++ b/crates/wit-component/tests/components/link-resources/lib-bar.wit @@ -0,0 +1,13 @@ +package test:test; + +interface bar { + resource x { + constructor(v: u32); + get: func() -> u32; + } +} + +world lib-bar { + import bar; + export bar; +} diff --git a/crates/wit-component/tests/components/link-resources/lib-foo.wat b/crates/wit-component/tests/components/link-resources/lib-foo.wat new file mode 100644 index 0000000000..f561b00e9c --- /dev/null +++ b/crates/wit-component/tests/components/link-resources/lib-foo.wat @@ -0,0 +1,17 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func (param i32) (result i32))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (func $x_ctor (type 0) (param i32) (result i32) + unreachable + ) + (func $x_get (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/foo#[constructor]x" (func $x_ctor)) + (export "test:test/foo#[method]x.get" (func $x_get)) +) diff --git a/crates/wit-component/tests/components/link-resources/lib-foo.wit b/crates/wit-component/tests/components/link-resources/lib-foo.wit new file mode 100644 index 0000000000..47bd48c1d3 --- /dev/null +++ b/crates/wit-component/tests/components/link-resources/lib-foo.wit @@ -0,0 +1,13 @@ +package test:test; + +interface foo { + resource x { + constructor(v: u32); + get: func() -> u32; + } +} + +world lib-foo { + import foo; + export foo; +} diff --git a/crates/wit-component/tests/components/link-stubs/component.wat b/crates/wit-component/tests/components/link-stubs/component.wat new file mode 100644 index 0000000000..f859d77c50 --- /dev/null +++ b/crates/wit-component/tests/components/link-stubs/component.wat @@ -0,0 +1,159 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "v" s32) (result s32))) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import (interface "test:test/test") (instance (;0;) (type 0))) + (core module (;0;) + (table (;0;) 0 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048592) + (global (;2;) i32 i32.const 0) + (global (;3;) i32 i32.const 1048592) + (global (;4;) i32 i32.const 0) + (global (;5;) (mut i32) i32.const 1048592) + (global (;6;) (mut i32) i32.const 1114112) + (export "__stack_pointer" (global 0)) + (export "foo:memory_base" (global 1)) + (export "foo:table_base" (global 2)) + (export "wit-component:stubs:memory_base" (global 3)) + (export "wit-component:stubs:table_base" (global 4)) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + unreachable + ) + (func (;1;) (type 1) (param i32) (result i32) + unreachable + ) + (export "bar" (func 0)) + (export "foo" (func 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (;0;) (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (;0;) (type 0))) + (import "env" "foo" (func $import_foo2 (;1;) (type 0))) + (import "env" "bar" (func $import_bar (;2;) (type 0))) + (func $foo (;3;) (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) + ) + (core module (;3;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (func (;0;) (type 0)) + (start 0) + (elem (;0;) (i32.const 0) func) + (elem (;1;) (i32.const 0) func) + (data (;0;) (i32.const 1048576) "\00\00\00\00\00\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "__heap_base" (core global (;0;))) + (alias core export 0 "__heap_end" (core global (;1;))) + (core instance (;1;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;2;)) + (alias core export 0 "memory" (core memory (;1;))) + (alias core export 0 "__indirect_function_table" (core table (;0;))) + (alias core export 0 "__stack_pointer" (core global (;2;))) + (alias core export 0 "wit-component:stubs:memory_base" (core global (;3;))) + (alias core export 0 "wit-component:stubs:table_base" (core global (;4;))) + (core instance (;3;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + ) + (core instance (;4;) (instantiate 1 + (with "GOT.mem" (instance 1)) + (with "GOT.func" (instance 2)) + (with "env" (instance 3)) + ) + ) + (alias core export 0 "__heap_base" (core global (;5;))) + (alias core export 0 "__heap_end" (core global (;6;))) + (core instance (;5;) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + ) + (core instance (;6;)) + (alias core export 0 "memory" (core memory (;2;))) + (alias core export 0 "__indirect_function_table" (core table (;1;))) + (alias core export 0 "__stack_pointer" (core global (;7;))) + (alias core export 0 "foo:memory_base" (core global (;8;))) + (alias core export 0 "foo:table_base" (core global (;9;))) + (alias core export 4 "bar" (core func (;0;))) + (alias core export 4 "foo" (core func (;1;))) + (core instance (;7;) + (export "memory" (memory 2)) + (export "__indirect_function_table" (table 1)) + (export "__stack_pointer" (global 7)) + (export "__memory_base" (global 8)) + (export "__table_base" (global 9)) + (export "bar" (func 0)) + (export "foo" (func 1)) + ) + (alias export 0 "foo" (func (;0;))) + (core func (;2;) (canon lower (func 0))) + (core instance (;8;) + (export "foo" (func 2)) + ) + (core instance (;9;) (instantiate 2 + (with "GOT.mem" (instance 5)) + (with "GOT.func" (instance 6)) + (with "env" (instance 7)) + (with "test:test/test" (instance 8)) + ) + ) + (core instance (;10;) (instantiate 3 + (with "env" (instance 0)) + (with "foo" (instance 9)) + (with "wit-component:stubs" (instance 4)) + ) + ) + (type (;1;) (func (param "v" s32) (result s32))) + (alias core export 9 "test:test/test#foo" (core func (;3;))) + (func (;1;) (type 1) (canon lift (core func 3))) + (component (;0;) + (type (;0;) (func (param "v" s32) (result s32))) + (import "import-func-foo" (func (;0;) (type 0))) + (type (;1;) (func (param "v" s32) (result s32))) + (export (;1;) "foo" (func 0) (func (type 1))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-foo" (func 1)) + ) + ) + (export (;2;) (interface "test:test/test") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link-stubs/component.wit.print b/crates/wit-component/tests/components/link-stubs/component.wit.print new file mode 100644 index 0000000000..d02a685b6f --- /dev/null +++ b/crates/wit-component/tests/components/link-stubs/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import test:test/test + + export test:test/test +} diff --git a/crates/wit-component/tests/components/link-stubs/lib-foo.wat b/crates/wit-component/tests/components/link-stubs/lib-foo.wat new file mode 100644 index 0000000000..0e47f33480 --- /dev/null +++ b/crates/wit-component/tests/components/link-stubs/lib-foo.wat @@ -0,0 +1,13 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (import "env" "foo" (func $import_foo2 (type 0))) + (import "env" "bar" (func $import_bar (type 0))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) +) diff --git a/crates/wit-component/tests/components/link-stubs/lib-foo.wit b/crates/wit-component/tests/components/link-stubs/lib-foo.wit new file mode 100644 index 0000000000..576de43434 --- /dev/null +++ b/crates/wit-component/tests/components/link-stubs/lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/link-stubs/stub-missing-functions b/crates/wit-component/tests/components/link-stubs/stub-missing-functions new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-component/tests/components/link-weak-import/component.wat b/crates/wit-component/tests/components/link-weak-import/component.wat new file mode 100644 index 0000000000..f66f107f14 --- /dev/null +++ b/crates/wit-component/tests/components/link-weak-import/component.wat @@ -0,0 +1,161 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "v" s32) (result s32))) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import (interface "test:test/test") (instance (;0;) (type 0))) + (core module (;0;) + (table (;0;) 0 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048592) + (global (;2;) i32 i32.const 0) + (global (;3;) i32 i32.const 1048592) + (global (;4;) i32 i32.const 0) + (global (;5;) (mut i32) i32.const 1048592) + (global (;6;) (mut i32) i32.const 1114112) + (export "__stack_pointer" (global 0)) + (export "foo:memory_base" (global 1)) + (export "foo:table_base" (global 2)) + (export "wit-component:stubs:memory_base" (global 3)) + (export "wit-component:stubs:table_base" (global 4)) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + unreachable + ) + (func (;1;) (type 1) (param i32) (result i32) + unreachable + ) + (export "bar" (func 0)) + (export "foo" (func 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (@dylink.0 + (mem-info (memory 0 4)) + (import-info "env" "foo" binding-weak) + (import-info "env" "bar" binding-weak) + ) + (type (;0;) (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (;0;) (type 0))) + (import "env" "foo" (func $import_foo2 (;1;) (type 0))) + (import "env" "bar" (func $import_bar (;2;) (type 0))) + (func $foo (;3;) (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) + ) + (core module (;3;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (func (;0;) (type 0)) + (start 0) + (elem (;0;) (i32.const 0) func) + (elem (;1;) (i32.const 0) func) + (data (;0;) (i32.const 1048576) "\00\00\00\00\00\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "__heap_base" (core global (;0;))) + (alias core export 0 "__heap_end" (core global (;1;))) + (core instance (;1;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;2;)) + (alias core export 0 "memory" (core memory (;1;))) + (alias core export 0 "__indirect_function_table" (core table (;0;))) + (alias core export 0 "__stack_pointer" (core global (;2;))) + (alias core export 0 "wit-component:stubs:memory_base" (core global (;3;))) + (alias core export 0 "wit-component:stubs:table_base" (core global (;4;))) + (core instance (;3;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + ) + (core instance (;4;) (instantiate 1 + (with "GOT.mem" (instance 1)) + (with "GOT.func" (instance 2)) + (with "env" (instance 3)) + ) + ) + (alias core export 0 "__heap_base" (core global (;5;))) + (alias core export 0 "__heap_end" (core global (;6;))) + (core instance (;5;) + (export "__heap_base" (global 5)) + (export "__heap_end" (global 6)) + ) + (core instance (;6;)) + (alias core export 0 "memory" (core memory (;2;))) + (alias core export 0 "__indirect_function_table" (core table (;1;))) + (alias core export 0 "__stack_pointer" (core global (;7;))) + (alias core export 0 "foo:memory_base" (core global (;8;))) + (alias core export 0 "foo:table_base" (core global (;9;))) + (alias core export 4 "bar" (core func (;0;))) + (alias core export 4 "foo" (core func (;1;))) + (core instance (;7;) + (export "memory" (memory 2)) + (export "__indirect_function_table" (table 1)) + (export "__stack_pointer" (global 7)) + (export "__memory_base" (global 8)) + (export "__table_base" (global 9)) + (export "bar" (func 0)) + (export "foo" (func 1)) + ) + (alias export 0 "foo" (func (;0;))) + (core func (;2;) (canon lower (func 0))) + (core instance (;8;) + (export "foo" (func 2)) + ) + (core instance (;9;) (instantiate 2 + (with "GOT.mem" (instance 5)) + (with "GOT.func" (instance 6)) + (with "env" (instance 7)) + (with "test:test/test" (instance 8)) + ) + ) + (core instance (;10;) (instantiate 3 + (with "env" (instance 0)) + (with "foo" (instance 9)) + (with "wit-component:stubs" (instance 4)) + ) + ) + (type (;1;) (func (param "v" s32) (result s32))) + (alias core export 9 "test:test/test#foo" (core func (;3;))) + (func (;1;) (type 1) (canon lift (core func 3))) + (component (;0;) + (type (;0;) (func (param "v" s32) (result s32))) + (import "import-func-foo" (func (;0;) (type 0))) + (type (;1;) (func (param "v" s32) (result s32))) + (export (;1;) "foo" (func 0) (func (type 1))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-foo" (func 1)) + ) + ) + (export (;2;) (interface "test:test/test") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link-weak-import/component.wit.print b/crates/wit-component/tests/components/link-weak-import/component.wit.print new file mode 100644 index 0000000000..d02a685b6f --- /dev/null +++ b/crates/wit-component/tests/components/link-weak-import/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import test:test/test + + export test:test/test +} diff --git a/crates/wit-component/tests/components/link-weak-import/lib-foo.wat b/crates/wit-component/tests/components/link-weak-import/lib-foo.wat new file mode 100644 index 0000000000..fe54e0bd63 --- /dev/null +++ b/crates/wit-component/tests/components/link-weak-import/lib-foo.wat @@ -0,0 +1,15 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + (import-info "env" "foo" binding-weak) + (import-info "env" "bar" binding-weak) + ) + (type (func (param i32) (result i32))) + (import "test:test/test" "foo" (func $import_foo (type 0))) + (import "env" "foo" (func $import_foo2 (type 0))) + (import "env" "bar" (func $import_bar (type 0))) + (func $foo (type 0) (param i32) (result i32) + unreachable + ) + (export "test:test/test#foo" (func $foo)) +) diff --git a/crates/wit-component/tests/components/link-weak-import/lib-foo.wit b/crates/wit-component/tests/components/link-weak-import/lib-foo.wit new file mode 100644 index 0000000000..576de43434 --- /dev/null +++ b/crates/wit-component/tests/components/link-weak-import/lib-foo.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + foo: func(v: s32) -> s32; +} + +world lib-foo { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/link/component.wat b/crates/wit-component/tests/components/link/component.wat new file mode 100644 index 0000000000..47466a042c --- /dev/null +++ b/crates/wit-component/tests/components/link/component.wat @@ -0,0 +1,300 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "v" s32) (result s32))) + (export (;0;) "bar" (func (type 0))) + ) + ) + (import (interface "test:test/test") (instance (;0;) (type 0))) + (core module (;0;) + (table (;0;) 0 funcref) + (memory (;0;) 17) + (global (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048592) + (global (;2;) i32 i32.const 0) + (global (;3;) (mut i32) i32.const 0) + (global (;4;) i32 i32.const 1048624) + (global (;5;) i32 i32.const 0) + (global (;6;) i32 i32.const 1048624) + (global (;7;) i32 i32.const 0) + (global (;8;) (mut i32) i32.const 0) + (global (;9;) (mut i32) i32.const 1048640) + (global (;10;) (mut i32) i32.const 1114112) + (export "__stack_pointer" (global 0)) + (export "bar:memory_base" (global 1)) + (export "bar:table_base" (global 2)) + (export "bar:well" (global 3)) + (export "c:memory_base" (global 4)) + (export "c:table_base" (global 5)) + (export "foo:memory_base" (global 6)) + (export "foo:table_base" (global 7)) + (export "foo:um" (global 8)) + (export "__heap_base" (global 9)) + (export "__heap_end" (global 10)) + (export "__indirect_function_table" (table 0)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;1;) + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (import "GOT.mem" "__heap_base" (global $__heap_base (;0;) (mut i32))) + (import "GOT.mem" "__heap_end" (global $__heap_end (;1;) (mut i32))) + (func $start (;0;) (type 0) + global.get $__heap_base + global.set $heap + ) + (func $malloc (;1;) (type 1) (param i32) (result i32) + global.get $heap + global.get $heap + local.get 0 + i32.add + global.set $heap + ) + (func $abort (;2;) (type 0) + unreachable + ) + (global $heap (;2;) (mut i32) i32.const 0) + (export "malloc" (func $malloc)) + (export "abort" (func $abort)) + (start $start) + ) + (core module (;2;) + (@dylink.0 + (mem-info (memory 4 4)) + (needed "c") + ) + (type $.data (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (import "env" "memory" (memory (;0;) 1)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "env" "__stack_pointer" (global $__stack_pointer (;0;) (mut i32))) + (import "env" "__memory_base" (global $__memory_base (;1;) i32)) + (import "env" "__table_base" (global $__table_base (;2;) i32)) + (import "env" "malloc" (func $malloc (;0;) (type 1))) + (import "env" "abort" (func $abort (;1;) (type $.data))) + (import "GOT.mem" "um" (global $um (;3;) (mut i32))) + (import "test:test/test" "bar" (func $bar (;2;) (type 1))) + (func $__wasm_call_ctors (;3;) (type $.data)) + (func $__wasm_apply_data_relocs (;4;) (type $.data)) + (func $foo (;5;) (type 1) (param i32) (result i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + global.set $__stack_pointer + i32.const 4 + call $malloc + i32.const 0 + i32.eq + if ;; label = @1 + call $abort + unreachable + end + local.get 0 + global.get $um + i32.load offset=16 + i32.add + i32.const 42 + i32.add + call $bar + global.get $__stack_pointer + i32.const 16 + i32.add + global.set $__stack_pointer + ) + (global (;4;) i32 i32.const 0) + (export "__wasm_call_ctors" (func $__wasm_call_ctors)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "foo" (func $foo)) + (export "well" (global 4)) + (data (;0;) (global.get $__memory_base) "\04\00\00\00") + ) + (core module (;3;) + (@dylink.0 + (mem-info (memory 20 4)) + (needed "foo") + ) + (type $.data (;0;) (func (param i32) (result i32))) + (type (;1;) (func)) + (import "env" "memory" (memory (;0;) 1)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "env" "__memory_base" (global $__memory_base (;0;) i32)) + (import "env" "__table_base" (global $__table_base (;1;) i32)) + (import "env" "foo" (func $foo (;0;) (type $.data))) + (import "GOT.mem" "well" (global $well (;2;) (mut i32))) + (func $__wasm_call_ctors (;1;) (type 1)) + (func $__wasm_apply_data_relocs (;2;) (type 1)) + (func $bar (;3;) (type $.data) (param i32) (result i32) + local.get 0 + call $foo + global.get $well + i32.load + i32.add + ) + (global (;3;) i32 i32.const 0) + (export "__wasm_call_ctors" (func $__wasm_call_ctors)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "test:test/test#bar" (func $bar)) + (export "um" (global 3)) + (data (;0;) (global.get $__memory_base) "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00") + ) + (core module (;4;) + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (import "env" "memory" (memory (;0;) 0)) + (import "env" "__indirect_function_table" (table (;0;) 0 funcref)) + (import "bar" "__wasm_apply_data_relocs" (func (;0;) (type 0))) + (import "bar" "__wasm_call_ctors" (func (;1;) (type 0))) + (import "env" "foo:memory_base" (global (;0;) i32)) + (import "foo" "well" (global (;1;) i32)) + (import "env" "bar:well" (global (;2;) (mut i32))) + (import "foo" "__wasm_apply_data_relocs" (func (;2;) (type 0))) + (import "foo" "__wasm_call_ctors" (func (;3;) (type 0))) + (import "env" "bar:memory_base" (global (;3;) i32)) + (import "bar" "um" (global (;4;) i32)) + (import "env" "foo:um" (global (;5;) (mut i32))) + (func (;4;) (type 0) + global.get 0 + global.get 1 + i32.add + global.set 2 + global.get 3 + global.get 4 + i32.add + global.set 5 + call 0 + call 2 + call 1 + call 3 + ) + (start 4) + (elem (;0;) (i32.const 0) func) + (elem (;1;) (i32.const 0) func) + (data (;0;) (i32.const 1048576) "\00\00\00\00\00\00\10\00") + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "__heap_base" (core global (;0;))) + (alias core export 0 "__heap_end" (core global (;1;))) + (core instance (;1;) + (export "__heap_base" (global 0)) + (export "__heap_end" (global 1)) + ) + (core instance (;2;)) + (alias core export 0 "memory" (core memory (;1;))) + (alias core export 0 "__indirect_function_table" (core table (;0;))) + (alias core export 0 "__stack_pointer" (core global (;2;))) + (alias core export 0 "c:memory_base" (core global (;3;))) + (alias core export 0 "c:table_base" (core global (;4;))) + (core instance (;3;) + (export "memory" (memory 1)) + (export "__indirect_function_table" (table 0)) + (export "__stack_pointer" (global 2)) + (export "__memory_base" (global 3)) + (export "__table_base" (global 4)) + ) + (core instance (;4;) (instantiate 1 + (with "GOT.mem" (instance 1)) + (with "GOT.func" (instance 2)) + (with "env" (instance 3)) + ) + ) + (alias core export 0 "foo:um" (core global (;5;))) + (alias core export 0 "__heap_base" (core global (;6;))) + (alias core export 0 "__heap_end" (core global (;7;))) + (core instance (;5;) + (export "um" (global 5)) + (export "__heap_base" (global 6)) + (export "__heap_end" (global 7)) + ) + (core instance (;6;)) + (alias core export 0 "memory" (core memory (;2;))) + (alias core export 0 "__indirect_function_table" (core table (;1;))) + (alias core export 0 "__stack_pointer" (core global (;8;))) + (alias core export 0 "foo:memory_base" (core global (;9;))) + (alias core export 0 "foo:table_base" (core global (;10;))) + (alias core export 4 "abort" (core func (;0;))) + (alias core export 4 "malloc" (core func (;1;))) + (core instance (;7;) + (export "memory" (memory 2)) + (export "__indirect_function_table" (table 1)) + (export "__stack_pointer" (global 8)) + (export "__memory_base" (global 9)) + (export "__table_base" (global 10)) + (export "abort" (func 0)) + (export "malloc" (func 1)) + ) + (alias export 0 "bar" (func (;0;))) + (core func (;2;) (canon lower (func 0))) + (core instance (;8;) + (export "bar" (func 2)) + ) + (core instance (;9;) (instantiate 2 + (with "GOT.mem" (instance 5)) + (with "GOT.func" (instance 6)) + (with "env" (instance 7)) + (with "test:test/test" (instance 8)) + ) + ) + (alias core export 0 "bar:well" (core global (;11;))) + (alias core export 0 "__heap_base" (core global (;12;))) + (alias core export 0 "__heap_end" (core global (;13;))) + (core instance (;10;) + (export "well" (global 11)) + (export "__heap_base" (global 12)) + (export "__heap_end" (global 13)) + ) + (core instance (;11;)) + (alias core export 0 "memory" (core memory (;3;))) + (alias core export 0 "__indirect_function_table" (core table (;2;))) + (alias core export 0 "__stack_pointer" (core global (;14;))) + (alias core export 0 "bar:memory_base" (core global (;15;))) + (alias core export 0 "bar:table_base" (core global (;16;))) + (alias core export 9 "foo" (core func (;3;))) + (core instance (;12;) + (export "memory" (memory 3)) + (export "__indirect_function_table" (table 2)) + (export "__stack_pointer" (global 14)) + (export "__memory_base" (global 15)) + (export "__table_base" (global 16)) + (export "foo" (func 3)) + ) + (core instance (;13;) (instantiate 3 + (with "GOT.mem" (instance 10)) + (with "GOT.func" (instance 11)) + (with "env" (instance 12)) + ) + ) + (core instance (;14;) (instantiate 4 + (with "env" (instance 0)) + (with "bar" (instance 13)) + (with "c" (instance 4)) + (with "foo" (instance 9)) + ) + ) + (type (;1;) (func (param "v" s32) (result s32))) + (alias core export 13 "test:test/test#bar" (core func (;4;))) + (func (;1;) (type 1) (canon lift (core func 4))) + (component (;0;) + (type (;0;) (func (param "v" s32) (result s32))) + (import "import-func-bar" (func (;0;) (type 0))) + (type (;1;) (func (param "v" s32) (result s32))) + (export (;1;) "bar" (func 0) (func (type 1))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-bar" (func 1)) + ) + ) + (export (;2;) (interface "test:test/test") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/link/component.wit.print b/crates/wit-component/tests/components/link/component.wit.print new file mode 100644 index 0000000000..d02a685b6f --- /dev/null +++ b/crates/wit-component/tests/components/link/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import test:test/test + + export test:test/test +} diff --git a/crates/wit-component/tests/components/link/lib-bar.wat b/crates/wit-component/tests/components/link/lib-bar.wat new file mode 100644 index 0000000000..d06fe9ba04 --- /dev/null +++ b/crates/wit-component/tests/components/link/lib-bar.wat @@ -0,0 +1,29 @@ +(module + (@dylink.0 + (mem-info (memory 20 4)) + (needed "foo") + ) + (type (func (param i32) (result i32))) + (type (func)) + (import "env" "memory" (memory 1)) + (import "env" "__indirect_function_table" (table 0 funcref)) + (import "env" "__memory_base" (global $__memory_base i32)) + (import "env" "__table_base" (global $__table_base i32)) + (import "env" "foo" (func $foo (type 0))) + (import "GOT.mem" "well" (global $well (mut i32))) + (func $__wasm_call_ctors (type 1)) + (func $__wasm_apply_data_relocs (type 1)) + (func $bar (type 0) (param i32) (result i32) + local.get 0 + call $foo + global.get $well + i32.load + i32.add + ) + (global i32 i32.const 0) + (export "__wasm_call_ctors" (func $__wasm_call_ctors)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "test:test/test#bar" (func $bar)) + (export "um" (global 3)) + (data $.data (global.get $__memory_base) "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00") +) diff --git a/crates/wit-component/tests/components/link/lib-bar.wit b/crates/wit-component/tests/components/link/lib-bar.wit new file mode 100644 index 0000000000..9cab0b5e2e --- /dev/null +++ b/crates/wit-component/tests/components/link/lib-bar.wit @@ -0,0 +1,10 @@ +package test:test; + +interface test { + bar: func(v: s32) -> s32; +} + +world lib-bar { + import test; + export test; +} diff --git a/crates/wit-component/tests/components/link/lib-c.wat b/crates/wit-component/tests/components/link/lib-c.wat new file mode 100644 index 0000000000..7798b7d6dd --- /dev/null +++ b/crates/wit-component/tests/components/link/lib-c.wat @@ -0,0 +1,27 @@ +(module + (@dylink.0 + (mem-info (memory 0 4)) + ) + (type (func)) + (type (func (param i32) (result i32))) + (import "GOT.mem" "__heap_base" (global $__heap_base (mut i32))) + (import "GOT.mem" "__heap_end" (global $__heap_end (mut i32))) + (global $heap (mut i32) i32.const 0) + (func $start (type 0) + global.get $__heap_base + global.set $heap + ) + (func $malloc (type 1) (param i32) (result i32) + global.get $heap + global.get $heap + local.get 0 + i32.add + global.set $heap + ) + (func $abort (type 0) + unreachable + ) + (export "malloc" (func $malloc)) + (export "abort" (func $abort)) + (start $start) +) diff --git a/crates/wit-component/tests/components/link/lib-c.wit b/crates/wit-component/tests/components/link/lib-c.wit new file mode 100644 index 0000000000..262c853de3 --- /dev/null +++ b/crates/wit-component/tests/components/link/lib-c.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-c { } diff --git a/crates/wit-component/tests/components/link/lib-foo.wat b/crates/wit-component/tests/components/link/lib-foo.wat new file mode 100644 index 0000000000..e681ea2017 --- /dev/null +++ b/crates/wit-component/tests/components/link/lib-foo.wat @@ -0,0 +1,55 @@ +(module + (@dylink.0 + (mem-info (memory 4 4)) + (needed "c") + ) + (type (func)) + (type (func (param i32) (result i32))) + (import "env" "memory" (memory 1)) + (import "env" "__indirect_function_table" (table 0 funcref)) + (import "env" "__stack_pointer" (global $__stack_pointer (mut i32))) + (import "env" "__memory_base" (global $__memory_base i32)) + (import "env" "__table_base" (global $__table_base i32)) + (import "env" "malloc" (func $malloc (type 1))) + (import "env" "abort" (func $abort (type 0))) + (import "GOT.mem" "um" (global $um (mut i32))) + (import "test:test/test" "bar" (func $bar (type 1))) + (func $__wasm_call_ctors (type 0)) + (func $__wasm_apply_data_relocs (type 0)) + (func $foo (type 1) (param i32) (result i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + global.set $__stack_pointer + + i32.const 4 + call $malloc + + i32.const 0 + i32.eq + if + call $abort + unreachable + end + + local.get 0 + global.get $um + i32.load offset=16 + i32.add + i32.const 42 + i32.add + + call $bar + + global.get $__stack_pointer + i32.const 16 + i32.add + global.set $__stack_pointer + ) + (global i32 i32.const 0) + (export "__wasm_call_ctors" (func $__wasm_call_ctors)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "foo" (func $foo)) + (export "well" (global 4)) + (data $.data (global.get $__memory_base) "\04\00\00\00") +) diff --git a/crates/wit-component/tests/components/link/lib-foo.wit b/crates/wit-component/tests/components/link/lib-foo.wit new file mode 100644 index 0000000000..3171fc9990 --- /dev/null +++ b/crates/wit-component/tests/components/link/lib-foo.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-foo { } diff --git a/crates/wit-component/tests/components/link/lib-unused.wat b/crates/wit-component/tests/components/link/lib-unused.wat new file mode 100644 index 0000000000..8818e20f74 --- /dev/null +++ b/crates/wit-component/tests/components/link/lib-unused.wat @@ -0,0 +1,55 @@ +(module + (@dylink.0 + (mem-info (memory 4 4)) + (needed "c") + ) + (type (func)) + (type (func (param i32) (result i32))) + (import "env" "memory" (memory 1)) + (import "env" "__indirect_function_table" (table 0 funcref)) + (import "env" "__stack_pointer" (global $__stack_pointer (mut i32))) + (import "env" "__memory_base" (global $__memory_base i32)) + (import "env" "__table_base" (global $__table_base i32)) + (import "env" "malloc" (func $malloc (type 1))) + (import "env" "abort" (func $abort (type 0))) + (import "GOT.mem" "um" (global $um (mut i32))) + (import "test:test/test" "bar" (func $bar (type 1))) + (func $__wasm_call_ctors (type 0)) + (func $__wasm_apply_data_relocs (type 0)) + (func $foo (type 1) (param i32) (result i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + global.set $__stack_pointer + + i32.const 4 + call $malloc + + i32.const 0 + i32.eq + if + call $abort + unreachable + end + + local.get 0 + global.get $um + i32.load offset=16 + i32.add + i32.const 42 + i32.add + + call $bar + + global.get $__stack_pointer + i32.const 16 + i32.add + global.set $__stack_pointer + ) + (global i32 i32.const 0) + (export "__wasm_call_ctors" (func $__wasm_call_ctors)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "foo2" (func $foo)) + (export "well2" (global 4)) + (data $.data (global.get $__memory_base) "\04\00\00\00") +) diff --git a/crates/wit-component/tests/components/link/lib-unused.wit b/crates/wit-component/tests/components/link/lib-unused.wit new file mode 100644 index 0000000000..73d286f7c6 --- /dev/null +++ b/crates/wit-component/tests/components/link/lib-unused.wit @@ -0,0 +1,3 @@ +package test:test; + +world lib-unused { } diff --git a/crates/wit-component/tests/components/live-exports-dead-imports/component.wat b/crates/wit-component/tests/components/live-exports-dead-imports/component.wat new file mode 100644 index 0000000000..e1dd36853b --- /dev/null +++ b/crates/wit-component/tests/components/live-exports-dead-imports/component.wat @@ -0,0 +1,38 @@ +(component + (core module (;0;) + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + unreachable + ) + (export "foo:foo/a#[constructor]r" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (type (;0;) (resource (rep i32))) + (core instance (;0;) (instantiate 0)) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (alias core export 0 "foo:foo/a#[constructor]r" (core func (;0;))) + (func (;0;) (type 2) (canon lift (core func 0))) + (component (;0;) + (import "import-type-r" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (import "import-constructor-r" (func (;0;) (type 2))) + (export (;3;) "r" (type 0)) + (type (;4;) (own 3)) + (type (;5;) (func (result 4))) + (export (;1;) "[constructor]r" (func 0) (func (type 5))) + ) + (instance (;0;) (instantiate 0 + (with "import-constructor-r" (func 0)) + (with "import-type-r" (type 0)) + ) + ) + (export (;1;) (interface "foo:foo/a") (instance 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/live-exports-dead-imports/component.wit.print b/crates/wit-component/tests/components/live-exports-dead-imports/component.wit.print new file mode 100644 index 0000000000..3aca8207ae --- /dev/null +++ b/crates/wit-component/tests/components/live-exports-dead-imports/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + export foo:foo/a +} diff --git a/crates/wit-component/tests/components/live-exports-dead-imports/module.wat b/crates/wit-component/tests/components/live-exports-dead-imports/module.wat new file mode 100644 index 0000000000..6f4a9406dd --- /dev/null +++ b/crates/wit-component/tests/components/live-exports-dead-imports/module.wat @@ -0,0 +1,4 @@ +(module + (func (export "foo:foo/a#[constructor]r") (result i32) + unreachable) +) diff --git a/crates/wit-component/tests/components/live-exports-dead-imports/module.wit b/crates/wit-component/tests/components/live-exports-dead-imports/module.wit new file mode 100644 index 0000000000..39f4ce242e --- /dev/null +++ b/crates/wit-component/tests/components/live-exports-dead-imports/module.wit @@ -0,0 +1,12 @@ +package foo:foo; + +interface a { + resource r { + constructor(); + } +} + +world module { + import a; + export a; +} diff --git a/crates/wit-component/tests/components/lower-options/component.wat b/crates/wit-component/tests/components/lower-options/component.wat new file mode 100644 index 0000000000..9aa289c2a3 --- /dev/null +++ b/crates/wit-component/tests/components/lower-options/component.wat @@ -0,0 +1,281 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "s" string))) + (export (;1;) "r" (type (eq 0))) + (type (;2;) (variant (case "s" string))) + (export (;3;) "v" (type (eq 2))) + (type (;4;) (record (field "s" u32))) + (export (;5;) "r-no-string" (type (eq 4))) + (type (;6;) (variant (case "s" u32))) + (export (;7;) "v-no-string" (type (eq 6))) + (type (;8;) (func)) + (export (;0;) "a" (func (type 8))) + (type (;9;) (list string)) + (type (;10;) (func (param "x" 9))) + (export (;1;) "b" (func (type 10))) + (type (;11;) (func (param "x" 1))) + (export (;2;) "c" (func (type 11))) + (type (;12;) (func (param "x" 3))) + (export (;3;) "d" (func (type 12))) + (type (;13;) (func (param "x" 5))) + (export (;4;) "e" (func (type 13))) + (type (;14;) (func (param "x" 7))) + (export (;5;) "f" (func (type 14))) + (type (;15;) (list 1)) + (type (;16;) (func (param "x" 15))) + (export (;6;) "g" (func (type 16))) + (type (;17;) (list 3)) + (type (;18;) (func (param "x" 17))) + (export (;7;) "h" (func (type 18))) + (type (;19;) (list u32)) + (type (;20;) (func (param "x" 19))) + (export (;8;) "i" (func (type 20))) + (type (;21;) (func (param "x" u32))) + (export (;9;) "j" (func (type 21))) + (type (;22;) (tuple u32 u32)) + (type (;23;) (func (result 22))) + (export (;10;) "k" (func (type 23))) + (type (;24;) (func (result string))) + (export (;11;) "l" (func (type 24))) + (type (;25;) (func (result 19))) + (export (;12;) "m" (func (type 25))) + (type (;26;) (func (result u32))) + (export (;13;) "n" (func (type 26))) + (type (;27;) (func (result 3))) + (export (;14;) "o" (func (type 27))) + (type (;28;) (list 7)) + (type (;29;) (func (result 28))) + (export (;15;) "p" (func (type 29))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32 i32))) + (type (;2;) (func (param i32 i32 i32))) + (type (;3;) (func (param i32))) + (type (;4;) (func (result i32))) + (type (;5;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo:foo/foo" "a" (func (;0;) (type 0))) + (import "foo:foo/foo" "b" (func (;1;) (type 1))) + (import "foo:foo/foo" "c" (func (;2;) (type 1))) + (import "foo:foo/foo" "d" (func (;3;) (type 2))) + (import "foo:foo/foo" "e" (func (;4;) (type 3))) + (import "foo:foo/foo" "f" (func (;5;) (type 1))) + (import "foo:foo/foo" "g" (func (;6;) (type 1))) + (import "foo:foo/foo" "h" (func (;7;) (type 1))) + (import "foo:foo/foo" "i" (func (;8;) (type 1))) + (import "foo:foo/foo" "j" (func (;9;) (type 3))) + (import "foo:foo/foo" "k" (func (;10;) (type 3))) + (import "foo:foo/foo" "l" (func (;11;) (type 3))) + (import "foo:foo/foo" "m" (func (;12;) (type 3))) + (import "foo:foo/foo" "n" (func (;13;) (type 4))) + (import "foo:foo/foo" "o" (func (;14;) (type 3))) + (import "foo:foo/foo" "p" (func (;15;) (type 3))) + (func (;16;) (type 5) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 16)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32 i32))) + (type (;2;) (func (param i32))) + (func $indirect-foo:foo/foo-b (;0;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 0 + call_indirect (type 0) + ) + (func $indirect-foo:foo/foo-c (;1;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 1 + call_indirect (type 0) + ) + (func $indirect-foo:foo/foo-d (;2;) (type 1) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + i32.const 2 + call_indirect (type 1) + ) + (func $indirect-foo:foo/foo-g (;3;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 3 + call_indirect (type 0) + ) + (func $indirect-foo:foo/foo-h (;4;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 4 + call_indirect (type 0) + ) + (func $indirect-foo:foo/foo-i (;5;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 5 + call_indirect (type 0) + ) + (func $indirect-foo:foo/foo-k (;6;) (type 2) (param i32) + local.get 0 + i32.const 6 + call_indirect (type 2) + ) + (func $indirect-foo:foo/foo-l (;7;) (type 2) (param i32) + local.get 0 + i32.const 7 + call_indirect (type 2) + ) + (func $indirect-foo:foo/foo-m (;8;) (type 2) (param i32) + local.get 0 + i32.const 8 + call_indirect (type 2) + ) + (func $indirect-foo:foo/foo-o (;9;) (type 2) (param i32) + local.get 0 + i32.const 9 + call_indirect (type 2) + ) + (func $indirect-foo:foo/foo-p (;10;) (type 2) (param i32) + local.get 0 + i32.const 10 + call_indirect (type 2) + ) + (table (;0;) 11 11 funcref) + (export "0" (func $indirect-foo:foo/foo-b)) + (export "1" (func $indirect-foo:foo/foo-c)) + (export "2" (func $indirect-foo:foo/foo-d)) + (export "3" (func $indirect-foo:foo/foo-g)) + (export "4" (func $indirect-foo:foo/foo-h)) + (export "5" (func $indirect-foo:foo/foo-i)) + (export "6" (func $indirect-foo:foo/foo-k)) + (export "7" (func $indirect-foo:foo/foo-l)) + (export "8" (func $indirect-foo:foo/foo-m)) + (export "9" (func $indirect-foo:foo/foo-o)) + (export "10" (func $indirect-foo:foo/foo-p)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32 i32))) + (type (;2;) (func (param i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "2" (func (;2;) (type 1))) + (import "" "3" (func (;3;) (type 0))) + (import "" "4" (func (;4;) (type 0))) + (import "" "5" (func (;5;) (type 0))) + (import "" "6" (func (;6;) (type 2))) + (import "" "7" (func (;7;) (type 2))) + (import "" "8" (func (;8;) (type 2))) + (import "" "9" (func (;9;) (type 2))) + (import "" "10" (func (;10;) (type 2))) + (import "" "$imports" (table (;0;) 11 11 funcref)) + (elem (;0;) (i32.const 0) func 0 1 2 3 4 5 6 7 8 9 10) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 1)) + (alias export 0 "a" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (alias core export 0 "0" (core func (;1;))) + (alias core export 0 "1" (core func (;2;))) + (alias core export 0 "2" (core func (;3;))) + (alias export 0 "e" (func (;1;))) + (core func (;4;) (canon lower (func 1))) + (alias export 0 "f" (func (;2;))) + (core func (;5;) (canon lower (func 2))) + (alias core export 0 "3" (core func (;6;))) + (alias core export 0 "4" (core func (;7;))) + (alias core export 0 "5" (core func (;8;))) + (alias export 0 "j" (func (;3;))) + (core func (;9;) (canon lower (func 3))) + (alias core export 0 "6" (core func (;10;))) + (alias core export 0 "7" (core func (;11;))) + (alias core export 0 "8" (core func (;12;))) + (alias export 0 "n" (func (;4;))) + (core func (;13;) (canon lower (func 4))) + (alias core export 0 "9" (core func (;14;))) + (alias core export 0 "10" (core func (;15;))) + (core instance (;1;) + (export "a" (func 0)) + (export "b" (func 1)) + (export "c" (func 2)) + (export "d" (func 3)) + (export "e" (func 4)) + (export "f" (func 5)) + (export "g" (func 6)) + (export "h" (func 7)) + (export "i" (func 8)) + (export "j" (func 9)) + (export "k" (func 10)) + (export "l" (func 11)) + (export "m" (func 12)) + (export "n" (func 13)) + (export "o" (func 14)) + (export "p" (func 15)) + ) + (core instance (;2;) (instantiate 0 + (with "foo:foo/foo" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;16;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "b" (func (;5;))) + (core func (;17;) (canon lower (func 5) (memory 0) string-encoding=utf8)) + (alias export 0 "c" (func (;6;))) + (core func (;18;) (canon lower (func 6) (memory 0) string-encoding=utf8)) + (alias export 0 "d" (func (;7;))) + (core func (;19;) (canon lower (func 7) (memory 0) string-encoding=utf8)) + (alias export 0 "g" (func (;8;))) + (core func (;20;) (canon lower (func 8) (memory 0) string-encoding=utf8)) + (alias export 0 "h" (func (;9;))) + (core func (;21;) (canon lower (func 9) (memory 0) string-encoding=utf8)) + (alias export 0 "i" (func (;10;))) + (core func (;22;) (canon lower (func 10) (memory 0))) + (alias export 0 "k" (func (;11;))) + (core func (;23;) (canon lower (func 11) (memory 0))) + (alias export 0 "l" (func (;12;))) + (core func (;24;) (canon lower (func 12) (memory 0) (realloc 16) string-encoding=utf8)) + (alias export 0 "m" (func (;13;))) + (core func (;25;) (canon lower (func 13) (memory 0) (realloc 16))) + (alias export 0 "o" (func (;14;))) + (core func (;26;) (canon lower (func 14) (memory 0) (realloc 16) string-encoding=utf8)) + (alias export 0 "p" (func (;15;))) + (core func (;27;) (canon lower (func 15) (memory 0) (realloc 16))) + (core instance (;3;) + (export "$imports" (table 0)) + (export "0" (func 17)) + (export "1" (func 18)) + (export "2" (func 19)) + (export "3" (func 20)) + (export "4" (func 21)) + (export "5" (func 22)) + (export "6" (func 23)) + (export "7" (func 24)) + (export "8" (func 25)) + (export "9" (func 26)) + (export "10" (func 27)) + ) + (core instance (;4;) (instantiate 2 + (with "" (instance 3)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/lower-options/component.wit.print b/crates/wit-component/tests/components/lower-options/component.wit.print new file mode 100644 index 0000000000..7ef7c78b37 --- /dev/null +++ b/crates/wit-component/tests/components/lower-options/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + import foo:foo/foo +} diff --git a/crates/wit-component/tests/components/lower-options/module.wat b/crates/wit-component/tests/components/lower-options/module.wat new file mode 100644 index 0000000000..a0a9f1327d --- /dev/null +++ b/crates/wit-component/tests/components/lower-options/module.wat @@ -0,0 +1,20 @@ +(module + (import "foo:foo/foo" "a" (func)) + (import "foo:foo/foo" "b" (func (param i32 i32))) + (import "foo:foo/foo" "c" (func (param i32 i32))) + (import "foo:foo/foo" "d" (func (param i32 i32 i32))) + (import "foo:foo/foo" "e" (func (param i32))) + (import "foo:foo/foo" "f" (func (param i32 i32))) + (import "foo:foo/foo" "g" (func (param i32 i32))) + (import "foo:foo/foo" "h" (func (param i32 i32))) + (import "foo:foo/foo" "i" (func (param i32 i32))) + (import "foo:foo/foo" "j" (func (param i32))) + (import "foo:foo/foo" "k" (func (param i32))) + (import "foo:foo/foo" "l" (func (param i32))) + (import "foo:foo/foo" "m" (func (param i32))) + (import "foo:foo/foo" "n" (func (result i32))) + (import "foo:foo/foo" "o" (func (param i32))) + (import "foo:foo/foo" "p" (func (param i32))) + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) +) diff --git a/crates/wit-component/tests/components/lower-options/module.wit b/crates/wit-component/tests/components/lower-options/module.wit new file mode 100644 index 0000000000..fac2a606dd --- /dev/null +++ b/crates/wit-component/tests/components/lower-options/module.wit @@ -0,0 +1,40 @@ +package foo:foo; + +interface foo { + record r { + s: string + } + + record r-no-string { + s: u32 + } + + variant v { + s(string) + } + + variant v-no-string { + s(u32) + } + + a: func(); + b: func(x: list); + c: func(x: r); + d: func(x: v); + e: func(x: r-no-string); + f: func(x: v-no-string); + g: func(x: list); + h: func(x: list); + i: func(x: list); + j: func(x: u32); + k: func() -> tuple; + l: func() -> string; + m: func() -> list; + n: func() -> u32; + o: func() -> v; + p: func() -> list; +} + +world module { + import foo; +} diff --git a/crates/wit-component/tests/components/many-same-names/component.wat b/crates/wit-component/tests/components/many-same-names/component.wat new file mode 100644 index 0000000000..7c84080c42 --- /dev/null +++ b/crates/wit-component/tests/components/many-same-names/component.wat @@ -0,0 +1,46 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "name#a" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (component (;0;) + (type (;0;) (record (field "f" u8))) + (export (;1;) "r1" (type 0)) + (type (;2;) (record (field "x" 1))) + (export (;3;) "r2" (type 2)) + ) + (instance (;0;) (instantiate 0)) + (export (;1;) (interface "foo:foo/name") (instance 0)) + (type (;0;) (func)) + (alias core export 0 "name#a" (core func (;0;))) + (func (;0;) (type 0) (canon lift (core func 0))) + (alias export 1 "r1" (type (;1;))) + (alias export 1 "r2" (type (;2;))) + (component (;1;) + (type (;0;) (record (field "f" u8))) + (import "import-type-r1" (type (;1;) (eq 0))) + (type (;2;) (record (field "x" 1))) + (import "import-type-r2" (type (;3;) (eq 2))) + (type (;4;) (func)) + (import "import-func-a" (func (;0;) (type 4))) + (export (;5;) "r2" (type 3)) + (type (;6;) (func)) + (export (;1;) "a" (func 0) (func (type 6))) + ) + (instance (;2;) (instantiate 1 + (with "import-func-a" (func 0)) + (with "import-type-r1" (type 1)) + (with "import-type-r2" (type 2)) + ) + ) + (export (;3;) "name" (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/many-same-names/component.wit.print b/crates/wit-component/tests/components/many-same-names/component.wit.print new file mode 100644 index 0000000000..c13c2a4cfb --- /dev/null +++ b/crates/wit-component/tests/components/many-same-names/component.wit.print @@ -0,0 +1,10 @@ +package root:component + +world root { + export foo:foo/name + export name: interface { + use foo:foo/name.{r2} + + a: func() + } +} diff --git a/crates/wit-component/tests/components/many-same-names/module.wat b/crates/wit-component/tests/components/many-same-names/module.wat new file mode 100644 index 0000000000..1cb58c5b52 --- /dev/null +++ b/crates/wit-component/tests/components/many-same-names/module.wat @@ -0,0 +1,3 @@ +(module + (func (export "name#a")) +) diff --git a/crates/wit-component/tests/components/many-same-names/module.wit b/crates/wit-component/tests/components/many-same-names/module.wit new file mode 100644 index 0000000000..020baad81a --- /dev/null +++ b/crates/wit-component/tests/components/many-same-names/module.wit @@ -0,0 +1,21 @@ +package foo:foo; + +interface name { + record r1 { + f: u8, + } + + record r2 { + x: r1 + } +} + +world module { + import name; + export name; + + export name: interface { + use name.{r2}; + a: func(); + } +} diff --git a/crates/wit-component/tests/components/no-realloc-required/component.wat b/crates/wit-component/tests/components/no-realloc-required/component.wat new file mode 100644 index 0000000000..7c8c1e80a8 --- /dev/null +++ b/crates/wit-component/tests/components/no-realloc-required/component.wat @@ -0,0 +1,67 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "s" string))) + (export (;0;) "log" (func (type 0))) + ) + ) + (import "foo" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32 i32))) + (import "foo" "log" (func (;0;) (type 0))) + (memory (;0;) 1) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32 i32))) + (func $indirect-foo-log (;0;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + i32.const 0 + call_indirect (type 0) + ) + (table (;0;) 1 1 funcref) + (export "0" (func $indirect-foo-log)) + (export "$imports" (table 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32 i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "$imports" (table (;0;) 1 1 funcref)) + (elem (;0;) (i32.const 0) func 0) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 1)) + (alias core export 0 "0" (core func (;0;))) + (core instance (;1;) + (export "log" (func 0)) + ) + (core instance (;2;) (instantiate 0 + (with "foo" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 0 "$imports" (core table (;0;))) + (alias export 0 "log" (func (;0;))) + (core func (;1;) (canon lower (func 0) (memory 0) string-encoding=utf8)) + (core instance (;3;) + (export "$imports" (table 0)) + (export "0" (func 1)) + ) + (core instance (;4;) (instantiate 2 + (with "" (instance 3)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/no-realloc-required/component.wit.print b/crates/wit-component/tests/components/no-realloc-required/component.wit.print new file mode 100644 index 0000000000..f1fc2527b5 --- /dev/null +++ b/crates/wit-component/tests/components/no-realloc-required/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import foo: interface { + log: func(s: string) + } +} diff --git a/crates/wit-component/tests/components/no-realloc-required/module.wat b/crates/wit-component/tests/components/no-realloc-required/module.wat new file mode 100644 index 0000000000..83b9b701d8 --- /dev/null +++ b/crates/wit-component/tests/components/no-realloc-required/module.wat @@ -0,0 +1,4 @@ +(module + (import "foo" "log" (func (param i32 i32))) + (memory (export "memory") 1) +) diff --git a/crates/wit-component/tests/components/no-realloc-required/module.wit b/crates/wit-component/tests/components/no-realloc-required/module.wit new file mode 100644 index 0000000000..481eefa2fa --- /dev/null +++ b/crates/wit-component/tests/components/no-realloc-required/module.wit @@ -0,0 +1,7 @@ +package foo:foo; + +world module { + import foo: interface { + log: func(s: string); + } +} diff --git a/crates/wit-component/tests/components/post-return/component.wat b/crates/wit-component/tests/components/post-return/component.wat new file mode 100644 index 0000000000..0fd5f323ad --- /dev/null +++ b/crates/wit-component/tests/components/post-return/component.wat @@ -0,0 +1,36 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32))) + (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;1;) (type 1) (result i32) + unreachable + ) + (func (;2;) (type 2) (param i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 0)) + (export "a" (func 1)) + (export "cabi_post_a" (func 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "cabi_realloc" (core func (;0;))) + (type (;0;) (func (result string))) + (alias core export 0 "a" (core func (;1;))) + (alias core export 0 "cabi_post_a" (core func (;2;))) + (func (;0;) (type 0) (canon lift (core func 1) (memory 0) string-encoding=utf8 (post-return 2))) + (export (;1;) "a" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/post-return/component.wit.print b/crates/wit-component/tests/components/post-return/component.wit.print new file mode 100644 index 0000000000..a1d34262af --- /dev/null +++ b/crates/wit-component/tests/components/post-return/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + export a: func() -> string +} diff --git a/crates/wit-component/tests/components/post-return/module.wat b/crates/wit-component/tests/components/post-return/module.wat new file mode 100644 index 0000000000..985257e240 --- /dev/null +++ b/crates/wit-component/tests/components/post-return/module.wat @@ -0,0 +1,6 @@ +(module + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "a") (result i32) unreachable) + (func (export "cabi_post_a") (param i32) unreachable) +) diff --git a/crates/wit-component/tests/components/post-return/module.wit b/crates/wit-component/tests/components/post-return/module.wit new file mode 100644 index 0000000000..043467c904 --- /dev/null +++ b/crates/wit-component/tests/components/post-return/module.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world module { + export a: func() -> string; +} diff --git a/crates/wit-component/tests/components/rename-import-interface/component.wat b/crates/wit-component/tests/components/rename-import-interface/component.wat new file mode 100644 index 0000000000..929103c013 --- /dev/null +++ b/crates/wit-component/tests/components/rename-import-interface/component.wat @@ -0,0 +1,29 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "the-func" (func (type 0))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func)) + (import "foo:foo/foo" "the-func" (func (;0;) (type 0))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "the-func" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;0;) + (export "the-func" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "foo:foo/foo" (instance 0)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/rename-import-interface/component.wit.print b/crates/wit-component/tests/components/rename-import-interface/component.wit.print new file mode 100644 index 0000000000..7ef7c78b37 --- /dev/null +++ b/crates/wit-component/tests/components/rename-import-interface/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + import foo:foo/foo +} diff --git a/crates/wit-component/tests/components/rename-import-interface/module.wat b/crates/wit-component/tests/components/rename-import-interface/module.wat new file mode 100644 index 0000000000..3a09d29a69 --- /dev/null +++ b/crates/wit-component/tests/components/rename-import-interface/module.wat @@ -0,0 +1,3 @@ +(module + (import "foo:foo/foo" "the-func" (func)) +) diff --git a/crates/wit-component/tests/components/rename-import-interface/module.wit b/crates/wit-component/tests/components/rename-import-interface/module.wit new file mode 100644 index 0000000000..6e1abda3b1 --- /dev/null +++ b/crates/wit-component/tests/components/rename-import-interface/module.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface foo { + the-func: func(); +} + +world module { + import foo; +} diff --git a/crates/wit-component/tests/components/rename-interface/component.wat b/crates/wit-component/tests/components/rename-interface/component.wat new file mode 100644 index 0000000000..300caf8b18 --- /dev/null +++ b/crates/wit-component/tests/components/rename-interface/component.wat @@ -0,0 +1,39 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "bar" (type (eq 0))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (alias export 0 "bar" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "bar" (type (eq 0))) + (type (;2;) (func (result 1))) + (export (;0;) "a" (func (type 2))) + ) + ) + (import "other-name" (instance (;1;) (type 2))) + (core module (;0;) + (type (;0;) (func (result i32))) + (import "other-name" "a" (func (;0;) (type 0))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 1 "a" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;0;) + (export "a" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "other-name" (instance 0)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/rename-interface/component.wit.print b/crates/wit-component/tests/components/rename-interface/component.wit.print new file mode 100644 index 0000000000..8687ef18c3 --- /dev/null +++ b/crates/wit-component/tests/components/rename-interface/component.wit.print @@ -0,0 +1,10 @@ +package root:component + +world root { + import foo:foo/foo + import other-name: interface { + use foo:foo/foo.{bar} + + a: func() -> bar + } +} diff --git a/crates/wit-component/tests/components/rename-interface/module.wat b/crates/wit-component/tests/components/rename-interface/module.wat new file mode 100644 index 0000000000..002259d77d --- /dev/null +++ b/crates/wit-component/tests/components/rename-interface/module.wat @@ -0,0 +1,3 @@ +(module + (import "other-name" "a" (func (result i32))) +) diff --git a/crates/wit-component/tests/components/rename-interface/module.wit b/crates/wit-component/tests/components/rename-interface/module.wit new file mode 100644 index 0000000000..c237a8541f --- /dev/null +++ b/crates/wit-component/tests/components/rename-interface/module.wit @@ -0,0 +1,18 @@ +package foo:foo; + +interface foo { + record bar { + f: u8, + } + + a: func() -> bar; +} + +world module { + import foo; + import other-name: interface { + use foo.{bar}; + + a: func() -> bar; + } +} diff --git a/crates/wit-component/tests/components/resource-intrinsics-with-just-import/component.wat b/crates/wit-component/tests/components/resource-intrinsics-with-just-import/component.wat new file mode 100644 index 0000000000..41509309d7 --- /dev/null +++ b/crates/wit-component/tests/components/resource-intrinsics-with-just-import/component.wat @@ -0,0 +1,28 @@ +(component + (type (;0;) + (instance + (export (;0;) "a" (type (sub resource))) + ) + ) + (import "foo" (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32))) + (import "foo" "[resource-drop]a" (func (;0;) (type 0))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "a" (type (;1;))) + (core func (;0;) (canon resource.drop 1)) + (core instance (;0;) + (export "[resource-drop]a" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "foo" (instance 0)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/resource-intrinsics-with-just-import/component.wit.print b/crates/wit-component/tests/components/resource-intrinsics-with-just-import/component.wit.print new file mode 100644 index 0000000000..8cc7cfa730 --- /dev/null +++ b/crates/wit-component/tests/components/resource-intrinsics-with-just-import/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + import foo: interface { + resource a + } +} diff --git a/crates/wit-component/tests/components/resource-intrinsics-with-just-import/module.wat b/crates/wit-component/tests/components/resource-intrinsics-with-just-import/module.wat new file mode 100644 index 0000000000..1f989c2215 --- /dev/null +++ b/crates/wit-component/tests/components/resource-intrinsics-with-just-import/module.wat @@ -0,0 +1,3 @@ +(module + (import "foo" "[resource-drop]a" (func (param i32))) +) diff --git a/crates/wit-component/tests/components/resource-intrinsics-with-just-import/module.wit b/crates/wit-component/tests/components/resource-intrinsics-with-just-import/module.wit new file mode 100644 index 0000000000..036ff501ed --- /dev/null +++ b/crates/wit-component/tests/components/resource-intrinsics-with-just-import/module.wit @@ -0,0 +1,7 @@ +package foo:bar; + +world module { + import foo: interface { + resource a; + } +} diff --git a/crates/wit-component/tests/components/resource-used-through-import/component.wat b/crates/wit-component/tests/components/resource-used-through-import/component.wat new file mode 100644 index 0000000000..729cb3de51 --- /dev/null +++ b/crates/wit-component/tests/components/resource-used-through-import/component.wat @@ -0,0 +1,57 @@ +(component + (type (;0;) + (instance + (export (;0;) "r" (type (sub resource))) + ) + ) + (import (interface "foo:bar/a") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32))) + (type (;1;) (func (result i32))) + (import "foo:bar/a" "[resource-drop]r" (func (;0;) (type 0))) + (func (;1;) (type 1) (result i32) + i32.const 0 + ) + (export "b#foo" (func 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "r" (type (;1;))) + (core func (;0;) (canon resource.drop 1)) + (core instance (;0;) + (export "[resource-drop]r" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "foo:bar/a" (instance 0)) + ) + ) + (alias export 0 "r" (type (;2;))) + (type (;3;) (own 2)) + (type (;4;) (func (result 3))) + (alias core export 1 "b#foo" (core func (;1;))) + (func (;0;) (type 4) (canon lift (core func 1))) + (alias export 0 "r" (type (;5;))) + (component (;0;) + (import "import-type-r" (type (;0;) (sub resource))) + (import "import-type-r0" (type (;1;) (eq 0))) + (type (;2;) (own 1)) + (type (;3;) (func (result 2))) + (import "import-func-foo" (func (;0;) (type 3))) + (export (;4;) "r" (type 0)) + (type (;5;) (own 4)) + (type (;6;) (func (result 5))) + (export (;1;) "foo" (func 0) (func (type 6))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-foo" (func 0)) + (with "import-type-r" (type 5)) + (with "import-type-r0" (type 2)) + ) + ) + (export (;2;) "b" (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/resource-used-through-import/component.wit.print b/crates/wit-component/tests/components/resource-used-through-import/component.wit.print new file mode 100644 index 0000000000..33604827ec --- /dev/null +++ b/crates/wit-component/tests/components/resource-used-through-import/component.wit.print @@ -0,0 +1,11 @@ +package root:component + +world root { + import foo:bar/a + + export b: interface { + use foo:bar/a.{r} + + foo: func() -> r + } +} diff --git a/crates/wit-component/tests/components/resource-used-through-import/module.wat b/crates/wit-component/tests/components/resource-used-through-import/module.wat new file mode 100644 index 0000000000..45428e2239 --- /dev/null +++ b/crates/wit-component/tests/components/resource-used-through-import/module.wat @@ -0,0 +1,6 @@ +(module + (import "foo:bar/a" "[resource-drop]r" (func (param i32))) + (func (export "b#foo") (result i32) + (i32.const 0) + ) +) diff --git a/crates/wit-component/tests/components/resource-used-through-import/module.wit b/crates/wit-component/tests/components/resource-used-through-import/module.wit new file mode 100644 index 0000000000..e18f09d860 --- /dev/null +++ b/crates/wit-component/tests/components/resource-used-through-import/module.wit @@ -0,0 +1,13 @@ +package foo:bar; + +interface a { + resource r; +} + +world module { + export b: interface { + use a.{r}; + + foo: func() -> r; + } +} diff --git a/crates/wit-component/tests/components/resource-using-export/component.wat b/crates/wit-component/tests/components/resource-using-export/component.wat new file mode 100644 index 0000000000..b1cb6c403d --- /dev/null +++ b/crates/wit-component/tests/components/resource-using-export/component.wat @@ -0,0 +1,63 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (import "[export]foo:bar/foo" "[resource-new]r" (func $new (;0;) (type 0))) + (func (;1;) (type 1) (result i32) + i32.const 100 + call $new + ) + (export "anon#f" (func 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (type (;0;) (resource (rep i32))) + (core func (;0;) (canon resource.new 0)) + (core instance (;0;) + (export "[resource-new]r" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "[export]foo:bar/foo" (instance 0)) + ) + ) + (component (;0;) + (import "import-type-r" (type (;0;) (sub resource))) + (export (;1;) "r" (type 0)) + (type (;2;) (own 1)) + (export (;3;) "handle" (type 2)) + ) + (instance (;0;) (instantiate 0 + (with "import-type-r" (type 0)) + ) + ) + (export (;1;) (interface "foo:bar/foo") (instance 0)) + (alias export 1 "handle" (type (;1;))) + (type (;2;) (func (result 1))) + (alias core export 1 "anon#f" (core func (;1;))) + (func (;0;) (type 2) (canon lift (core func 1))) + (alias export 1 "r" (type (;3;))) + (component (;1;) + (import "import-type-r" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (import "import-type-handle" (type (;2;) (eq 1))) + (import "import-type-handle0" (type (;3;) (eq 2))) + (type (;4;) (func (result 3))) + (import "import-func-f" (func (;0;) (type 4))) + (export (;5;) "handle" (type 2)) + (type (;6;) (func (result 5))) + (export (;1;) "f" (func 0) (func (type 6))) + ) + (instance (;2;) (instantiate 1 + (with "import-func-f" (func 0)) + (with "import-type-r" (type 3)) + (with "import-type-handle" (type 1)) + (with "import-type-handle0" (type 1)) + ) + ) + (export (;3;) "anon" (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/resource-using-export/component.wit.print b/crates/wit-component/tests/components/resource-using-export/component.wit.print new file mode 100644 index 0000000000..3de043990a --- /dev/null +++ b/crates/wit-component/tests/components/resource-using-export/component.wit.print @@ -0,0 +1,10 @@ +package root:component + +world root { + export foo:bar/foo + export anon: interface { + use foo:bar/foo.{handle} + + f: func() -> handle + } +} diff --git a/crates/wit-component/tests/components/resource-using-export/module.wat b/crates/wit-component/tests/components/resource-using-export/module.wat new file mode 100644 index 0000000000..38c372c877 --- /dev/null +++ b/crates/wit-component/tests/components/resource-using-export/module.wat @@ -0,0 +1,6 @@ +(module + (import "[export]foo:bar/foo" "[resource-new]r" (func $new (param i32) (result i32))) + (func (export "anon#f") (result i32) + (call $new (i32.const 100)) + ) +) diff --git a/crates/wit-component/tests/components/resource-using-export/module.wit b/crates/wit-component/tests/components/resource-using-export/module.wit new file mode 100644 index 0000000000..3b906f6ec0 --- /dev/null +++ b/crates/wit-component/tests/components/resource-using-export/module.wit @@ -0,0 +1,16 @@ +package foo:bar; + +interface foo { + resource r; + + type handle = own; +} + +world module { + export foo; + export anon: interface { + use foo.{handle}; + f: func() -> handle; + } +} + diff --git a/crates/wit-component/tests/components/simple/component.wat b/crates/wit-component/tests/components/simple/component.wat new file mode 100644 index 0000000000..6b9902d70f --- /dev/null +++ b/crates/wit-component/tests/components/simple/component.wat @@ -0,0 +1,64 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (param i32))) + (type (;4;) (func (param i32 i32) (result i32))) + (type (;5;) (func (param i32 i32))) + (func $cabi_realloc (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func $a (;1;) (type 1) + unreachable + ) + (func $b (;2;) (type 2) (result i32) + unreachable + ) + (func (;3;) (type 3) (param i32) + unreachable + ) + (func $c (;4;) (type 4) (param i32 i32) (result i32) + unreachable + ) + (func (;5;) (type 3) (param i32) + unreachable + ) + (func $d (;6;) (type 5) (param i32 i32) + unreachable + ) + (memory $memory (;0;) 1) + (export "memory" (memory $memory)) + (export "cabi_realloc" (func $cabi_realloc)) + (export "a" (func $a)) + (export "b" (func $b)) + (export "cabi_post_b" (func 3)) + (export "c" (func $c)) + (export "cabi_post_c" (func 5)) + (export "d" (func $d)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "cabi_realloc" (core func (;0;))) + (type (;0;) (func)) + (alias core export 0 "a" (core func (;1;))) + (func (;0;) (type 0) (canon lift (core func 1))) + (export (;1;) "a" (func 0)) + (type (;1;) (func (result string))) + (alias core export 0 "b" (core func (;2;))) + (alias core export 0 "cabi_post_b" (core func (;3;))) + (func (;2;) (type 1) (canon lift (core func 2) (memory 0) string-encoding=utf8 (post-return 3))) + (export (;3;) "b" (func 2)) + (type (;2;) (func (param "x" string) (result string))) + (alias core export 0 "c" (core func (;4;))) + (alias core export 0 "cabi_post_c" (core func (;5;))) + (func (;4;) (type 2) (canon lift (core func 4) (memory 0) (realloc 0) string-encoding=utf8 (post-return 5))) + (export (;5;) "c" (func 4)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/simple/component.wit.print b/crates/wit-component/tests/components/simple/component.wit.print new file mode 100644 index 0000000000..5c7dcae2fd --- /dev/null +++ b/crates/wit-component/tests/components/simple/component.wit.print @@ -0,0 +1,7 @@ +package root:component + +world root { + export a: func() + export b: func() -> string + export c: func(x: string) -> string +} diff --git a/crates/wit-component/tests/components/simple/module.wat b/crates/wit-component/tests/components/simple/module.wat new file mode 100644 index 0000000000..efa7b01a4f --- /dev/null +++ b/crates/wit-component/tests/components/simple/module.wat @@ -0,0 +1,10 @@ +(module + (memory $memory (export "memory") 1) + (func $cabi_realloc (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (func $a (export "a") unreachable) + (func $b (export "b") (result i32) unreachable) + (func (export "cabi_post_b") (param i32) unreachable) + (func $c (export "c") (param i32 i32) (result i32) unreachable) + (func (export "cabi_post_c") (param i32) unreachable) + (func $d (export "d") (param i32 i32) unreachable) +) diff --git a/crates/wit-component/tests/components/simple/module.wit b/crates/wit-component/tests/components/simple/module.wit new file mode 100644 index 0000000000..2ddaa10757 --- /dev/null +++ b/crates/wit-component/tests/components/simple/module.wit @@ -0,0 +1,7 @@ +package foo:foo; + +world module { + export a: func(); + export b: func() -> string; + export c: func(x: string) -> string; +} diff --git a/crates/wit-component/tests/components/tricky-order/component.wat b/crates/wit-component/tests/components/tricky-order/component.wat new file mode 100644 index 0000000000..d46be4d187 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-order/component.wat @@ -0,0 +1,42 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "name" (type (eq 0))) + ) + ) + (import (interface "foo:foo/name1") (instance (;0;) (type 0))) + (alias export 0 "name" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "name" (type (eq 0))) + ) + ) + (import (interface "foo:foo/name2") (instance (;1;) (type 2))) + (core module (;0;) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias export 0 "name" (type (;3;))) + (alias export 1 "name" (type (;4;))) + (component (;0;) + (type (;0;) (record (field "f" u8))) + (import "import-type-name" (type (;1;) (eq 0))) + (import "import-type-name0" (type (;2;) (eq 1))) + (export (;3;) "name" (type 1)) + (export (;4;) "name1" (type 2)) + ) + (instance (;2;) (instantiate 0 + (with "import-type-name" (type 3)) + (with "import-type-name0" (type 4)) + ) + ) + (export (;3;) "name" (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/tricky-order/component.wit.print b/crates/wit-component/tests/components/tricky-order/component.wit.print new file mode 100644 index 0000000000..53365cc682 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-order/component.wit.print @@ -0,0 +1,11 @@ +package root:component + +world root { + import foo:foo/name1 + import foo:foo/name2 + + export name: interface { + use foo:foo/name1.{name} + use foo:foo/name2.{name as name1} + } +} diff --git a/crates/wit-component/tests/components/tricky-order/module.wat b/crates/wit-component/tests/components/tricky-order/module.wat new file mode 100644 index 0000000000..3af8f25454 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-order/module.wat @@ -0,0 +1 @@ +(module) diff --git a/crates/wit-component/tests/components/tricky-order/module.wit b/crates/wit-component/tests/components/tricky-order/module.wit new file mode 100644 index 0000000000..040aa39569 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-order/module.wit @@ -0,0 +1,20 @@ +package foo:foo; + +interface name1 { + record name { + f: u8, + } +} + +interface name2 { + use name1.{name}; +} + +world module { + import name1; + import name2; + export name: interface { + use name1.{name}; + use name2.{name as name1}; + } +} diff --git a/crates/wit-component/tests/components/tricky-resources/component.wat b/crates/wit-component/tests/components/tricky-resources/component.wat new file mode 100644 index 0000000000..a7d64c1171 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources/component.wat @@ -0,0 +1,75 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (result i32))) + (import "[export]foo:bar/a" "[resource-drop]r" (func (;0;) (type 0))) + (import "[export]foo:bar/a" "[resource-rep]r" (func (;1;) (type 1))) + (func (;2;) (type 2) (result i32) + unreachable + ) + (export "some-name#f" (func 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (type (;0;) (resource (rep i32))) + (core func (;0;) (canon resource.drop 0)) + (core func (;1;) (canon resource.rep 0)) + (core instance (;0;) + (export "[resource-drop]r" (func 0)) + (export "[resource-rep]r" (func 1)) + ) + (core instance (;1;) (instantiate 0 + (with "[export]foo:bar/a" (instance 0)) + ) + ) + (component (;0;) + (import "import-type-r" (type (;0;) (sub resource))) + (export (;1;) "r" (type 0)) + ) + (instance (;0;) (instantiate 0 + (with "import-type-r" (type 0)) + ) + ) + (export (;1;) (interface "foo:bar/a") (instance 0)) + (alias export 1 "r" (type (;1;))) + (component (;1;) + (import "import-type-r" (type (;0;) (sub resource))) + (export (;1;) "r" (type 0)) + ) + (instance (;2;) (instantiate 1 + (with "import-type-r" (type 1)) + ) + ) + (export (;3;) (interface "foo:bar/b") (instance 2)) + (alias export 3 "r" (type (;2;))) + (type (;3;) (own 2)) + (type (;4;) (func (result 3))) + (alias core export 1 "some-name#f" (core func (;2;))) + (func (;0;) (type 4) (canon lift (core func 2))) + (component (;2;) + (import "import-type-r" (type (;0;) (sub resource))) + (import "import-type-r0" (type (;1;) (eq 0))) + (import "import-type-r01" (type (;2;) (eq 1))) + (type (;3;) (own 2)) + (type (;4;) (func (result 3))) + (import "import-func-f" (func (;0;) (type 4))) + (export (;5;) "r" (type 1)) + (type (;6;) (own 5)) + (type (;7;) (func (result 6))) + (export (;1;) "f" (func 0) (func (type 7))) + ) + (instance (;4;) (instantiate 2 + (with "import-func-f" (func 0)) + (with "import-type-r" (type 1)) + (with "import-type-r0" (type 2)) + (with "import-type-r01" (type 2)) + ) + ) + (export (;5;) "some-name" (instance 4)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/tricky-resources/component.wit.print b/crates/wit-component/tests/components/tricky-resources/component.wit.print new file mode 100644 index 0000000000..d400c25403 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources/component.wit.print @@ -0,0 +1,11 @@ +package root:component + +world root { + export foo:bar/a + export foo:bar/b + export some-name: interface { + use foo:bar/b.{r} + + f: func() -> r + } +} diff --git a/crates/wit-component/tests/components/tricky-resources/module.wat b/crates/wit-component/tests/components/tricky-resources/module.wat new file mode 100644 index 0000000000..788821cdee --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources/module.wat @@ -0,0 +1,7 @@ +(module + (import "[export]foo:bar/a" "[resource-drop]r" (func (param i32))) + (import "[export]foo:bar/a" "[resource-rep]r" (func (param i32) (result i32))) + + (func (export "some-name#f") (result i32) + unreachable) +) diff --git a/crates/wit-component/tests/components/tricky-resources/module.wit b/crates/wit-component/tests/components/tricky-resources/module.wit new file mode 100644 index 0000000000..523ad87bb2 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources/module.wit @@ -0,0 +1,19 @@ +package foo:bar; + +interface a { + resource r; +} + +interface b { + use a.{r}; +} + +world module { + export b; + export some-name: interface { + use b.{r}; + + f: func() -> r; + } + export a; +} diff --git a/crates/wit-component/tests/components/tricky-resources2/component.wat b/crates/wit-component/tests/components/tricky-resources2/component.wat new file mode 100644 index 0000000000..2f611ee7f4 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources2/component.wat @@ -0,0 +1,50 @@ +(component + (core module (;0;) + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + unreachable + ) + (export "anon#foo" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (type (;0;) (resource (rep i32))) + (core instance (;0;) (instantiate 0)) + (component (;0;) + (import "import-type-r" (type (;0;) (sub resource))) + (export (;1;) "r" (type 0)) + ) + (instance (;0;) (instantiate 0 + (with "import-type-r" (type 0)) + ) + ) + (export (;1;) (interface "foo:bar/a") (instance 0)) + (alias export 1 "r" (type (;1;))) + (type (;2;) (own 1)) + (type (;3;) (func (result 2))) + (alias core export 0 "anon#foo" (core func (;0;))) + (func (;0;) (type 3) (canon lift (core func 0))) + (component (;1;) + (import "import-type-r" (type (;0;) (sub resource))) + (import "import-type-r0" (type (;1;) (eq 0))) + (type (;2;) (own 1)) + (type (;3;) (func (result 2))) + (import "import-func-foo" (func (;0;) (type 3))) + (export (;4;) "r" (type 0)) + (type (;5;) (own 4)) + (type (;6;) (func (result 5))) + (export (;1;) "foo" (func 0) (func (type 6))) + ) + (instance (;2;) (instantiate 1 + (with "import-func-foo" (func 0)) + (with "import-type-r" (type 1)) + (with "import-type-r0" (type 1)) + ) + ) + (export (;3;) "anon" (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/tricky-resources2/component.wit.print b/crates/wit-component/tests/components/tricky-resources2/component.wit.print new file mode 100644 index 0000000000..ababf1db4c --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources2/component.wit.print @@ -0,0 +1,10 @@ +package root:component + +world root { + export foo:bar/a + export anon: interface { + use foo:bar/a.{r} + + foo: func() -> r + } +} diff --git a/crates/wit-component/tests/components/tricky-resources2/module.wat b/crates/wit-component/tests/components/tricky-resources2/module.wat new file mode 100644 index 0000000000..bb3630ceff --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources2/module.wat @@ -0,0 +1,4 @@ +(module + (func (export "anon#foo") (result i32) + unreachable) +) diff --git a/crates/wit-component/tests/components/tricky-resources2/module.wit b/crates/wit-component/tests/components/tricky-resources2/module.wit new file mode 100644 index 0000000000..8b149b179c --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources2/module.wit @@ -0,0 +1,14 @@ +package foo:bar; + +interface a { + resource r; +} + +world module { + export anon: interface { + use a.{r}; + + foo: func() -> r; + } + export a; +} diff --git a/crates/wit-component/tests/components/tricky-resources3/component.wat b/crates/wit-component/tests/components/tricky-resources3/component.wat new file mode 100644 index 0000000000..49e146d4b6 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources3/component.wat @@ -0,0 +1,44 @@ +(component + (core module (;0;) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (type (;0;) (resource (rep i32))) + (core instance (;0;) (instantiate 0)) + (component (;0;) + (import "import-type-name" (type (;0;) (sub resource))) + (export (;1;) "name" (type 0)) + ) + (instance (;0;) (instantiate 0 + (with "import-type-name" (type 0)) + ) + ) + (export (;1;) (interface "foo:bar/foo") (instance 0)) + (alias export 1 "name" (type (;1;))) + (component (;1;) + (import "import-type-name" (type (;0;) (sub resource))) + (export (;1;) "name" (type 0)) + ) + (instance (;2;) (instantiate 1 + (with "import-type-name" (type 1)) + ) + ) + (export (;3;) (interface "foo:bar/name") (instance 2)) + (alias export 3 "name" (type (;2;))) + (component (;2;) + (import "import-type-name" (type (;0;) (sub resource))) + (import "import-type-name0" (type (;1;) (eq 0))) + (export (;2;) "name" (type 1)) + ) + (instance (;4;) (instantiate 2 + (with "import-type-name" (type 1)) + (with "import-type-name0" (type 2)) + ) + ) + (export (;5;) "name" (instance 4)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/tricky-resources3/component.wit.print b/crates/wit-component/tests/components/tricky-resources3/component.wit.print new file mode 100644 index 0000000000..082f52f829 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources3/component.wit.print @@ -0,0 +1,9 @@ +package root:component + +world root { + export foo:bar/foo + export foo:bar/name + export name: interface { + use foo:bar/name.{name} + } +} diff --git a/crates/wit-component/tests/components/tricky-resources3/module.wat b/crates/wit-component/tests/components/tricky-resources3/module.wat new file mode 100644 index 0000000000..3af8f25454 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources3/module.wat @@ -0,0 +1 @@ +(module) diff --git a/crates/wit-component/tests/components/tricky-resources3/module.wit b/crates/wit-component/tests/components/tricky-resources3/module.wit new file mode 100644 index 0000000000..36e0edf476 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources3/module.wit @@ -0,0 +1,17 @@ +package foo:bar; + +interface foo { + resource name; +} + +interface name { + use foo.{name}; +} + +world module { + export foo; + export name; + export name: interface { + use name.{name}; + } +} diff --git a/crates/wit-component/tests/components/tricky-resources4/component.wat b/crates/wit-component/tests/components/tricky-resources4/component.wat new file mode 100644 index 0000000000..7e7608155d --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources4/component.wat @@ -0,0 +1,64 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (import "[export]foo:bar/name" "[resource-new]name" (func $new (;0;) (type 0))) + (func (;1;) (type 1) (result i32) + i32.const 100 + call $new + ) + (export "foo:bar/name#foo" (func 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (type (;0;) (resource (rep i32))) + (core func (;0;) (canon resource.new 0)) + (core instance (;0;) + (export "[resource-new]name" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "[export]foo:bar/name" (instance 0)) + ) + ) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (alias core export 1 "foo:bar/name#foo" (core func (;1;))) + (func (;0;) (type 2) (canon lift (core func 1))) + (component (;0;) + (import "import-type-name" (type (;0;) (sub resource))) + (import "import-type-handle" (type (;1;) (eq 0))) + (type (;2;) (own 1)) + (type (;3;) (func (result 2))) + (import "import-func-foo" (func (;0;) (type 3))) + (export (;4;) "name" (type 0)) + (export (;5;) "handle" (type 4)) + (type (;6;) (own 5)) + (type (;7;) (func (result 6))) + (export (;1;) "foo" (func 0) (func (type 7))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-foo" (func 0)) + (with "import-type-name" (type 0)) + (with "import-type-handle" (type 0)) + ) + ) + (export (;1;) (interface "foo:bar/name") (instance 0)) + (alias export 1 "name" (type (;3;))) + (alias export 1 "handle" (type (;4;))) + (component (;1;) + (import "import-type-name" (type (;0;) (sub resource))) + (import "import-type-handle" (type (;1;) (eq 0))) + (export (;2;) "handle" (type 1)) + ) + (instance (;2;) (instantiate 1 + (with "import-type-name" (type 3)) + (with "import-type-handle" (type 4)) + ) + ) + (export (;3;) "name" (instance 2)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/tricky-resources4/component.wit.print b/crates/wit-component/tests/components/tricky-resources4/component.wit.print new file mode 100644 index 0000000000..5bc857709d --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources4/component.wit.print @@ -0,0 +1,8 @@ +package root:component + +world root { + export foo:bar/name + export name: interface { + use foo:bar/name.{handle} + } +} diff --git a/crates/wit-component/tests/components/tricky-resources4/module.wat b/crates/wit-component/tests/components/tricky-resources4/module.wat new file mode 100644 index 0000000000..bb3ade4901 --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources4/module.wat @@ -0,0 +1,6 @@ +(module + (import "[export]foo:bar/name" "[resource-new]name" + (func $new (param i32) (result i32))) + (func (export "foo:bar/name#foo") (result i32) + (call $new (i32.const 100))) +) diff --git a/crates/wit-component/tests/components/tricky-resources4/module.wit b/crates/wit-component/tests/components/tricky-resources4/module.wit new file mode 100644 index 0000000000..7e1f5053ea --- /dev/null +++ b/crates/wit-component/tests/components/tricky-resources4/module.wit @@ -0,0 +1,16 @@ +package foo:bar; + +interface name { + resource name; + + type handle = name; + + foo: func() -> handle; +} + +world module { + export name; + export name: interface { + use name.{handle}; + } +} diff --git a/crates/wit-component/tests/components/unused-import/component.wat b/crates/wit-component/tests/components/unused-import/component.wat new file mode 100644 index 0000000000..59d4716d58 --- /dev/null +++ b/crates/wit-component/tests/components/unused-import/component.wat @@ -0,0 +1,29 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "x" bool))) + (export (;0;) "name" (func (type 0))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func (param i32))) + (import "foo:foo/foo" "name" (func (;0;) (type 0))) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "name" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;0;) + (export "name" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "foo:foo/foo" (instance 0)) + ) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/unused-import/component.wit.print b/crates/wit-component/tests/components/unused-import/component.wit.print new file mode 100644 index 0000000000..7ef7c78b37 --- /dev/null +++ b/crates/wit-component/tests/components/unused-import/component.wit.print @@ -0,0 +1,5 @@ +package root:component + +world root { + import foo:foo/foo +} diff --git a/crates/wit-component/tests/components/unused-import/module.wat b/crates/wit-component/tests/components/unused-import/module.wat new file mode 100644 index 0000000000..eede8e1ac4 --- /dev/null +++ b/crates/wit-component/tests/components/unused-import/module.wat @@ -0,0 +1,3 @@ +(module + (import "foo:foo/foo" "name" (func (param i32))) +) diff --git a/crates/wit-component/tests/components/unused-import/module.wit b/crates/wit-component/tests/components/unused-import/module.wit new file mode 100644 index 0000000000..04ff702d07 --- /dev/null +++ b/crates/wit-component/tests/components/unused-import/module.wit @@ -0,0 +1,12 @@ +package foo:foo; + +interface bar {} + +interface foo { + name: func(x: bool); +} + +world module { + import bar; // unused + import foo; +} diff --git a/crates/wit-component/tests/components/worlds-with-type-renamings/component.wat b/crates/wit-component/tests/components/worlds-with-type-renamings/component.wat new file mode 100644 index 0000000000..3d23846db4 --- /dev/null +++ b/crates/wit-component/tests/components/worlds-with-type-renamings/component.wat @@ -0,0 +1,67 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "some-type" (type (eq 0))) + (type (;2;) (func (result 1))) + (export (;0;) "the-func" (func (type 2))) + ) + ) + (import (interface "foo:foo/i") (instance (;0;) (type 0))) + (alias export 0 "some-type" (type (;1;))) + (import "other-name" (type (;2;) (eq 1))) + (core module (;0;) + (type (;0;) (func (param i32 i64 i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (type (;2;) (func (result i32))) + (import "foo:foo/i" "the-func" (func (;0;) (type 2))) + (func (;1;) (type 2) (result i32) + unreachable + ) + (func (;2;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 0) + (export "foo:foo/i#the-func" (func 1)) + (export "cabi_realloc" (func 2)) + (export "memory" (memory 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (alias export 0 "the-func" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;0;) + (export "the-func" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "foo:foo/i" (instance 0)) + ) + ) + (alias core export 1 "memory" (core memory (;0;))) + (alias core export 1 "cabi_realloc" (core func (;1;))) + (type (;3;) (record (field "f" u8))) + (type (;4;) (func (result 3))) + (alias core export 1 "foo:foo/i#the-func" (core func (;2;))) + (func (;1;) (type 4) (canon lift (core func 2))) + (component (;0;) + (type (;0;) (record (field "f" u8))) + (import "import-type-some-type" (type (;1;) (eq 0))) + (type (;2;) (func (result 1))) + (import "import-func-the-func" (func (;0;) (type 2))) + (type (;3;) (record (field "f" u8))) + (export (;4;) "some-type" (type 3)) + (type (;5;) (func (result 4))) + (export (;1;) "the-func" (func 0) (func (type 5))) + ) + (instance (;1;) (instantiate 0 + (with "import-func-the-func" (func 1)) + (with "import-type-some-type" (type 3)) + ) + ) + (export (;2;) (interface "foo:foo/i") (instance 1)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/worlds-with-type-renamings/component.wit.print b/crates/wit-component/tests/components/worlds-with-type-renamings/component.wit.print new file mode 100644 index 0000000000..b87bb226f9 --- /dev/null +++ b/crates/wit-component/tests/components/worlds-with-type-renamings/component.wit.print @@ -0,0 +1,8 @@ +package root:component + +world root { + import foo:foo/i + use foo:foo/i.{some-type as other-name} + + export foo:foo/i +} diff --git a/crates/wit-component/tests/components/worlds-with-type-renamings/module.wat b/crates/wit-component/tests/components/worlds-with-type-renamings/module.wat new file mode 100644 index 0000000000..3592e7a323 --- /dev/null +++ b/crates/wit-component/tests/components/worlds-with-type-renamings/module.wat @@ -0,0 +1,12 @@ +(module + (type (;0;) (func (param i32 i64 i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "foo:foo/i" "the-func" (func (result i32))) + (func (export "foo:foo/i#the-func") (result i32) + unreachable + ) + (func (;2;) (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (export "memory") 0) +) diff --git a/crates/wit-component/tests/components/worlds-with-type-renamings/module.wit b/crates/wit-component/tests/components/worlds-with-type-renamings/module.wit new file mode 100644 index 0000000000..a83a6c0c73 --- /dev/null +++ b/crates/wit-component/tests/components/worlds-with-type-renamings/module.wit @@ -0,0 +1,17 @@ +package foo:foo; + +interface i { + record some-type { + f: u8, + } + + the-func: func() -> some-type; +} + + +world module { + use i.{some-type as other-name}; + + import i; + export i; +} diff --git a/crates/wit-component/tests/components/worlds-with-types/component.wat b/crates/wit-component/tests/components/worlds-with-types/component.wat new file mode 100644 index 0000000000..afb6bd454f --- /dev/null +++ b/crates/wit-component/tests/components/worlds-with-types/component.wat @@ -0,0 +1,25 @@ +(component + (type (;0;) u32) + (import "t" (type (;1;) (eq 0))) + (type (;2;) (record (field "x" 1))) + (import "r" (type (;3;) (eq 2))) + (core module (;0;) + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + i32.const 1 + ) + (export "a" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance (;0;) (instantiate 0)) + (type (;4;) (func (param "r" 3) (result 1))) + (alias core export 0 "a" (core func (;0;))) + (func (;0;) (type 4) (canon lift (core func 0))) + (export (;1;) "a" (func 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/components/worlds-with-types/component.wit.print b/crates/wit-component/tests/components/worlds-with-types/component.wit.print new file mode 100644 index 0000000000..e68a82150e --- /dev/null +++ b/crates/wit-component/tests/components/worlds-with-types/component.wit.print @@ -0,0 +1,11 @@ +package root:component + +world root { + type t = u32 + + record r { + x: t, + } + + export a: func(r: r) -> t +} diff --git a/crates/wit-component/tests/components/worlds-with-types/module.wat b/crates/wit-component/tests/components/worlds-with-types/module.wat new file mode 100644 index 0000000000..c25e92bcb4 --- /dev/null +++ b/crates/wit-component/tests/components/worlds-with-types/module.wat @@ -0,0 +1,3 @@ +(module + (func (export "a") (param i32) (result i32) (i32.const 1)) +) diff --git a/crates/wit-component/tests/components/worlds-with-types/module.wit b/crates/wit-component/tests/components/worlds-with-types/module.wit new file mode 100644 index 0000000000..d00f403e62 --- /dev/null +++ b/crates/wit-component/tests/components/worlds-with-types/module.wit @@ -0,0 +1,10 @@ +package foo:foo; + +world module { + type t = u32; + record r { + x: t + } + + export a: func(r: r) -> t; +} diff --git a/crates/wit-component/tests/interfaces.rs b/crates/wit-component/tests/interfaces.rs new file mode 100644 index 0000000000..9327d60ac2 --- /dev/null +++ b/crates/wit-component/tests/interfaces.rs @@ -0,0 +1,116 @@ +use anyhow::{Context, Result}; +use pretty_assertions::assert_eq; +use std::fs; +use std::path::Path; +use wit_component::WitPrinter; +use wit_parser::{PackageId, Resolve, UnresolvedPackage}; + +/// Tests the encoding of a WIT package as a WebAssembly binary. +/// +/// This test looks in the `interfaces/` directory for test cases. Each test +/// case is a `*.wit` file or a folder which contains `*.wit` files as part of a +/// multi-file package. Each tests `foo.wit` is accompanied with a `foo.wat` for +/// the WebAssembly text format encoding of the package. Additionally each test +/// has a `foo.print.wit` which is the machine-printed version of the WIT +/// document as decoded from the binary encoded interface. +/// +/// Run the test with the environment variable `BLESS` set to update +/// the baseline files. +#[test] +fn interface_encoding() -> Result<()> { + env_logger::init(); + + for entry in fs::read_dir("tests/interfaces")? { + let path = entry?.path(); + let name = match path.file_name().and_then(|s| s.to_str()) { + Some(s) => s, + None => continue, + }; + let is_dir = path.is_dir(); + let is_test = is_dir || name.ends_with(".wit"); + if is_test { + run_test(&path, is_dir).context(format!("failed test `{}`", path.display()))?; + } + } + + Ok(()) +} + +fn run_test(path: &Path, is_dir: bool) -> Result<()> { + println!("running test at {path:?}"); + let mut resolve = Resolve::new(); + let package = if is_dir { + resolve.push_dir(path)?.0 + } else { + resolve.push(UnresolvedPackage::parse_file(path)?)? + }; + + assert_print(&resolve, package, path, is_dir)?; + + let features = wasmparser::WasmFeatures { + component_model: true, + ..Default::default() + }; + + // First convert the WIT package to a binary WebAssembly output, then + // convert that binary wasm to textual wasm, then assert it matches the + // expectation. + let wasm = wit_component::encode(&resolve, package)?; + let wat = wasmprinter::print_bytes(&wasm)?; + assert_output(&path.with_extension("wat"), &wat)?; + wasmparser::Validator::new_with_features(features) + .validate_all(&wasm) + .context("failed to validate wasm output")?; + + // Next decode a fresh WIT package from the WebAssembly generated. Print + // this package's documents and assert they all match the expectations. + let decoded = wit_component::decode(&wasm)?; + let resolve = decoded.resolve(); + + assert_print(resolve, decoded.package(), path, is_dir)?; + + // Finally convert the decoded package to wasm again and make sure it + // matches the prior wasm. + let wasm2 = wit_component::encode(resolve, decoded.package())?; + if wasm != wasm2 { + let wat2 = wasmprinter::print_bytes(&wasm)?; + assert_eq!(wat, wat2, "document did not roundtrip correctly"); + } + + Ok(()) +} + +fn assert_print(resolve: &Resolve, package: PackageId, path: &Path, is_dir: bool) -> Result<()> { + let pkg = &resolve.packages[package]; + let expected = if is_dir { + path.join(format!("{}.wit.print", &pkg.name.name)) + } else { + path.with_extension("wit.print") + }; + let output = WitPrinter::default().print(resolve, package)?; + assert_output(&expected, &output)?; + + UnresolvedPackage::parse("foo.wit".as_ref(), &output) + .context("failed to parse printed output")?; + Ok(()) +} + +fn assert_output(expected: &Path, actual: &str) -> Result<()> { + let actual = actual.replace( + concat!("\"", env!("CARGO_PKG_VERSION"), "\""), + "\"$CARGO_PKG_VERSION\"", + ); + if std::env::var_os("BLESS").is_some() { + fs::write(expected, actual).with_context(|| format!("failed to write {expected:?}"))?; + } else { + assert_eq!( + fs::read_to_string(expected) + .with_context(|| format!("failed to read {expected:?}"))? + .replace("\r\n", "\n"), + actual, + "expectation `{}` did not match actual", + expected.display(), + ); + } + Ok(()) +} diff --git a/crates/wit-component/tests/interfaces/console.wat b/crates/wit-component/tests/interfaces/console.wat new file mode 100644 index 0000000000..6aa6caf4d0 --- /dev/null +++ b/crates/wit-component/tests/interfaces/console.wat @@ -0,0 +1,17 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (func (param "arg" string))) + (export (;0;) "log" (func (type 0))) + ) + ) + (export (;0;) (interface "foo:console/console") (instance (type 0))) + ) + ) + (export (;1;) (interface "foo:console/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/console.wit b/crates/wit-component/tests/interfaces/console.wit new file mode 100644 index 0000000000..4c9ad25283 --- /dev/null +++ b/crates/wit-component/tests/interfaces/console.wit @@ -0,0 +1,5 @@ +package foo:console; + +interface console { + log: func(arg: string); +} diff --git a/crates/wit-component/tests/interfaces/console.wit.print b/crates/wit-component/tests/interfaces/console.wit.print new file mode 100644 index 0000000000..73a5363d56 --- /dev/null +++ b/crates/wit-component/tests/interfaces/console.wit.print @@ -0,0 +1,6 @@ +package foo:console + +interface console { + log: func(arg: string) +} + diff --git a/crates/wit-component/tests/interfaces/diamond-disambiguate.wat b/crates/wit-component/tests/interfaces/diamond-disambiguate.wat new file mode 100644 index 0000000000..c7e8718193 --- /dev/null +++ b/crates/wit-component/tests/interfaces/diamond-disambiguate.wat @@ -0,0 +1,59 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "t1" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:foo/shared1") (instance (type 0))) + (type (;1;) + (instance + (type (;0;) u8) + (export (;1;) "t2" (type (eq 0))) + ) + ) + (export (;1;) (interface "foo:foo/shared2") (instance (type 1))) + (type (;2;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "t1" (type (eq 0))) + ) + ) + (import (interface "foo:foo/shared1") (instance (;0;) (type 0))) + (alias export 0 "t1" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "t1" (type (eq 0))) + ) + ) + (import "foo" (instance (;1;) (type 2))) + (type (;3;) + (instance + (type (;0;) u8) + (export (;1;) "t2" (type (eq 0))) + ) + ) + (import (interface "foo:foo/shared2") (instance (;2;) (type 3))) + (alias export 2 "t2" (type (;4;))) + (type (;5;) + (instance + (alias outer 1 4 (type (;0;))) + (export (;1;) "t2" (type (eq 0))) + ) + ) + (import "bar" (instance (;3;) (type 5))) + ) + ) + (export (;0;) (interface "foo:foo/w1") (component (type 2))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/diamond-disambiguate/foo.wit.print b/crates/wit-component/tests/interfaces/diamond-disambiguate/foo.wit.print new file mode 100644 index 0000000000..b1268c266a --- /dev/null +++ b/crates/wit-component/tests/interfaces/diamond-disambiguate/foo.wit.print @@ -0,0 +1,20 @@ +package foo:foo + +interface shared1 { + type t1 = u8 +} + +interface shared2 { + type t2 = u8 +} + +world w1 { + import shared1 + import foo: interface { + use shared1.{t1} + } + import shared2 + import bar: interface { + use shared2.{t2} + } +} diff --git a/crates/wit-component/tests/interfaces/diamond-disambiguate/join.wit b/crates/wit-component/tests/interfaces/diamond-disambiguate/join.wit new file mode 100644 index 0000000000..aafd3b535a --- /dev/null +++ b/crates/wit-component/tests/interfaces/diamond-disambiguate/join.wit @@ -0,0 +1,10 @@ +package foo:foo; + +world w1 { + import foo: interface { + use shared1.{t1}; + } + import bar: interface { + use shared2.{t2}; + } +} diff --git a/crates/wit-component/tests/interfaces/diamond-disambiguate/shared1.wit b/crates/wit-component/tests/interfaces/diamond-disambiguate/shared1.wit new file mode 100644 index 0000000000..2cc832531b --- /dev/null +++ b/crates/wit-component/tests/interfaces/diamond-disambiguate/shared1.wit @@ -0,0 +1,3 @@ +interface shared1 { + type t1 = u8; +} diff --git a/crates/wit-component/tests/interfaces/diamond-disambiguate/shared2.wit b/crates/wit-component/tests/interfaces/diamond-disambiguate/shared2.wit new file mode 100644 index 0000000000..bd42d792cc --- /dev/null +++ b/crates/wit-component/tests/interfaces/diamond-disambiguate/shared2.wit @@ -0,0 +1,3 @@ +interface shared2 { + type t2 = u8; +} diff --git a/crates/wit-component/tests/interfaces/diamond.wat b/crates/wit-component/tests/interfaces/diamond.wat new file mode 100644 index 0000000000..ec37918830 --- /dev/null +++ b/crates/wit-component/tests/interfaces/diamond.wat @@ -0,0 +1,91 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (enum "a")) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:foo/shared-items") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (enum "a")) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (import (interface "foo:foo/shared-items") (instance (;0;) (type 0))) + (alias export 0 "the-enum" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (import "foo" (instance (;1;) (type 2))) + (type (;3;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (import "bar" (instance (;2;) (type 3))) + ) + ) + (export (;0;) (interface "foo:foo/w1") (component (type 1))) + (type (;2;) + (component + (type (;0;) + (instance + (type (;0;) (enum "a")) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (import (interface "foo:foo/shared-items") (instance (;0;) (type 0))) + (alias export 0 "the-enum" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (import "foo" (instance (;1;) (type 2))) + (type (;3;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (export (;2;) "bar" (instance (type 3))) + ) + ) + (export (;1;) (interface "foo:foo/w2") (component (type 2))) + (type (;3;) + (component + (type (;0;) + (instance + (type (;0;) (enum "a")) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (import (interface "foo:foo/shared-items") (instance (;0;) (type 0))) + (alias export 0 "the-enum" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-enum" (type (eq 0))) + ) + ) + (export (;1;) "bar" (instance (type 2))) + ) + ) + (export (;2;) (interface "foo:foo/w3") (component (type 3))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/diamond.wit b/crates/wit-component/tests/interfaces/diamond.wit new file mode 100644 index 0000000000..ffbc9c767a --- /dev/null +++ b/crates/wit-component/tests/interfaces/diamond.wit @@ -0,0 +1,31 @@ +package foo:foo; + +interface shared-items { + enum the-enum { + a + } +} + +world w1 { + import foo: interface { + use shared-items.{the-enum}; + } + import bar: interface { + use shared-items.{the-enum}; + } +} + +world w2 { + import foo: interface { + use shared-items.{the-enum}; + } + export bar: interface { + use shared-items.{the-enum}; + } +} + +world w3 { + export bar: interface { + use shared-items.{the-enum}; + } +} diff --git a/crates/wit-component/tests/interfaces/diamond.wit.print b/crates/wit-component/tests/interfaces/diamond.wit.print new file mode 100644 index 0000000000..f09cb0e58d --- /dev/null +++ b/crates/wit-component/tests/interfaces/diamond.wit.print @@ -0,0 +1,34 @@ +package foo:foo + +interface shared-items { + enum the-enum { + a, + } +} + +world w1 { + import shared-items + import foo: interface { + use shared-items.{the-enum} + } + import bar: interface { + use shared-items.{the-enum} + } +} +world w2 { + import shared-items + import foo: interface { + use shared-items.{the-enum} + } + + export bar: interface { + use shared-items.{the-enum} + } +} +world w3 { + import shared-items + + export bar: interface { + use shared-items.{the-enum} + } +} diff --git a/crates/wit-component/tests/interfaces/doc-comments.wat b/crates/wit-component/tests/interfaces/doc-comments.wat new file mode 100644 index 0000000000..7f3cd0337b --- /dev/null +++ b/crates/wit-component/tests/interfaces/doc-comments.wat @@ -0,0 +1,62 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + (type (;2;) (record (field "f1" u8) (field "f2" u8))) + (export (;3;) "r" (type (eq 2))) + (type (;4;) (flags "f1" "f2")) + (export (;5;) "fl" (type (eq 4))) + (type (;6;) (variant (case "c1" u8) (case "c2"))) + (export (;7;) "v" (type (eq 6))) + (type (;8;) (enum "c1" "c2")) + (export (;9;) "e" (type (eq 8))) + (export (;10;) "res" (type (sub resource))) + (type (;11;) (own 10)) + (type (;12;) (func (result 11))) + (export (;0;) "[constructor]res" (func (type 12))) + (type (;13;) (borrow 10)) + (type (;14;) (func (param "self" 13))) + (export (;1;) "[method]res.m" (func (type 14))) + (type (;15;) (func)) + (export (;2;) "[static]res.s" (func (type 15))) + (export (;3;) "f" (func (type 15))) + ) + ) + (export (;0;) (interface "foo:foo/coverage-iface") (instance (type 0))) + (type (;1;) + (instance + (type (;0;) (func)) + (export (;0;) "multiple-lines-split" (func (type 0))) + (export (;1;) "mixed-forms" (func (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/other-comment-forms") (instance (type 1))) + (type (;2;) + (component + (type (;0;) u32) + (import "t" (type (;1;) (eq 0))) + (type (;2;) (func)) + (import "imp" (func (;0;) (type 2))) + (export (;1;) "exp" (func (type 2))) + (type (;3;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + (type (;2;) (func)) + (export (;0;) "f" (func (type 2))) + ) + ) + (export (;0;) "i" (instance (type 3))) + ) + ) + (export (;0;) (interface "foo:foo/coverage-world") (component (type 2))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/doc-comments/foo.wit b/crates/wit-component/tests/interfaces/doc-comments/foo.wit new file mode 100644 index 0000000000..0d7a6f4246 --- /dev/null +++ b/crates/wit-component/tests/interfaces/doc-comments/foo.wit @@ -0,0 +1,79 @@ +/// package docs; +package foo:foo; + +/// interface docs +interface coverage-iface { + /// basic typedef docs + type t = u32; + + /// record typedef docs + record r { + /// record field docs + f1: u8, + f2: u8, + } + + flags fl { + /// flag docs + f1, + f2, + } + + variant v { + /// variant case docs + c1(u8), + c2, + } + + enum e { + /// enum case docs + c1, + c2, + } + + resource res { + /// constructor docs + constructor(); + /// method docs + m: func(); + /// static func docs + s: static func(); + } + + /// interface func docs + f: func(); +} + +/// world docs +world coverage-world { + /// world func import docs + import imp: func(); + + /// world typedef docs + type t = u32; + + /// world inline interface docs + export i: interface { + /// inline interface typedef docs + type t = u32; + + /// inline interface func docs + f: func(); + } + /// world func export docs + export exp: func(); +} + +/** other comment forms + multi-line block */ +interface other-comment-forms { + /// one doc line + // non-doc in the middle + /// another doc line + multiple-lines-split: func(); + + /// mixed forms; line doc + /** plus block doc + multi-line */ + mixed-forms: func(); +} diff --git a/crates/wit-component/tests/interfaces/doc-comments/foo.wit.print b/crates/wit-component/tests/interfaces/doc-comments/foo.wit.print new file mode 100644 index 0000000000..03708a0d5b --- /dev/null +++ b/crates/wit-component/tests/interfaces/doc-comments/foo.wit.print @@ -0,0 +1,78 @@ +/// package docs; +package foo:foo + +/// interface docs +interface coverage-iface { + /// basic typedef docs + type t = u32 + + /// record typedef docs + record r { + /// record field docs + f1: u8, + f2: u8, + } + + flags fl { + /// flag docs + f1, + f2, + } + + variant v { + /// variant case docs + c1(u8), + c2, + } + + enum e { + /// enum case docs + c1, + c2, + } + + resource res { + /// constructor docs + constructor() + /// method docs + m: func() + /// static func docs + s: static func() + } + + /// interface func docs + f: func() +} + +/// other comment forms +/// multi-line block +interface other-comment-forms { + /// one doc line + /// another doc line + multiple-lines-split: func() + + /// mixed forms; line doc + /// plus block doc + /// multi-line + mixed-forms: func() +} + +/// world docs +world coverage-world { + /// world func import docs + import imp: func() + + /// world typedef docs + type t = u32 + + /// world func export docs + export exp: func() + /// world inline interface docs + export i: interface { + /// inline interface typedef docs + type t = u32 + + /// inline interface func docs + f: func() + } +} diff --git a/crates/wit-component/tests/interfaces/empty.wat b/crates/wit-component/tests/interfaces/empty.wat new file mode 100644 index 0000000000..02906cca8c --- /dev/null +++ b/crates/wit-component/tests/interfaces/empty.wat @@ -0,0 +1,39 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance) + ) + (export (;0;) (interface "foo:empty/empty") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance) + ) + (import (interface "foo:empty/empty") (instance (;0;) (type 0))) + (type (;1;) + (instance) + ) + (import "empty" (instance (;1;) (type 1))) + (type (;2;) + (instance) + ) + (export (;2;) (interface "foo:empty/empty") (instance (type 2))) + (type (;3;) + (instance) + ) + (export (;3;) "empty2" (instance (type 3))) + ) + ) + (export (;0;) (interface "foo:empty/empty-world") (component (type 1))) + (type (;2;) + (component) + ) + (export (;1;) (interface "foo:empty/actually-empty-world") (component (type 2))) + ) + ) + (export (;1;) (interface "foo:empty/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/empty.wit b/crates/wit-component/tests/interfaces/empty.wit new file mode 100644 index 0000000000..0164214b63 --- /dev/null +++ b/crates/wit-component/tests/interfaces/empty.wit @@ -0,0 +1,12 @@ +package foo:empty; + +interface empty {} + +world empty-world { + import empty; + import empty: interface {} + export empty; + export empty2: interface {} +} + +world actually-empty-world {} diff --git a/crates/wit-component/tests/interfaces/empty.wit.print b/crates/wit-component/tests/interfaces/empty.wit.print new file mode 100644 index 0000000000..4f16a4b9f0 --- /dev/null +++ b/crates/wit-component/tests/interfaces/empty.wit.print @@ -0,0 +1,16 @@ +package foo:empty + +interface empty { +} + +world empty-world { + import empty + import empty: interface { + } + + export empty + export empty2: interface { + } +} +world actually-empty-world { +} diff --git a/crates/wit-component/tests/interfaces/export-other-packages-interface.wat b/crates/wit-component/tests/interfaces/export-other-packages-interface.wat new file mode 100644 index 0000000000..e9569e89b3 --- /dev/null +++ b/crates/wit-component/tests/interfaces/export-other-packages-interface.wat @@ -0,0 +1,22 @@ +(component + (type (;0;) + (component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "t" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:the-dep/the-interface") (instance (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (component (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/export-other-packages-interface/deps/the-dep/the-doc.wit b/crates/wit-component/tests/interfaces/export-other-packages-interface/deps/the-dep/the-doc.wit new file mode 100644 index 0000000000..adc2c4c39f --- /dev/null +++ b/crates/wit-component/tests/interfaces/export-other-packages-interface/deps/the-dep/the-doc.wit @@ -0,0 +1,9 @@ +package foo:the-dep; + +interface the-interface { + type t = u8; +} + +interface unused-interface { + type u = u32; +} diff --git a/crates/wit-component/tests/interfaces/export-other-packages-interface/foo.wit b/crates/wit-component/tests/interfaces/export-other-packages-interface/foo.wit new file mode 100644 index 0000000000..13801e0945 --- /dev/null +++ b/crates/wit-component/tests/interfaces/export-other-packages-interface/foo.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo { + export foo:the-dep/the-interface; +} diff --git a/crates/wit-component/tests/interfaces/export-other-packages-interface/foo.wit.print b/crates/wit-component/tests/interfaces/export-other-packages-interface/foo.wit.print new file mode 100644 index 0000000000..63721d405b --- /dev/null +++ b/crates/wit-component/tests/interfaces/export-other-packages-interface/foo.wit.print @@ -0,0 +1,5 @@ +package foo:foo + +world foo { + export foo:the-dep/the-interface +} diff --git a/crates/wit-component/tests/interfaces/exports.wat b/crates/wit-component/tests/interfaces/exports.wat new file mode 100644 index 0000000000..3f2bd04011 --- /dev/null +++ b/crates/wit-component/tests/interfaces/exports.wat @@ -0,0 +1,33 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "a" u32))) + (export (;1;) "my-struct" (type (eq 0))) + (type (;2;) (func (param "a" 1) (result string))) + (export (;0;) "my-function" (func (type 2))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "a" u32))) + (export (;1;) "my-struct" (type (eq 0))) + (type (;2;) (func (param "a" 1) (result string))) + (export (;0;) "my-function" (func (type 2))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/export-foo") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/exports.wit b/crates/wit-component/tests/interfaces/exports.wit new file mode 100644 index 0000000000..49d73b6f10 --- /dev/null +++ b/crates/wit-component/tests/interfaces/exports.wit @@ -0,0 +1,13 @@ +package foo:foo; + +interface foo { + record my-struct { + a: u32, + } + + my-function: func(a: my-struct) -> string; +} + +world export-foo { + export foo; +} diff --git a/crates/wit-component/tests/interfaces/exports.wit.print b/crates/wit-component/tests/interfaces/exports.wit.print new file mode 100644 index 0000000000..542abad8a9 --- /dev/null +++ b/crates/wit-component/tests/interfaces/exports.wit.print @@ -0,0 +1,13 @@ +package foo:foo + +interface foo { + record my-struct { + a: u32, + } + + my-function: func(a: my-struct) -> string +} + +world export-foo { + export foo +} diff --git a/crates/wit-component/tests/interfaces/flags.wat b/crates/wit-component/tests/interfaces/flags.wat new file mode 100644 index 0000000000..1c07f49055 --- /dev/null +++ b/crates/wit-component/tests/interfaces/flags.wat @@ -0,0 +1,81 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (flags "b0")) + (export (;1;) "flag1" (type (eq 0))) + (type (;2;) (flags "b0" "b1")) + (export (;3;) "flag2" (type (eq 2))) + (type (;4;) (flags "b0" "b1" "b2" "b3")) + (export (;5;) "flag4" (type (eq 4))) + (type (;6;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7")) + (export (;7;) "flag8" (type (eq 6))) + (type (;8;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15")) + (export (;9;) "flag16" (type (eq 8))) + (type (;10;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15" "b16" "b17" "b18" "b19" "b20" "b21" "b22" "b23" "b24" "b25" "b26" "b27" "b28" "b29" "b30" "b31")) + (export (;11;) "flag32" (type (eq 10))) + (type (;12;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15" "b16" "b17" "b18" "b19" "b20" "b21" "b22" "b23" "b24" "b25" "b26" "b27" "b28" "b29" "b30" "b31" "b32" "b33" "b34" "b35" "b36" "b37" "b38" "b39" "b40" "b41" "b42" "b43" "b44" "b45" "b46" "b47" "b48" "b49" "b50" "b51" "b52" "b53" "b54" "b55" "b56" "b57" "b58" "b59" "b60" "b61" "b62" "b63")) + (export (;13;) "flag64" (type (eq 12))) + (type (;14;) (func (param "x" 1) (result 1))) + (export (;0;) "roundtrip-flag1" (func (type 14))) + (type (;15;) (func (param "x" 3) (result 3))) + (export (;1;) "roundtrip-flag2" (func (type 15))) + (type (;16;) (func (param "x" 5) (result 5))) + (export (;2;) "roundtrip-flag4" (func (type 16))) + (type (;17;) (func (param "x" 7) (result 7))) + (export (;3;) "roundtrip-flag8" (func (type 17))) + (type (;18;) (func (param "x" 9) (result 9))) + (export (;4;) "roundtrip-flag16" (func (type 18))) + (type (;19;) (func (param "x" 11) (result 11))) + (export (;5;) "roundtrip-flag32" (func (type 19))) + (type (;20;) (func (param "x" 13) (result 13))) + (export (;6;) "roundtrip-flag64" (func (type 20))) + ) + ) + (export (;0;) (interface "foo:flags/imports") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (flags "b0")) + (export (;1;) "flag1" (type (eq 0))) + (type (;2;) (flags "b0" "b1")) + (export (;3;) "flag2" (type (eq 2))) + (type (;4;) (flags "b0" "b1" "b2" "b3")) + (export (;5;) "flag4" (type (eq 4))) + (type (;6;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7")) + (export (;7;) "flag8" (type (eq 6))) + (type (;8;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15")) + (export (;9;) "flag16" (type (eq 8))) + (type (;10;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15" "b16" "b17" "b18" "b19" "b20" "b21" "b22" "b23" "b24" "b25" "b26" "b27" "b28" "b29" "b30" "b31")) + (export (;11;) "flag32" (type (eq 10))) + (type (;12;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15" "b16" "b17" "b18" "b19" "b20" "b21" "b22" "b23" "b24" "b25" "b26" "b27" "b28" "b29" "b30" "b31" "b32" "b33" "b34" "b35" "b36" "b37" "b38" "b39" "b40" "b41" "b42" "b43" "b44" "b45" "b46" "b47" "b48" "b49" "b50" "b51" "b52" "b53" "b54" "b55" "b56" "b57" "b58" "b59" "b60" "b61" "b62" "b63")) + (export (;13;) "flag64" (type (eq 12))) + (type (;14;) (func (param "x" 1) (result 1))) + (export (;0;) "roundtrip-flag1" (func (type 14))) + (type (;15;) (func (param "x" 3) (result 3))) + (export (;1;) "roundtrip-flag2" (func (type 15))) + (type (;16;) (func (param "x" 5) (result 5))) + (export (;2;) "roundtrip-flag4" (func (type 16))) + (type (;17;) (func (param "x" 7) (result 7))) + (export (;3;) "roundtrip-flag8" (func (type 17))) + (type (;18;) (func (param "x" 9) (result 9))) + (export (;4;) "roundtrip-flag16" (func (type 18))) + (type (;19;) (func (param "x" 11) (result 11))) + (export (;5;) "roundtrip-flag32" (func (type 19))) + (type (;20;) (func (param "x" 13) (result 13))) + (export (;6;) "roundtrip-flag64" (func (type 20))) + ) + ) + (import (interface "foo:flags/imports") (instance (;0;) (type 0))) + ) + ) + (export (;0;) (interface "foo:flags/flags-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:flags/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/flags.wit b/crates/wit-component/tests/interfaces/flags.wit new file mode 100644 index 0000000000..9542f96e08 --- /dev/null +++ b/crates/wit-component/tests/interfaces/flags.wit @@ -0,0 +1,169 @@ +package foo:%flags; + +interface imports { + flags flag1 { + b0, + } + + flags flag2 { + b0, + b1, + } + + flags flag4 { + b0, + b1, + b2, + b3, + } + + flags flag8 { + b0, + b1, + b2, + b3, + b4, + b5, + b6, + b7, + } + + flags flag16 { + b0, + b1, + b2, + b3, + b4, + b5, + b6, + b7, + b8, + b9, + b10, + b11, + b12, + b13, + b14, + b15, + } + + flags flag32 { + b0, + b1, + b2, + b3, + b4, + b5, + b6, + b7, + b8, + b9, + b10, + b11, + b12, + b13, + b14, + b15, + b16, + b17, + b18, + b19, + b20, + b21, + b22, + b23, + b24, + b25, + b26, + b27, + b28, + b29, + b30, + b31, + } + + flags flag64 { + b0, + b1, + b2, + b3, + b4, + b5, + b6, + b7, + b8, + b9, + b10, + b11, + b12, + b13, + b14, + b15, + b16, + b17, + b18, + b19, + b20, + b21, + b22, + b23, + b24, + b25, + b26, + b27, + b28, + b29, + b30, + b31, + b32, + b33, + b34, + b35, + b36, + b37, + b38, + b39, + b40, + b41, + b42, + b43, + b44, + b45, + b46, + b47, + b48, + b49, + b50, + b51, + b52, + b53, + b54, + b55, + b56, + b57, + b58, + b59, + b60, + b61, + b62, + b63, + } + + roundtrip-flag1: func(x: flag1) -> flag1; + + roundtrip-flag2: func(x: flag2) -> flag2; + + roundtrip-flag4: func(x: flag4) -> flag4; + + roundtrip-flag8: func(x: flag8) -> flag8; + + roundtrip-flag16: func(x: flag16) -> flag16; + + roundtrip-flag32: func(x: flag32) -> flag32; + + roundtrip-flag64: func(x: flag64) -> flag64; +} + +world flags-world { + import imports; +} diff --git a/crates/wit-component/tests/interfaces/flags.wit.print b/crates/wit-component/tests/interfaces/flags.wit.print new file mode 100644 index 0000000000..6f23fdd3dc --- /dev/null +++ b/crates/wit-component/tests/interfaces/flags.wit.print @@ -0,0 +1,169 @@ +package foo:%flags + +interface imports { + flags flag1 { + b0, + } + + flags flag2 { + b0, + b1, + } + + flags flag4 { + b0, + b1, + b2, + b3, + } + + flags flag8 { + b0, + b1, + b2, + b3, + b4, + b5, + b6, + b7, + } + + flags flag16 { + b0, + b1, + b2, + b3, + b4, + b5, + b6, + b7, + b8, + b9, + b10, + b11, + b12, + b13, + b14, + b15, + } + + flags flag32 { + b0, + b1, + b2, + b3, + b4, + b5, + b6, + b7, + b8, + b9, + b10, + b11, + b12, + b13, + b14, + b15, + b16, + b17, + b18, + b19, + b20, + b21, + b22, + b23, + b24, + b25, + b26, + b27, + b28, + b29, + b30, + b31, + } + + flags flag64 { + b0, + b1, + b2, + b3, + b4, + b5, + b6, + b7, + b8, + b9, + b10, + b11, + b12, + b13, + b14, + b15, + b16, + b17, + b18, + b19, + b20, + b21, + b22, + b23, + b24, + b25, + b26, + b27, + b28, + b29, + b30, + b31, + b32, + b33, + b34, + b35, + b36, + b37, + b38, + b39, + b40, + b41, + b42, + b43, + b44, + b45, + b46, + b47, + b48, + b49, + b50, + b51, + b52, + b53, + b54, + b55, + b56, + b57, + b58, + b59, + b60, + b61, + b62, + b63, + } + + roundtrip-flag1: func(x: flag1) -> flag1 + + roundtrip-flag2: func(x: flag2) -> flag2 + + roundtrip-flag4: func(x: flag4) -> flag4 + + roundtrip-flag8: func(x: flag8) -> flag8 + + roundtrip-flag16: func(x: flag16) -> flag16 + + roundtrip-flag32: func(x: flag32) -> flag32 + + roundtrip-flag64: func(x: flag64) -> flag64 +} + +world flags-world { + import imports +} diff --git a/crates/wit-component/tests/interfaces/floats.wat b/crates/wit-component/tests/interfaces/floats.wat new file mode 100644 index 0000000000..e974ebe846 --- /dev/null +++ b/crates/wit-component/tests/interfaces/floats.wat @@ -0,0 +1,41 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (func (param "x" float32))) + (export (;0;) "float32-param" (func (type 0))) + (type (;1;) (func (param "x" float64))) + (export (;1;) "float64-param" (func (type 1))) + (type (;2;) (func (result float32))) + (export (;2;) "float32-result" (func (type 2))) + (type (;3;) (func (result float64))) + (export (;3;) "float64-result" (func (type 3))) + ) + ) + (export (;0;) (interface "foo:floats/floats") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (func (param "x" float32))) + (export (;0;) "float32-param" (func (type 0))) + (type (;1;) (func (param "x" float64))) + (export (;1;) "float64-param" (func (type 1))) + (type (;2;) (func (result float32))) + (export (;2;) "float32-result" (func (type 2))) + (type (;3;) (func (result float64))) + (export (;3;) "float64-result" (func (type 3))) + ) + ) + (import (interface "foo:floats/floats") (instance (;0;) (type 0))) + ) + ) + (export (;0;) (interface "foo:floats/floats-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:floats/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/floats.wit b/crates/wit-component/tests/interfaces/floats.wit new file mode 100644 index 0000000000..fa75f8b593 --- /dev/null +++ b/crates/wit-component/tests/interfaces/floats.wit @@ -0,0 +1,12 @@ +package foo:floats; + +interface floats { + float32-param: func(x: float32); + float64-param: func(x: float64); + float32-result: func() -> float32; + float64-result: func() -> float64; +} + +world floats-world { + import floats; +} diff --git a/crates/wit-component/tests/interfaces/floats.wit.print b/crates/wit-component/tests/interfaces/floats.wit.print new file mode 100644 index 0000000000..b770c37e5e --- /dev/null +++ b/crates/wit-component/tests/interfaces/floats.wit.print @@ -0,0 +1,15 @@ +package foo:floats + +interface floats { + float32-param: func(x: float32) + + float64-param: func(x: float64) + + float32-result: func() -> float32 + + float64-result: func() -> float64 +} + +world floats-world { + import floats +} diff --git a/crates/wit-component/tests/interfaces/foreign-use-chain.wat b/crates/wit-component/tests/interfaces/foreign-use-chain.wat new file mode 100644 index 0000000000..c55bb5a1f7 --- /dev/null +++ b/crates/wit-component/tests/interfaces/foreign-use-chain.wat @@ -0,0 +1,30 @@ +(component + (type (;0;) + (component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "the-type" (type (eq 0))) + ) + ) + (import (interface "foo:bar/the-interface") (instance (;0;) (type 0))) + (alias export 0 "the-type" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "bar" (type (eq 0))) + ) + ) + (import (interface "foo:bar/bar") (instance (;1;) (type 2))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (component (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/foreign-use-chain/deps/bar/bar.wit b/crates/wit-component/tests/interfaces/foreign-use-chain/deps/bar/bar.wit new file mode 100644 index 0000000000..a6b7de13ee --- /dev/null +++ b/crates/wit-component/tests/interfaces/foreign-use-chain/deps/bar/bar.wit @@ -0,0 +1,9 @@ +package foo:bar; + +interface bar { + use the-interface.{the-type as bar}; +} + +interface the-interface { + type the-type = u8; +} diff --git a/crates/wit-component/tests/interfaces/foreign-use-chain/foo.wit b/crates/wit-component/tests/interfaces/foreign-use-chain/foo.wit new file mode 100644 index 0000000000..c7b87f7bd2 --- /dev/null +++ b/crates/wit-component/tests/interfaces/foreign-use-chain/foo.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo { + import foo:bar/bar; +} diff --git a/crates/wit-component/tests/interfaces/foreign-use-chain/foo.wit.print b/crates/wit-component/tests/interfaces/foreign-use-chain/foo.wit.print new file mode 100644 index 0000000000..c05357cdf3 --- /dev/null +++ b/crates/wit-component/tests/interfaces/foreign-use-chain/foo.wit.print @@ -0,0 +1,6 @@ +package foo:foo + +world foo { + import foo:bar/the-interface + import foo:bar/bar +} diff --git a/crates/wit-component/tests/interfaces/import-and-export.wat b/crates/wit-component/tests/interfaces/import-and-export.wat new file mode 100644 index 0000000000..627281eec3 --- /dev/null +++ b/crates/wit-component/tests/interfaces/import-and-export.wat @@ -0,0 +1,43 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "foo" (func (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + (type (;1;) + (instance + (type (;0;) (func)) + (export (;0;) "bar" (func (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/bar") (instance (type 1))) + (type (;2;) + (component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "foo" (func (type 0))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (func)) + (export (;0;) "bar" (func (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/bar") (instance (type 1))) + ) + ) + (export (;0;) (interface "foo:foo/import-and-export") (component (type 2))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/import-and-export.wit b/crates/wit-component/tests/interfaces/import-and-export.wit new file mode 100644 index 0000000000..3d84154abb --- /dev/null +++ b/crates/wit-component/tests/interfaces/import-and-export.wit @@ -0,0 +1,14 @@ +package foo:foo; + +interface foo { + foo: func(); +} + +interface bar { + bar: func(); +} + +world import-and-export { + import foo; + export bar; +} diff --git a/crates/wit-component/tests/interfaces/import-and-export.wit.print b/crates/wit-component/tests/interfaces/import-and-export.wit.print new file mode 100644 index 0000000000..4dbc26b837 --- /dev/null +++ b/crates/wit-component/tests/interfaces/import-and-export.wit.print @@ -0,0 +1,15 @@ +package foo:foo + +interface foo { + foo: func() +} + +interface bar { + bar: func() +} + +world import-and-export { + import foo + + export bar +} diff --git a/crates/wit-component/tests/interfaces/integers.wat b/crates/wit-component/tests/interfaces/integers.wat new file mode 100644 index 0000000000..a4baed8995 --- /dev/null +++ b/crates/wit-component/tests/interfaces/integers.wat @@ -0,0 +1,103 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (func (param "x" u8))) + (export (;0;) "a1" (func (type 0))) + (type (;1;) (func (param "x" s8))) + (export (;1;) "a2" (func (type 1))) + (type (;2;) (func (param "x" u16))) + (export (;2;) "a3" (func (type 2))) + (type (;3;) (func (param "x" s16))) + (export (;3;) "a4" (func (type 3))) + (type (;4;) (func (param "x" u32))) + (export (;4;) "a5" (func (type 4))) + (type (;5;) (func (param "x" s32))) + (export (;5;) "a6" (func (type 5))) + (type (;6;) (func (param "x" u64))) + (export (;6;) "a7" (func (type 6))) + (type (;7;) (func (param "x" s64))) + (export (;7;) "a8" (func (type 7))) + (type (;8;) (func (param "p1" u8) (param "p2" s8) (param "p3" u16) (param "p4" s16) (param "p5" u32) (param "p6" s32) (param "p7" u64) (param "p8" s64))) + (export (;8;) "a9" (func (type 8))) + (type (;9;) (func (result u8))) + (export (;9;) "r1" (func (type 9))) + (type (;10;) (func (result s8))) + (export (;10;) "r2" (func (type 10))) + (type (;11;) (func (result u16))) + (export (;11;) "r3" (func (type 11))) + (type (;12;) (func (result s16))) + (export (;12;) "r4" (func (type 12))) + (type (;13;) (func (result u32))) + (export (;13;) "r5" (func (type 13))) + (type (;14;) (func (result s32))) + (export (;14;) "r6" (func (type 14))) + (type (;15;) (func (result u64))) + (export (;15;) "r7" (func (type 15))) + (type (;16;) (func (result s64))) + (export (;16;) "r8" (func (type 16))) + (type (;17;) (tuple s64 u8)) + (type (;18;) (func (result 17))) + (export (;17;) "pair-ret" (func (type 18))) + (type (;19;) (func (result "a" s64) (result "b" u8))) + (export (;18;) "multi-ret" (func (type 19))) + ) + ) + (export (;0;) (interface "foo:foo/integers") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (func (param "x" u8))) + (export (;0;) "a1" (func (type 0))) + (type (;1;) (func (param "x" s8))) + (export (;1;) "a2" (func (type 1))) + (type (;2;) (func (param "x" u16))) + (export (;2;) "a3" (func (type 2))) + (type (;3;) (func (param "x" s16))) + (export (;3;) "a4" (func (type 3))) + (type (;4;) (func (param "x" u32))) + (export (;4;) "a5" (func (type 4))) + (type (;5;) (func (param "x" s32))) + (export (;5;) "a6" (func (type 5))) + (type (;6;) (func (param "x" u64))) + (export (;6;) "a7" (func (type 6))) + (type (;7;) (func (param "x" s64))) + (export (;7;) "a8" (func (type 7))) + (type (;8;) (func (param "p1" u8) (param "p2" s8) (param "p3" u16) (param "p4" s16) (param "p5" u32) (param "p6" s32) (param "p7" u64) (param "p8" s64))) + (export (;8;) "a9" (func (type 8))) + (type (;9;) (func (result u8))) + (export (;9;) "r1" (func (type 9))) + (type (;10;) (func (result s8))) + (export (;10;) "r2" (func (type 10))) + (type (;11;) (func (result u16))) + (export (;11;) "r3" (func (type 11))) + (type (;12;) (func (result s16))) + (export (;12;) "r4" (func (type 12))) + (type (;13;) (func (result u32))) + (export (;13;) "r5" (func (type 13))) + (type (;14;) (func (result s32))) + (export (;14;) "r6" (func (type 14))) + (type (;15;) (func (result u64))) + (export (;15;) "r7" (func (type 15))) + (type (;16;) (func (result s64))) + (export (;16;) "r8" (func (type 16))) + (type (;17;) (tuple s64 u8)) + (type (;18;) (func (result 17))) + (export (;17;) "pair-ret" (func (type 18))) + (type (;19;) (func (result "a" s64) (result "b" u8))) + (export (;18;) "multi-ret" (func (type 19))) + ) + ) + (import (interface "foo:foo/integers") (instance (;0;) (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/integers-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/integers.wit b/crates/wit-component/tests/interfaces/integers.wit new file mode 100644 index 0000000000..ae1cb7c2cd --- /dev/null +++ b/crates/wit-component/tests/interfaces/integers.wit @@ -0,0 +1,27 @@ +package foo:foo; + +interface integers { + a1: func(x: u8); + a2: func(x: s8); + a3: func(x: u16); + a4: func(x: s16); + a5: func(x: u32); + a6: func(x: s32); + a7: func(x: u64); + a8: func(x: s64); + a9: func(p1: u8, p2: s8, p3: u16, p4: s16, p5: u32, p6: s32, p7: u64, p8: s64); + r1: func() -> u8; + r2: func() -> s8; + r3: func() -> u16; + r4: func() -> s16; + r5: func() -> u32; + r6: func() -> s32; + r7: func() -> u64; + r8: func() -> s64; + pair-ret: func() -> tuple; + multi-ret: func() -> (a: s64, b: u8); +} + +world integers-world { + import integers; +} diff --git a/crates/wit-component/tests/interfaces/integers.wit.print b/crates/wit-component/tests/interfaces/integers.wit.print new file mode 100644 index 0000000000..d529056c3c --- /dev/null +++ b/crates/wit-component/tests/interfaces/integers.wit.print @@ -0,0 +1,45 @@ +package foo:foo + +interface integers { + a1: func(x: u8) + + a2: func(x: s8) + + a3: func(x: u16) + + a4: func(x: s16) + + a5: func(x: u32) + + a6: func(x: s32) + + a7: func(x: u64) + + a8: func(x: s64) + + a9: func(p1: u8, p2: s8, p3: u16, p4: s16, p5: u32, p6: s32, p7: u64, p8: s64) + + r1: func() -> u8 + + r2: func() -> s8 + + r3: func() -> u16 + + r4: func() -> s16 + + r5: func() -> u32 + + r6: func() -> s32 + + r7: func() -> u64 + + r8: func() -> s64 + + pair-ret: func() -> tuple + + multi-ret: func() -> (a: s64, b: u8) +} + +world integers-world { + import integers +} diff --git a/crates/wit-component/tests/interfaces/lists.wat b/crates/wit-component/tests/interfaces/lists.wat new file mode 100644 index 0000000000..21940bb27b --- /dev/null +++ b/crates/wit-component/tests/interfaces/lists.wat @@ -0,0 +1,205 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (record (field "a1" u32) (field "a2" u64) (field "a3" s32) (field "a4" s64) (field "b" string) (field "c" 0))) + (export (;2;) "other-record" (type (eq 1))) + (type (;3;) (record (field "x" string) (field "y" 2) (field "c1" u32) (field "c2" u64) (field "c3" s32) (field "c4" s64))) + (export (;4;) "some-record" (type (eq 3))) + (type (;5;) (variant (case "a") (case "b" u32) (case "c" string))) + (export (;6;) "other-variant" (type (eq 5))) + (type (;7;) (list 6)) + (type (;8;) (variant (case "a" string) (case "b") (case "c" u32) (case "d" 7))) + (export (;9;) "some-variant" (type (eq 8))) + (type (;10;) (tuple string u8 s8 u16 s16 u32 s32 u64 s64 float32 float64 char)) + (type (;11;) (list 10)) + (export (;12;) "load-store-all-sizes" (type (eq 11))) + (type (;13;) (func (param "x" 0))) + (export (;0;) "list-u8-param" (func (type 13))) + (type (;14;) (list u16)) + (type (;15;) (func (param "x" 14))) + (export (;1;) "list-u16-param" (func (type 15))) + (type (;16;) (list u32)) + (type (;17;) (func (param "x" 16))) + (export (;2;) "list-u32-param" (func (type 17))) + (type (;18;) (list u64)) + (type (;19;) (func (param "x" 18))) + (export (;3;) "list-u64-param" (func (type 19))) + (type (;20;) (list s8)) + (type (;21;) (func (param "x" 20))) + (export (;4;) "list-s8-param" (func (type 21))) + (type (;22;) (list s16)) + (type (;23;) (func (param "x" 22))) + (export (;5;) "list-s16-param" (func (type 23))) + (type (;24;) (list s32)) + (type (;25;) (func (param "x" 24))) + (export (;6;) "list-s32-param" (func (type 25))) + (type (;26;) (list s64)) + (type (;27;) (func (param "x" 26))) + (export (;7;) "list-s64-param" (func (type 27))) + (type (;28;) (list float32)) + (type (;29;) (func (param "x" 28))) + (export (;8;) "list-float32-param" (func (type 29))) + (type (;30;) (list float64)) + (type (;31;) (func (param "x" 30))) + (export (;9;) "list-float64-param" (func (type 31))) + (type (;32;) (func (result 0))) + (export (;10;) "list-u8-ret" (func (type 32))) + (type (;33;) (func (result 14))) + (export (;11;) "list-u16-ret" (func (type 33))) + (type (;34;) (func (result 16))) + (export (;12;) "list-u32-ret" (func (type 34))) + (type (;35;) (func (result 18))) + (export (;13;) "list-u64-ret" (func (type 35))) + (type (;36;) (func (result 20))) + (export (;14;) "list-s8-ret" (func (type 36))) + (type (;37;) (func (result 22))) + (export (;15;) "list-s16-ret" (func (type 37))) + (type (;38;) (func (result 24))) + (export (;16;) "list-s32-ret" (func (type 38))) + (type (;39;) (func (result 26))) + (export (;17;) "list-s64-ret" (func (type 39))) + (type (;40;) (func (result 28))) + (export (;18;) "list-float32-ret" (func (type 40))) + (type (;41;) (func (result 30))) + (export (;19;) "list-float64-ret" (func (type 41))) + (type (;42;) (tuple u8 s8)) + (type (;43;) (list 42)) + (type (;44;) (tuple s64 u32)) + (type (;45;) (list 44)) + (type (;46;) (func (param "x" 43) (result 45))) + (export (;20;) "tuple-list" (func (type 46))) + (type (;47;) (list string)) + (type (;48;) (func (param "a" 47))) + (export (;21;) "string-list-arg" (func (type 48))) + (type (;49;) (func (result 47))) + (export (;22;) "string-list-ret" (func (type 49))) + (type (;50;) (tuple u8 string)) + (type (;51;) (list 50)) + (type (;52;) (tuple string u8)) + (type (;53;) (list 52)) + (type (;54;) (func (param "x" 51) (result 53))) + (export (;23;) "tuple-string-list" (func (type 54))) + (type (;55;) (func (param "x" 47) (result 47))) + (export (;24;) "string-list" (func (type 55))) + (type (;56;) (list 4)) + (type (;57;) (list 2)) + (type (;58;) (func (param "x" 56) (result 57))) + (export (;25;) "record-list" (func (type 58))) + (type (;59;) (list 9)) + (type (;60;) (func (param "x" 59) (result 7))) + (export (;26;) "variant-list" (func (type 60))) + (type (;61;) (func (param "a" 12) (result 12))) + (export (;27;) "load-store-everything" (func (type 61))) + ) + ) + (export (;0;) (interface "foo:foo/lists") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (record (field "a1" u32) (field "a2" u64) (field "a3" s32) (field "a4" s64) (field "b" string) (field "c" 0))) + (export (;2;) "other-record" (type (eq 1))) + (type (;3;) (record (field "x" string) (field "y" 2) (field "c1" u32) (field "c2" u64) (field "c3" s32) (field "c4" s64))) + (export (;4;) "some-record" (type (eq 3))) + (type (;5;) (variant (case "a") (case "b" u32) (case "c" string))) + (export (;6;) "other-variant" (type (eq 5))) + (type (;7;) (list 6)) + (type (;8;) (variant (case "a" string) (case "b") (case "c" u32) (case "d" 7))) + (export (;9;) "some-variant" (type (eq 8))) + (type (;10;) (tuple string u8 s8 u16 s16 u32 s32 u64 s64 float32 float64 char)) + (type (;11;) (list 10)) + (export (;12;) "load-store-all-sizes" (type (eq 11))) + (type (;13;) (func (param "x" 0))) + (export (;0;) "list-u8-param" (func (type 13))) + (type (;14;) (list u16)) + (type (;15;) (func (param "x" 14))) + (export (;1;) "list-u16-param" (func (type 15))) + (type (;16;) (list u32)) + (type (;17;) (func (param "x" 16))) + (export (;2;) "list-u32-param" (func (type 17))) + (type (;18;) (list u64)) + (type (;19;) (func (param "x" 18))) + (export (;3;) "list-u64-param" (func (type 19))) + (type (;20;) (list s8)) + (type (;21;) (func (param "x" 20))) + (export (;4;) "list-s8-param" (func (type 21))) + (type (;22;) (list s16)) + (type (;23;) (func (param "x" 22))) + (export (;5;) "list-s16-param" (func (type 23))) + (type (;24;) (list s32)) + (type (;25;) (func (param "x" 24))) + (export (;6;) "list-s32-param" (func (type 25))) + (type (;26;) (list s64)) + (type (;27;) (func (param "x" 26))) + (export (;7;) "list-s64-param" (func (type 27))) + (type (;28;) (list float32)) + (type (;29;) (func (param "x" 28))) + (export (;8;) "list-float32-param" (func (type 29))) + (type (;30;) (list float64)) + (type (;31;) (func (param "x" 30))) + (export (;9;) "list-float64-param" (func (type 31))) + (type (;32;) (func (result 0))) + (export (;10;) "list-u8-ret" (func (type 32))) + (type (;33;) (func (result 14))) + (export (;11;) "list-u16-ret" (func (type 33))) + (type (;34;) (func (result 16))) + (export (;12;) "list-u32-ret" (func (type 34))) + (type (;35;) (func (result 18))) + (export (;13;) "list-u64-ret" (func (type 35))) + (type (;36;) (func (result 20))) + (export (;14;) "list-s8-ret" (func (type 36))) + (type (;37;) (func (result 22))) + (export (;15;) "list-s16-ret" (func (type 37))) + (type (;38;) (func (result 24))) + (export (;16;) "list-s32-ret" (func (type 38))) + (type (;39;) (func (result 26))) + (export (;17;) "list-s64-ret" (func (type 39))) + (type (;40;) (func (result 28))) + (export (;18;) "list-float32-ret" (func (type 40))) + (type (;41;) (func (result 30))) + (export (;19;) "list-float64-ret" (func (type 41))) + (type (;42;) (tuple u8 s8)) + (type (;43;) (list 42)) + (type (;44;) (tuple s64 u32)) + (type (;45;) (list 44)) + (type (;46;) (func (param "x" 43) (result 45))) + (export (;20;) "tuple-list" (func (type 46))) + (type (;47;) (list string)) + (type (;48;) (func (param "a" 47))) + (export (;21;) "string-list-arg" (func (type 48))) + (type (;49;) (func (result 47))) + (export (;22;) "string-list-ret" (func (type 49))) + (type (;50;) (tuple u8 string)) + (type (;51;) (list 50)) + (type (;52;) (tuple string u8)) + (type (;53;) (list 52)) + (type (;54;) (func (param "x" 51) (result 53))) + (export (;23;) "tuple-string-list" (func (type 54))) + (type (;55;) (func (param "x" 47) (result 47))) + (export (;24;) "string-list" (func (type 55))) + (type (;56;) (list 4)) + (type (;57;) (list 2)) + (type (;58;) (func (param "x" 56) (result 57))) + (export (;25;) "record-list" (func (type 58))) + (type (;59;) (list 9)) + (type (;60;) (func (param "x" 59) (result 7))) + (export (;26;) "variant-list" (func (type 60))) + (type (;61;) (func (param "a" 12) (result 12))) + (export (;27;) "load-store-everything" (func (type 61))) + ) + ) + (import (interface "foo:foo/lists") (instance (;0;) (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/lists-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/lists.wit b/crates/wit-component/tests/interfaces/lists.wit new file mode 100644 index 0000000000..6d192250ea --- /dev/null +++ b/crates/wit-component/tests/interfaces/lists.wit @@ -0,0 +1,96 @@ +package foo:foo; + +interface lists { + record other-record { + a1: u32, + a2: u64, + a3: s32, + a4: s64, + b: string, + c: list, + } + + record some-record { + x: string, + y: other-record, + c1: u32, + c2: u64, + c3: s32, + c4: s64, + } + + variant other-variant { + a, + b(u32), + c(string), + } + + variant some-variant { + a(string), + b, + c(u32), + d(list), + } + + type load-store-all-sizes = list>; + + list-u8-param: func(x: list); + + list-u16-param: func(x: list); + + list-u32-param: func(x: list); + + list-u64-param: func(x: list); + + list-s8-param: func(x: list); + + list-s16-param: func(x: list); + + list-s32-param: func(x: list); + + list-s64-param: func(x: list); + + list-float32-param: func(x: list); + + list-float64-param: func(x: list); + + list-u8-ret: func() -> list; + + list-u16-ret: func() -> list; + + list-u32-ret: func() -> list; + + list-u64-ret: func() -> list; + + list-s8-ret: func() -> list; + + list-s16-ret: func() -> list; + + list-s32-ret: func() -> list; + + list-s64-ret: func() -> list; + + list-float32-ret: func() -> list; + + list-float64-ret: func() -> list; + + tuple-list: func(x: list>) -> list>; + + string-list-arg: func(a: list); + + string-list-ret: func() -> list; + + tuple-string-list: func(x: list>) -> list>; + + string-list: func(x: list) -> list; + + record-list: func(x: list) -> list; + + variant-list: func(x: list) -> list; + + load-store-everything: func(a: load-store-all-sizes) -> load-store-all-sizes; +} + +world lists-world { + import lists; +} diff --git a/crates/wit-component/tests/interfaces/lists.wit.print b/crates/wit-component/tests/interfaces/lists.wit.print new file mode 100644 index 0000000000..c6dfa14625 --- /dev/null +++ b/crates/wit-component/tests/interfaces/lists.wit.print @@ -0,0 +1,96 @@ +package foo:foo + +interface lists { + record other-record { + a1: u32, + a2: u64, + a3: s32, + a4: s64, + b: string, + c: list, + } + + record some-record { + x: string, + y: other-record, + c1: u32, + c2: u64, + c3: s32, + c4: s64, + } + + variant other-variant { + a, + b(u32), + c(string), + } + + variant some-variant { + a(string), + b, + c(u32), + d(list), + } + + type load-store-all-sizes = list> + + list-u8-param: func(x: list) + + list-u16-param: func(x: list) + + list-u32-param: func(x: list) + + list-u64-param: func(x: list) + + list-s8-param: func(x: list) + + list-s16-param: func(x: list) + + list-s32-param: func(x: list) + + list-s64-param: func(x: list) + + list-float32-param: func(x: list) + + list-float64-param: func(x: list) + + list-u8-ret: func() -> list + + list-u16-ret: func() -> list + + list-u32-ret: func() -> list + + list-u64-ret: func() -> list + + list-s8-ret: func() -> list + + list-s16-ret: func() -> list + + list-s32-ret: func() -> list + + list-s64-ret: func() -> list + + list-float32-ret: func() -> list + + list-float64-ret: func() -> list + + tuple-list: func(x: list>) -> list> + + string-list-arg: func(a: list) + + string-list-ret: func() -> list + + tuple-string-list: func(x: list>) -> list> + + string-list: func(x: list) -> list + + record-list: func(x: list) -> list + + variant-list: func(x: list) -> list + + load-store-everything: func(a: load-store-all-sizes) -> load-store-all-sizes +} + +world lists-world { + import lists +} diff --git a/crates/wit-component/tests/interfaces/multi-doc.wat b/crates/wit-component/tests/interfaces/multi-doc.wat new file mode 100644 index 0000000000..e99ce635b6 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multi-doc.wat @@ -0,0 +1,39 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "the-type" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:foo/b") (instance (type 0))) + (alias export 0 "the-type" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-type" (type (eq 0))) + ) + ) + (export (;1;) (interface "foo:foo/a") (instance (type 2))) + (type (;3;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-type" (type (eq 0))) + ) + ) + (export (;2;) (interface "foo:foo/b2") (instance (type 3))) + (type (;4;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-type" (type (eq 0))) + ) + ) + (export (;3;) (interface "foo:foo/a2") (instance (type 4))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/multi-doc/a.wit b/crates/wit-component/tests/interfaces/multi-doc/a.wit new file mode 100644 index 0000000000..a2a494bb49 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multi-doc/a.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface a { + use b.{the-type}; +} + +interface b2 { + use b.{the-type}; +} diff --git a/crates/wit-component/tests/interfaces/multi-doc/b.wit b/crates/wit-component/tests/interfaces/multi-doc/b.wit new file mode 100644 index 0000000000..d669394504 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multi-doc/b.wit @@ -0,0 +1,9 @@ +interface a2 { + use b.{the-type}; +} + +interface b { + record the-type { + f: u8, + } +} diff --git a/crates/wit-component/tests/interfaces/multi-doc/foo.wit.print b/crates/wit-component/tests/interfaces/multi-doc/foo.wit.print new file mode 100644 index 0000000000..9cbc63ad98 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multi-doc/foo.wit.print @@ -0,0 +1,20 @@ +package foo:foo + +interface b { + record the-type { + f: u8, + } +} + +interface a { + use b.{the-type} +} + +interface b2 { + use b.{the-type} +} + +interface a2 { + use b.{the-type} +} + diff --git a/crates/wit-component/tests/interfaces/multiple-use.wat b/crates/wit-component/tests/interfaces/multiple-use.wat new file mode 100644 index 0000000000..38eff77f47 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multiple-use.wat @@ -0,0 +1,40 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "t1" (type (eq 0))) + (type (;2;) u8) + (export (;3;) "t2" (type (eq 2))) + ) + ) + (export (;0;) (interface "foo:multiuse/foo") (instance (type 0))) + (type (;1;) + (instance + (type (;0;) u8) + (export (;1;) "u" (type (eq 0))) + ) + ) + (export (;1;) (interface "foo:multiuse/bar") (instance (type 1))) + (alias export 0 "t1" (type (;2;))) + (alias export 1 "u" (type (;3;))) + (alias export 0 "t2" (type (;4;))) + (type (;5;) + (instance + (alias outer 1 2 (type (;0;))) + (export (;1;) "t1" (type (eq 0))) + (alias outer 1 3 (type (;2;))) + (export (;3;) "u" (type (eq 2))) + (alias outer 1 4 (type (;4;))) + (export (;5;) "t2" (type (eq 4))) + ) + ) + (export (;2;) (interface "foo:multiuse/baz") (instance (type 5))) + ) + ) + (export (;1;) (interface "foo:multiuse/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/multiple-use.wit b/crates/wit-component/tests/interfaces/multiple-use.wit new file mode 100644 index 0000000000..9648999290 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multiple-use.wit @@ -0,0 +1,16 @@ +package foo:multiuse; + +interface foo { + type t1 = u8; + type t2 = u8; +} + +interface bar { + type u = u8; +} + +interface baz { + use foo.{t1}; + use bar.{u}; + use foo.{t2}; +} diff --git a/crates/wit-component/tests/interfaces/multiple-use.wit.print b/crates/wit-component/tests/interfaces/multiple-use.wit.print new file mode 100644 index 0000000000..fe3dde10d8 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multiple-use.wit.print @@ -0,0 +1,18 @@ +package foo:multiuse + +interface foo { + type t1 = u8 + + type t2 = u8 +} + +interface bar { + type u = u8 +} + +interface baz { + use foo.{t1} + use bar.{u} + use foo.{t2} +} + diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain.wat b/crates/wit-component/tests/interfaces/pkg-use-chain.wat new file mode 100644 index 0000000000..3271c3f4f7 --- /dev/null +++ b/crates/wit-component/tests/interfaces/pkg-use-chain.wat @@ -0,0 +1,35 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "a" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:chain/a") (instance (type 0))) + (alias export 0 "a" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "a" (type (eq 0))) + (type (;2;) (enum "other")) + (export (;3;) "name" (type (eq 2))) + ) + ) + (export (;1;) (interface "foo:chain/def") (instance (type 2))) + (alias export 1 "name" (type (;3;))) + (type (;4;) + (instance + (alias outer 1 3 (type (;0;))) + (export (;1;) "name" (type (eq 0))) + ) + ) + (export (;2;) (interface "foo:chain/foo") (instance (type 4))) + ) + ) + (export (;1;) (interface "foo:chain/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain/chain.wit.print b/crates/wit-component/tests/interfaces/pkg-use-chain/chain.wit.print new file mode 100644 index 0000000000..6d3e94c9eb --- /dev/null +++ b/crates/wit-component/tests/interfaces/pkg-use-chain/chain.wit.print @@ -0,0 +1,18 @@ +package foo:chain + +interface a { + type a = u8 +} + +interface def { + use a.{a} + + enum name { + other, + } +} + +interface foo { + use def.{name} +} + diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain/def.wit b/crates/wit-component/tests/interfaces/pkg-use-chain/def.wit new file mode 100644 index 0000000000..0d98bd3d51 --- /dev/null +++ b/crates/wit-component/tests/interfaces/pkg-use-chain/def.wit @@ -0,0 +1,13 @@ +package foo:chain; + +interface def { + use a.{a}; + + enum name { + other, + } +} + +interface a { + type a = u8; +} diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain/the-use.wit b/crates/wit-component/tests/interfaces/pkg-use-chain/the-use.wit new file mode 100644 index 0000000000..8469472556 --- /dev/null +++ b/crates/wit-component/tests/interfaces/pkg-use-chain/the-use.wit @@ -0,0 +1,5 @@ +package foo:chain; + +interface foo { + use def.{name}; +} diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain2.wat b/crates/wit-component/tests/interfaces/pkg-use-chain2.wat new file mode 100644 index 0000000000..65c10e616c --- /dev/null +++ b/crates/wit-component/tests/interfaces/pkg-use-chain2.wat @@ -0,0 +1,35 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "name" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:foo/other") (instance (type 0))) + (alias export 0 "name" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "the-name" (type (eq 0))) + (type (;2;) (enum "a")) + (export (;3;) "name" (type (eq 2))) + ) + ) + (export (;1;) (interface "foo:foo/bar") (instance (type 2))) + (alias export 1 "the-name" (type (;3;))) + (type (;4;) + (instance + (alias outer 1 3 (type (;0;))) + (export (;1;) "the-name" (type (eq 0))) + ) + ) + (export (;2;) (interface "foo:foo/foo") (instance (type 4))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain2/bar.wit b/crates/wit-component/tests/interfaces/pkg-use-chain2/bar.wit new file mode 100644 index 0000000000..c8246fbf7b --- /dev/null +++ b/crates/wit-component/tests/interfaces/pkg-use-chain2/bar.wit @@ -0,0 +1,13 @@ +interface bar { + use other.{name as the-name}; + + enum name { + a + } +} + +interface other { + record name { + f: u8, + } +} diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain2/foo.wit b/crates/wit-component/tests/interfaces/pkg-use-chain2/foo.wit new file mode 100644 index 0000000000..a906a59aa9 --- /dev/null +++ b/crates/wit-component/tests/interfaces/pkg-use-chain2/foo.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface foo { + use bar.{the-name}; +} diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain2/foo.wit.print b/crates/wit-component/tests/interfaces/pkg-use-chain2/foo.wit.print new file mode 100644 index 0000000000..82e572f933 --- /dev/null +++ b/crates/wit-component/tests/interfaces/pkg-use-chain2/foo.wit.print @@ -0,0 +1,20 @@ +package foo:foo + +interface other { + record name { + f: u8, + } +} + +interface bar { + use other.{name as the-name} + + enum name { + a, + } +} + +interface foo { + use bar.{the-name} +} + diff --git a/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat b/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat new file mode 100644 index 0000000000..41d21f3a32 --- /dev/null +++ b/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat @@ -0,0 +1,41 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (enum "b")) + (export (;1;) "a" (type (eq 0))) + (type (;2;) (record (field "f" u8))) + (export (;3;) "ty" (type (eq 2))) + ) + ) + (import (interface "foo:dep/foo") (instance (;0;) (type 0))) + (alias export 0 "ty" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "ty" (type (eq 0))) + ) + ) + (export (;1;) (interface "foo:foo/foo") (instance (type 2))) + (type (;3;) + (component + (type (;0;) + (instance + (type (;0;) (enum "b")) + (export (;1;) "a" (type (eq 0))) + (type (;2;) (record (field "f" u8))) + (export (;3;) "ty" (type (eq 2))) + ) + ) + (import (interface "foo:dep/foo") (instance (;0;) (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/bar") (component (type 3))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/preserve-dep-type-order/deps/dep/foo.wit b/crates/wit-component/tests/interfaces/preserve-dep-type-order/deps/dep/foo.wit new file mode 100644 index 0000000000..1e2b6181ec --- /dev/null +++ b/crates/wit-component/tests/interfaces/preserve-dep-type-order/deps/dep/foo.wit @@ -0,0 +1,11 @@ +package foo:dep; + +interface foo { + enum a { + b + } + + record ty { + f: u8, + } +} diff --git a/crates/wit-component/tests/interfaces/preserve-dep-type-order/foo.wit b/crates/wit-component/tests/interfaces/preserve-dep-type-order/foo.wit new file mode 100644 index 0000000000..d82e5b1e73 --- /dev/null +++ b/crates/wit-component/tests/interfaces/preserve-dep-type-order/foo.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface foo { + use foo:dep/foo.{ty}; +} + +world bar { + import foo:dep/foo; +} diff --git a/crates/wit-component/tests/interfaces/preserve-dep-type-order/foo.wit.print b/crates/wit-component/tests/interfaces/preserve-dep-type-order/foo.wit.print new file mode 100644 index 0000000000..eafc191957 --- /dev/null +++ b/crates/wit-component/tests/interfaces/preserve-dep-type-order/foo.wit.print @@ -0,0 +1,9 @@ +package foo:foo + +interface foo { + use foo:dep/foo.{ty} +} + +world bar { + import foo:dep/foo +} diff --git a/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat b/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat new file mode 100644 index 0000000000..e82cad5994 --- /dev/null +++ b/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat @@ -0,0 +1,23 @@ +(component + (type (;0;) + (component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "foo" (type (eq 0))) + (export (;2;) "bar" (type (eq 1))) + ) + ) + (export (;0;) (interface "foo:my-dep/my-interface") (instance (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (component (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/preserve-foreign-reexport/deps/my-dep/my-doc.wit b/crates/wit-component/tests/interfaces/preserve-foreign-reexport/deps/my-dep/my-doc.wit new file mode 100644 index 0000000000..27b98fb289 --- /dev/null +++ b/crates/wit-component/tests/interfaces/preserve-foreign-reexport/deps/my-dep/my-doc.wit @@ -0,0 +1,8 @@ +package foo:my-dep; + +interface my-interface { + record foo { + f: u8, + } + type bar = foo; +} diff --git a/crates/wit-component/tests/interfaces/preserve-foreign-reexport/foo.wit b/crates/wit-component/tests/interfaces/preserve-foreign-reexport/foo.wit new file mode 100644 index 0000000000..24054d08df --- /dev/null +++ b/crates/wit-component/tests/interfaces/preserve-foreign-reexport/foo.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo { + export foo:my-dep/my-interface; +} diff --git a/crates/wit-component/tests/interfaces/preserve-foreign-reexport/foo.wit.print b/crates/wit-component/tests/interfaces/preserve-foreign-reexport/foo.wit.print new file mode 100644 index 0000000000..ae83137a39 --- /dev/null +++ b/crates/wit-component/tests/interfaces/preserve-foreign-reexport/foo.wit.print @@ -0,0 +1,5 @@ +package foo:foo + +world foo { + export foo:my-dep/my-interface +} diff --git a/crates/wit-component/tests/interfaces/print-keyword.wat b/crates/wit-component/tests/interfaces/print-keyword.wat new file mode 100644 index 0000000000..742b8644a8 --- /dev/null +++ b/crates/wit-component/tests/interfaces/print-keyword.wat @@ -0,0 +1,20 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "type" (type (eq 0))) + (export (;2;) "world" (type (eq 1))) + (type (;3;) (record (field "variant" 2))) + (export (;4;) "record" (type (eq 3))) + ) + ) + (export (;0;) (interface "foo:foo/interface") (instance (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/print-keyword.wit b/crates/wit-component/tests/interfaces/print-keyword.wit new file mode 100644 index 0000000000..4f0670f3a1 --- /dev/null +++ b/crates/wit-component/tests/interfaces/print-keyword.wit @@ -0,0 +1,10 @@ +package foo:foo; + +interface %interface { + type %type = u32; + type %world = %type; + + record %record { + %variant: %world, + } +} diff --git a/crates/wit-component/tests/interfaces/print-keyword.wit.print b/crates/wit-component/tests/interfaces/print-keyword.wit.print new file mode 100644 index 0000000000..4488715b75 --- /dev/null +++ b/crates/wit-component/tests/interfaces/print-keyword.wit.print @@ -0,0 +1,12 @@ +package foo:foo + +interface %interface { + type %type = u32 + + type %world = %type + + record %record { + %variant: %world, + } +} + diff --git a/crates/wit-component/tests/interfaces/records.wat b/crates/wit-component/tests/interfaces/records.wat new file mode 100644 index 0000000000..c5d7d31e56 --- /dev/null +++ b/crates/wit-component/tests/interfaces/records.wat @@ -0,0 +1,135 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "single" (type (eq 0))) + (type (;2;) (record (field "a" u32) (field "b" u32))) + (export (;3;) "scalars" (type (eq 2))) + (type (;4;) (flags "a" "b" "c" "d" "e" "f" "g" "h" "i")) + (export (;5;) "really-flags" (type (eq 4))) + (type (;6;) (record (field "a" 3) (field "b" u32) (field "c" 1) (field "d" string) (field "e" 5))) + (export (;7;) "aggregates" (type (eq 6))) + (type (;8;) s32) + (export (;9;) "int-typedef" (type (eq 8))) + (type (;10;) (tuple 9)) + (export (;11;) "tuple-typedef2" (type (eq 10))) + (type (;12;) (tuple char u32)) + (type (;13;) (func (param "x" 12))) + (export (;0;) "tuple-arg" (func (type 13))) + (type (;14;) (func (result 12))) + (export (;1;) "tuple-result" (func (type 14))) + (type (;15;) (func (param "x" 1))) + (export (;2;) "single-arg" (func (type 15))) + (type (;16;) (func (result 1))) + (export (;3;) "single-result" (func (type 16))) + (type (;17;) (func (param "x" 3))) + (export (;4;) "scalar-arg" (func (type 17))) + (type (;18;) (func (result 3))) + (export (;5;) "scalar-result" (func (type 18))) + (type (;19;) (func (param "x" 5))) + (export (;6;) "flags-arg" (func (type 19))) + (type (;20;) (func (result 5))) + (export (;7;) "flags-result" (func (type 20))) + (type (;21;) (func (param "x" 7))) + (export (;8;) "aggregate-arg" (func (type 21))) + (type (;22;) (func (result 7))) + (export (;9;) "aggregate-result" (func (type 22))) + (type (;23;) (func (param "e" 11) (result s32))) + (export (;10;) "typedef-inout" (func (type 23))) + ) + ) + (export (;0;) (interface "foo:records/records") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "single" (type (eq 0))) + (type (;2;) (record (field "a" u32) (field "b" u32))) + (export (;3;) "scalars" (type (eq 2))) + (type (;4;) (flags "a" "b" "c" "d" "e" "f" "g" "h" "i")) + (export (;5;) "really-flags" (type (eq 4))) + (type (;6;) (record (field "a" 3) (field "b" u32) (field "c" 1) (field "d" string) (field "e" 5))) + (export (;7;) "aggregates" (type (eq 6))) + (type (;8;) s32) + (export (;9;) "int-typedef" (type (eq 8))) + (type (;10;) (tuple 9)) + (export (;11;) "tuple-typedef2" (type (eq 10))) + (type (;12;) (tuple char u32)) + (type (;13;) (func (param "x" 12))) + (export (;0;) "tuple-arg" (func (type 13))) + (type (;14;) (func (result 12))) + (export (;1;) "tuple-result" (func (type 14))) + (type (;15;) (func (param "x" 1))) + (export (;2;) "single-arg" (func (type 15))) + (type (;16;) (func (result 1))) + (export (;3;) "single-result" (func (type 16))) + (type (;17;) (func (param "x" 3))) + (export (;4;) "scalar-arg" (func (type 17))) + (type (;18;) (func (result 3))) + (export (;5;) "scalar-result" (func (type 18))) + (type (;19;) (func (param "x" 5))) + (export (;6;) "flags-arg" (func (type 19))) + (type (;20;) (func (result 5))) + (export (;7;) "flags-result" (func (type 20))) + (type (;21;) (func (param "x" 7))) + (export (;8;) "aggregate-arg" (func (type 21))) + (type (;22;) (func (result 7))) + (export (;9;) "aggregate-result" (func (type 22))) + (type (;23;) (func (param "e" 11) (result s32))) + (export (;10;) "typedef-inout" (func (type 23))) + ) + ) + (import (interface "foo:records/records") (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (record (field "f" u8))) + (export (;1;) "single" (type (eq 0))) + (type (;2;) (record (field "a" u32) (field "b" u32))) + (export (;3;) "scalars" (type (eq 2))) + (type (;4;) (flags "a" "b" "c" "d" "e" "f" "g" "h" "i")) + (export (;5;) "really-flags" (type (eq 4))) + (type (;6;) (record (field "a" 3) (field "b" u32) (field "c" 1) (field "d" string) (field "e" 5))) + (export (;7;) "aggregates" (type (eq 6))) + (type (;8;) s32) + (export (;9;) "int-typedef" (type (eq 8))) + (type (;10;) (tuple 9)) + (export (;11;) "tuple-typedef2" (type (eq 10))) + (type (;12;) (tuple char u32)) + (type (;13;) (func (param "x" 12))) + (export (;0;) "tuple-arg" (func (type 13))) + (type (;14;) (func (result 12))) + (export (;1;) "tuple-result" (func (type 14))) + (type (;15;) (func (param "x" 1))) + (export (;2;) "single-arg" (func (type 15))) + (type (;16;) (func (result 1))) + (export (;3;) "single-result" (func (type 16))) + (type (;17;) (func (param "x" 3))) + (export (;4;) "scalar-arg" (func (type 17))) + (type (;18;) (func (result 3))) + (export (;5;) "scalar-result" (func (type 18))) + (type (;19;) (func (param "x" 5))) + (export (;6;) "flags-arg" (func (type 19))) + (type (;20;) (func (result 5))) + (export (;7;) "flags-result" (func (type 20))) + (type (;21;) (func (param "x" 7))) + (export (;8;) "aggregate-arg" (func (type 21))) + (type (;22;) (func (result 7))) + (export (;9;) "aggregate-result" (func (type 22))) + (type (;23;) (func (param "e" 11) (result s32))) + (export (;10;) "typedef-inout" (func (type 23))) + ) + ) + (export (;1;) (interface "foo:records/records") (instance (type 1))) + ) + ) + (export (;0;) (interface "foo:records/records-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:records/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/records.wit b/crates/wit-component/tests/interfaces/records.wit new file mode 100644 index 0000000000..15639dfd89 --- /dev/null +++ b/crates/wit-component/tests/interfaces/records.wit @@ -0,0 +1,63 @@ +package foo:records; + +interface records { + record single { + f: u8, + } + + record scalars { + a: u32, + b: u32, + } + + flags really-flags { + a, + b, + c, + d, + e, + f, + g, + h, + i, + } + + record aggregates { + a: scalars, + b: u32, + c: single, + d: string, + e: really-flags, + } + + type int-typedef = s32; + + type tuple-typedef2 = tuple; + + tuple-arg: func(x: tuple); + + tuple-result: func() -> tuple; + + single-arg: func(x: single); + + single-result: func() -> single; + + scalar-arg: func(x: scalars); + + scalar-result: func() -> scalars; + + flags-arg: func(x: really-flags); + + flags-result: func() -> really-flags; + + aggregate-arg: func(x: aggregates); + + aggregate-result: func() -> aggregates; + + typedef-inout: func(e: tuple-typedef2) -> s32; +} + +world records-world { + import records; + export records; +} diff --git a/crates/wit-component/tests/interfaces/records.wit.print b/crates/wit-component/tests/interfaces/records.wit.print new file mode 100644 index 0000000000..1b171380ed --- /dev/null +++ b/crates/wit-component/tests/interfaces/records.wit.print @@ -0,0 +1,64 @@ +package foo:records + +interface records { + record single { + f: u8, + } + + record scalars { + a: u32, + b: u32, + } + + flags really-flags { + a, + b, + c, + d, + e, + f, + g, + h, + i, + } + + record aggregates { + a: scalars, + b: u32, + c: single, + d: string, + e: really-flags, + } + + type int-typedef = s32 + + type tuple-typedef2 = tuple + + tuple-arg: func(x: tuple) + + tuple-result: func() -> tuple + + single-arg: func(x: single) + + single-result: func() -> single + + scalar-arg: func(x: scalars) + + scalar-result: func() -> scalars + + flags-arg: func(x: really-flags) + + flags-result: func() -> really-flags + + aggregate-arg: func(x: aggregates) + + aggregate-result: func() -> aggregates + + typedef-inout: func(e: tuple-typedef2) -> s32 +} + +world records-world { + import records + + export records +} diff --git a/crates/wit-component/tests/interfaces/reference-out-of-order.wat b/crates/wit-component/tests/interfaces/reference-out-of-order.wat new file mode 100644 index 0000000000..81f9af8fae --- /dev/null +++ b/crates/wit-component/tests/interfaces/reference-out-of-order.wat @@ -0,0 +1,57 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "s" string))) + (export (;1;) "r" (type (eq 0))) + (type (;2;) (variant (case "s" string))) + (export (;3;) "v" (type (eq 2))) + (type (;4;) (record (field "s" u32))) + (export (;5;) "r-no-string" (type (eq 4))) + (type (;6;) (variant (case "s" u32))) + (export (;7;) "v-no-string" (type (eq 6))) + (type (;8;) (func (param "x" 1))) + (export (;0;) "a" (func (type 8))) + (type (;9;) (func (param "x" 3))) + (export (;1;) "b" (func (type 9))) + (type (;10;) (func (param "x" 5))) + (export (;2;) "c" (func (type 10))) + (type (;11;) (func (param "x" 7))) + (export (;3;) "d" (func (type 11))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "s" string))) + (export (;1;) "r" (type (eq 0))) + (type (;2;) (variant (case "s" string))) + (export (;3;) "v" (type (eq 2))) + (type (;4;) (record (field "s" u32))) + (export (;5;) "r-no-string" (type (eq 4))) + (type (;6;) (variant (case "s" u32))) + (export (;7;) "v-no-string" (type (eq 6))) + (type (;8;) (func (param "x" 1))) + (export (;0;) "a" (func (type 8))) + (type (;9;) (func (param "x" 3))) + (export (;1;) "b" (func (type 9))) + (type (;10;) (func (param "x" 5))) + (export (;2;) "c" (func (type 10))) + (type (;11;) (func (param "x" 7))) + (export (;3;) "d" (func (type 11))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/foo-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/reference-out-of-order.wit b/crates/wit-component/tests/interfaces/reference-out-of-order.wit new file mode 100644 index 0000000000..5b75fc2044 --- /dev/null +++ b/crates/wit-component/tests/interfaces/reference-out-of-order.wit @@ -0,0 +1,28 @@ +package foo:foo; + +interface foo { + a: func(x: r); + b: func(x: v); + c: func(x: r-no-string); + d: func(x: v-no-string); + + record r { + s: string, + } + + variant v { + s(string), + } + + record r-no-string { + s: u32, + } + + variant v-no-string { + s(u32), + } +} + +world foo-world { + import foo; +} diff --git a/crates/wit-component/tests/interfaces/reference-out-of-order.wit.print b/crates/wit-component/tests/interfaces/reference-out-of-order.wit.print new file mode 100644 index 0000000000..dd2f9390c0 --- /dev/null +++ b/crates/wit-component/tests/interfaces/reference-out-of-order.wit.print @@ -0,0 +1,31 @@ +package foo:foo + +interface foo { + record r { + s: string, + } + + variant v { + s(string), + } + + record r-no-string { + s: u32, + } + + variant v-no-string { + s(u32), + } + + a: func(x: r) + + b: func(x: v) + + c: func(x: r-no-string) + + d: func(x: v-no-string) +} + +world foo-world { + import foo +} diff --git a/crates/wit-component/tests/interfaces/resources.wat b/crates/wit-component/tests/interfaces/resources.wat new file mode 100644 index 0000000000..ccc4762593 --- /dev/null +++ b/crates/wit-component/tests/interfaces/resources.wat @@ -0,0 +1,152 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (export (;0;) "bar" (type (sub resource))) + (export (;1;) "t" (type (eq 0))) + (type (;2;) (own 0)) + (export (;3;) "t2" (type (eq 2))) + (type (;4;) (own 0)) + (type (;5;) (func (result 4))) + (export (;0;) "[constructor]bar" (func (type 5))) + (type (;6;) (func)) + (export (;1;) "[static]bar.a" (func (type 6))) + (type (;7;) (borrow 0)) + (type (;8;) (func (param "self" 7))) + (export (;2;) "[method]bar.b" (func (type 8))) + (type (;9;) (func (param "x" 4) (result 4))) + (export (;3;) "a" (func (type 9))) + ) + ) + (export (;0;) (interface "foo:bar/foo") (instance (type 0))) + (alias export 0 "bar" (type (;1;))) + (alias export 0 "t" (type (;2;))) + (type (;3;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "bar" (type (eq 0))) + (alias outer 1 2 (type (;2;))) + (export (;3;) "t" (type (eq 2))) + (type (;4;) (own 1)) + (type (;5;) (func (param "x" 4) (result 4))) + (export (;0;) "a" (func (type 5))) + (type (;6;) (own 3)) + (type (;7;) (func (result 6))) + (export (;1;) "b" (func (type 7))) + ) + ) + (export (;1;) (interface "foo:bar/baz") (instance (type 3))) + (type (;4;) + (instance + (export (;0;) "a" (type (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (param "a1" 1) (param "a2" 1) (result 1))) + (export (;0;) "b" (func (type 2))) + (type (;3;) (list 1)) + (type (;4;) (func (result 3))) + (export (;1;) "c" (func (type 4))) + ) + ) + (export (;2;) (interface "foo:bar/implicit-own-handles") (instance (type 4))) + (type (;5;) + (instance + (export (;0;) "a" (type (sub resource))) + (export (;1;) "b" (type (sub resource))) + (export (;2;) "c" (type (sub resource))) + (type (;3;) (own 0)) + (type (;4;) (list 3)) + (type (;5;) (func (param "a" 4) (result 3))) + (export (;0;) "[constructor]a" (func (type 5))) + (type (;6;) (own 1)) + (type (;7;) (list 6)) + (type (;8;) (func (param "a" 7) (param "b" 6) (result 6))) + (export (;1;) "[constructor]b" (func (type 8))) + (type (;9;) (own 2)) + (type (;10;) (func (param "a" 9) (result 9))) + (export (;2;) "[static]c.a" (func (type 10))) + ) + ) + (export (;3;) (interface "foo:bar/implicit-own-handles2") (instance (type 5))) + (type (;6;) + (component + (type (;0;) + (instance + (export (;0;) "a" (type (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (export (;0;) "[constructor]a" (func (type 2))) + (type (;3;) (func)) + (export (;1;) "[static]a.b" (func (type 3))) + (type (;4;) (borrow 0)) + (type (;5;) (func (param "self" 4))) + (export (;2;) "[method]a.c" (func (type 5))) + ) + ) + (import "anon" (instance (;0;) (type 0))) + (type (;1;) + (instance + (export (;0;) "bar" (type (sub resource))) + (export (;1;) "t" (type (eq 0))) + (type (;2;) (own 0)) + (export (;3;) "t2" (type (eq 2))) + (type (;4;) (own 0)) + (type (;5;) (func (result 4))) + (export (;0;) "[constructor]bar" (func (type 5))) + (type (;6;) (func)) + (export (;1;) "[static]bar.a" (func (type 6))) + (type (;7;) (borrow 0)) + (type (;8;) (func (param "self" 7))) + (export (;2;) "[method]bar.b" (func (type 8))) + (type (;9;) (func (param "x" 4) (result 4))) + (export (;3;) "a" (func (type 9))) + ) + ) + (import (interface "foo:bar/foo") (instance (;1;) (type 1))) + (alias export 1 "bar" (type (;2;))) + (alias export 1 "t" (type (;3;))) + (type (;4;) + (instance + (alias outer 1 2 (type (;0;))) + (export (;1;) "bar" (type (eq 0))) + (alias outer 1 3 (type (;2;))) + (export (;3;) "t" (type (eq 2))) + (type (;4;) (own 1)) + (type (;5;) (func (param "x" 4) (result 4))) + (export (;0;) "a" (func (type 5))) + (type (;6;) (own 3)) + (type (;7;) (func (result 6))) + (export (;1;) "b" (func (type 7))) + ) + ) + (import (interface "foo:bar/baz") (instance (;2;) (type 4))) + (alias export 2 "bar" (type (;5;))) + (import "bar" (type (;6;) (eq 5))) + (import "a" (type (;7;) (sub resource))) + (type (;8;) (own 7)) + (type (;9;) (func (result 8))) + (import "[constructor]a" (func (;0;) (type 9))) + (export (;1;) "x" (func (type 9))) + (type (;10;) (own 6)) + (type (;11;) (func (result 10))) + (export (;2;) "y" (func (type 11))) + ) + ) + (export (;0;) (interface "foo:bar/some-world") (component (type 6))) + (type (;7;) + (component + (import "a" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (list 1)) + (type (;3;) (func (param "a" 2) (param "b" 2) (result 1))) + (import "[constructor]a" (func (;0;) (type 3))) + ) + ) + (export (;1;) (interface "foo:bar/implicit-own-handles3") (component (type 7))) + ) + ) + (export (;1;) (interface "foo:bar/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/resources.wit b/crates/wit-component/tests/interfaces/resources.wit new file mode 100644 index 0000000000..9558b6bad7 --- /dev/null +++ b/crates/wit-component/tests/interfaces/resources.wit @@ -0,0 +1,76 @@ +package foo:bar; + +interface foo { + resource bar { + constructor(); + a: static func(); + b: func(); + } + + a: func(x: bar) -> bar; + type t = bar; + type t2 = own; +} + +interface baz { + use foo.{bar,t}; + a: func(x: bar) -> bar; + + b: func() -> t; +} + + +world some-world { + use baz.{bar}; + + resource a { + constructor(); + } + + export x: func() -> a; + export y: func() -> bar; + + import anon: interface { + resource a { + constructor(); + + b: static func(); + + c: func(); + } + } +} + +interface implicit-own-handles { + resource a; + + b: func(a1: a, a2: a) -> own; + c: func() -> list>; +} + +interface implicit-own-handles2 { + // the `own` return and list param should be the same `own` + resource a { + constructor(a: list); + } + + // same as above, even when the `list` implicitly-defined `own` comes + // before an explicitly defined `own` + resource b { + constructor(a: list, b: own); + } + + // same as the above, the `own` argument should have the same type as the + // return value + resource c { + a: static func(a: own) -> c; + } +} + +world implicit-own-handles3 { + // there should only be one `list` type despite there looking like two + // list types here + resource a { + constructor(a: list, b: list>); + } +} diff --git a/crates/wit-component/tests/interfaces/resources.wit.print b/crates/wit-component/tests/interfaces/resources.wit.print new file mode 100644 index 0000000000..de90c452b4 --- /dev/null +++ b/crates/wit-component/tests/interfaces/resources.wit.print @@ -0,0 +1,70 @@ +package foo:bar + +interface foo { + resource bar { + constructor() + a: static func() + b: func() + } + + type t = bar + + type t2 = own + + a: func(x: bar) -> bar +} + +interface baz { + use foo.{bar, t} + + a: func(x: bar) -> bar + + b: func() -> t +} + +interface implicit-own-handles { + resource a + + b: func(a1: a, a2: a) -> a + + c: func() -> list +} + +interface implicit-own-handles2 { + resource a { + constructor(a: list) + } + + resource b { + constructor(a: list, b: b) + } + + resource c { + a: static func(a: c) -> c + } +} + +world some-world { + import anon: interface { + resource a { + constructor() + b: static func() + c: func() + } + } + import foo + import baz + use baz.{bar} + + resource a { + constructor() + } + + export x: func() -> a + export y: func() -> bar +} +world implicit-own-handles3 { + resource a { + constructor(a: list, b: list) + } +} diff --git a/crates/wit-component/tests/interfaces/simple-deps.wat b/crates/wit-component/tests/interfaces/simple-deps.wat new file mode 100644 index 0000000000..66f3bfca04 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-deps.wat @@ -0,0 +1,25 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "some-type" (type (eq 0))) + ) + ) + (import (interface "foo:some-dep/types") (instance (;0;) (type 0))) + (alias export 0 "some-type" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "some-type" (type (eq 0))) + ) + ) + (export (;1;) (interface "foo:foo/foo") (instance (type 2))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/simple-deps/deps/some-dep/types.wit b/crates/wit-component/tests/interfaces/simple-deps/deps/some-dep/types.wit new file mode 100644 index 0000000000..8084fdabe8 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-deps/deps/some-dep/types.wit @@ -0,0 +1,5 @@ +package foo:some-dep; + +interface types { + type some-type = u8; +} diff --git a/crates/wit-component/tests/interfaces/simple-deps/foo.wit b/crates/wit-component/tests/interfaces/simple-deps/foo.wit new file mode 100644 index 0000000000..3c1e96fc4b --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-deps/foo.wit @@ -0,0 +1,4 @@ +package foo:foo; +interface foo { + use foo:some-dep/types.{some-type}; +} diff --git a/crates/wit-component/tests/interfaces/simple-deps/foo.wit.print b/crates/wit-component/tests/interfaces/simple-deps/foo.wit.print new file mode 100644 index 0000000000..66aa458716 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-deps/foo.wit.print @@ -0,0 +1,6 @@ +package foo:foo + +interface foo { + use foo:some-dep/types.{some-type} +} + diff --git a/crates/wit-component/tests/interfaces/simple-multi.wat b/crates/wit-component/tests/interfaces/simple-multi.wat new file mode 100644 index 0000000000..2a0222d1c9 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-multi.wat @@ -0,0 +1,18 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance) + ) + (export (;0;) (interface "foo:foo/bar") (instance (type 0))) + (type (;1;) + (instance) + ) + (export (;1;) (interface "foo:foo/foo") (instance (type 1))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/simple-multi/bar.wit b/crates/wit-component/tests/interfaces/simple-multi/bar.wit new file mode 100644 index 0000000000..4e0eb61bca --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-multi/bar.wit @@ -0,0 +1 @@ +interface bar {} diff --git a/crates/wit-component/tests/interfaces/simple-multi/foo.wit b/crates/wit-component/tests/interfaces/simple-multi/foo.wit new file mode 100644 index 0000000000..21bf4083a7 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-multi/foo.wit @@ -0,0 +1,3 @@ +package foo:foo; + +interface foo {} diff --git a/crates/wit-component/tests/interfaces/simple-multi/foo.wit.print b/crates/wit-component/tests/interfaces/simple-multi/foo.wit.print new file mode 100644 index 0000000000..985ae52f23 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-multi/foo.wit.print @@ -0,0 +1,8 @@ +package foo:foo + +interface bar { +} + +interface foo { +} + diff --git a/crates/wit-component/tests/interfaces/simple-use.wat b/crates/wit-component/tests/interfaces/simple-use.wat new file mode 100644 index 0000000000..caf6e5fe5e --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-use.wat @@ -0,0 +1,27 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (enum "info" "debug")) + (export (;1;) "level" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:foo/types") (instance (type 0))) + (alias export 0 "level" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "level" (type (eq 0))) + (type (;2;) (func (param "level" 1) (param "msg" string))) + (export (;0;) "log" (func (type 2))) + ) + ) + (export (;1;) (interface "foo:foo/console") (instance (type 2))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/simple-use.wit b/crates/wit-component/tests/interfaces/simple-use.wit new file mode 100644 index 0000000000..15cb990c80 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-use.wit @@ -0,0 +1,13 @@ +package foo:foo; + +interface types { + enum level { + info, + debug, + } +} + +interface console { + use types.{level}; + log: func(level: level, msg: string); +} diff --git a/crates/wit-component/tests/interfaces/simple-use.wit.print b/crates/wit-component/tests/interfaces/simple-use.wit.print new file mode 100644 index 0000000000..00b4d1e1cf --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-use.wit.print @@ -0,0 +1,15 @@ +package foo:foo + +interface types { + enum level { + info, + debug, + } +} + +interface console { + use types.{level} + + log: func(level: level, msg: string) +} + diff --git a/crates/wit-component/tests/interfaces/simple-world.wat b/crates/wit-component/tests/interfaces/simple-world.wat new file mode 100644 index 0000000000..1354327a4b --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-world.wat @@ -0,0 +1,29 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (func (param "arg" string))) + (export (;0;) "log" (func (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/console") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (func (param "arg" string))) + (export (;0;) "log" (func (type 0))) + ) + ) + (import (interface "foo:foo/console") (instance (;0;) (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/the-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/simple-world.wit b/crates/wit-component/tests/interfaces/simple-world.wit new file mode 100644 index 0000000000..e5459b8902 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-world.wit @@ -0,0 +1,9 @@ +package foo:foo; + +world the-world { + import console; +} + +interface console { + log: func(arg: string); +} diff --git a/crates/wit-component/tests/interfaces/simple-world.wit.print b/crates/wit-component/tests/interfaces/simple-world.wit.print new file mode 100644 index 0000000000..ef62499f08 --- /dev/null +++ b/crates/wit-component/tests/interfaces/simple-world.wit.print @@ -0,0 +1,9 @@ +package foo:foo + +interface console { + log: func(arg: string) +} + +world the-world { + import console +} diff --git a/crates/wit-component/tests/interfaces/single-named-result.wat b/crates/wit-component/tests/interfaces/single-named-result.wat new file mode 100644 index 0000000000..980b3361c1 --- /dev/null +++ b/crates/wit-component/tests/interfaces/single-named-result.wat @@ -0,0 +1,17 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (func (result "a" u32))) + (export (;0;) "a" (func (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/single-named-result.wit b/crates/wit-component/tests/interfaces/single-named-result.wit new file mode 100644 index 0000000000..980b766bc3 --- /dev/null +++ b/crates/wit-component/tests/interfaces/single-named-result.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface foo { + a: func() -> (a: u32); +} diff --git a/crates/wit-component/tests/interfaces/single-named-result.wit.print b/crates/wit-component/tests/interfaces/single-named-result.wit.print new file mode 100644 index 0000000000..fe78a21bc2 --- /dev/null +++ b/crates/wit-component/tests/interfaces/single-named-result.wit.print @@ -0,0 +1,6 @@ +package foo:foo + +interface foo { + a: func() -> (a: u32) +} + diff --git a/crates/wit-component/tests/interfaces/type-alias.wat b/crates/wit-component/tests/interfaces/type-alias.wat new file mode 100644 index 0000000000..23c38d4b38 --- /dev/null +++ b/crates/wit-component/tests/interfaces/type-alias.wat @@ -0,0 +1,45 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "a" (type (eq 0))) + (export (;2;) "b" (type (eq 1))) + (type (;3;) (func (param "a" 1) (result 2))) + (export (;0;) "f" (func (type 3))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "a" (type (eq 0))) + (export (;2;) "b" (type (eq 1))) + (type (;3;) (func (param "a" 1) (result 2))) + (export (;0;) "f" (func (type 3))) + ) + ) + (import (interface "foo:foo/foo") (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) u8) + (export (;1;) "a" (type (eq 0))) + (export (;2;) "b" (type (eq 1))) + (type (;3;) (func (param "a" 1) (result 2))) + (export (;0;) "f" (func (type 3))) + ) + ) + (export (;1;) (interface "foo:foo/foo") (instance (type 1))) + ) + ) + (export (;0;) (interface "foo:foo/my-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/type-alias.wit b/crates/wit-component/tests/interfaces/type-alias.wit new file mode 100644 index 0000000000..11bb6b2f8c --- /dev/null +++ b/crates/wit-component/tests/interfaces/type-alias.wit @@ -0,0 +1,13 @@ +package foo:foo; + +interface foo { + type a = u8; + type b = a; + + f: func(a: a) -> b; +} + +world my-world { + import foo; + export foo; +} diff --git a/crates/wit-component/tests/interfaces/type-alias.wit.print b/crates/wit-component/tests/interfaces/type-alias.wit.print new file mode 100644 index 0000000000..6d9300cc17 --- /dev/null +++ b/crates/wit-component/tests/interfaces/type-alias.wit.print @@ -0,0 +1,15 @@ +package foo:foo + +interface foo { + type a = u8 + + type b = a + + f: func(a: a) -> b +} + +world my-world { + import foo + + export foo +} diff --git a/crates/wit-component/tests/interfaces/type-alias2.wat b/crates/wit-component/tests/interfaces/type-alias2.wat new file mode 100644 index 0000000000..85d2d1f02c --- /dev/null +++ b/crates/wit-component/tests/interfaces/type-alias2.wat @@ -0,0 +1,35 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (flags "b")) + (export (;1;) "a" (type (eq 0))) + (export (;2;) "b" (type (eq 1))) + (type (;3;) (func (result 2))) + (export (;0;) "f" (func (type 3))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (flags "b")) + (export (;1;) "a" (type (eq 0))) + (export (;2;) "b" (type (eq 1))) + (type (;3;) (func (result 2))) + (export (;0;) "f" (func (type 3))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + ) + ) + (export (;0;) (interface "foo:foo/my-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/type-alias2.wit b/crates/wit-component/tests/interfaces/type-alias2.wit new file mode 100644 index 0000000000..5c8156fa38 --- /dev/null +++ b/crates/wit-component/tests/interfaces/type-alias2.wit @@ -0,0 +1,15 @@ +package foo:foo; + +interface foo { + flags a { + b, + } + + type b = a; + + f: func() -> b; +} + +world my-world { + export foo; +} diff --git a/crates/wit-component/tests/interfaces/type-alias2.wit.print b/crates/wit-component/tests/interfaces/type-alias2.wit.print new file mode 100644 index 0000000000..b3a3d3fc07 --- /dev/null +++ b/crates/wit-component/tests/interfaces/type-alias2.wit.print @@ -0,0 +1,15 @@ +package foo:foo + +interface foo { + flags a { + b, + } + + type b = a + + f: func() -> b +} + +world my-world { + export foo +} diff --git a/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat b/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat new file mode 100644 index 0000000000..22c03c3a08 --- /dev/null +++ b/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat @@ -0,0 +1,35 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "ty" (type (eq 0))) + ) + ) + (import (interface "foo:a/the-name") (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) u8) + (export (;1;) "ty" (type (eq 0))) + ) + ) + (import (interface "foo:b/the-name") (instance (;1;) (type 1))) + (alias export 0 "ty" (type (;2;))) + (alias export 1 "ty" (type (;3;))) + (type (;4;) + (instance + (alias outer 1 2 (type (;0;))) + (export (;1;) "ty" (type (eq 0))) + (alias outer 1 3 (type (;2;))) + (export (;3;) "ty2" (type (eq 2))) + ) + ) + (export (;2;) (interface "foo:foo/a") (instance (type 4))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/upstream-deps-same-name/deps/a/the-name.wit b/crates/wit-component/tests/interfaces/upstream-deps-same-name/deps/a/the-name.wit new file mode 100644 index 0000000000..38334b3f9b --- /dev/null +++ b/crates/wit-component/tests/interfaces/upstream-deps-same-name/deps/a/the-name.wit @@ -0,0 +1,4 @@ +package foo:a; +interface the-name { + type ty = u8; +} diff --git a/crates/wit-component/tests/interfaces/upstream-deps-same-name/deps/b/the-name.wit b/crates/wit-component/tests/interfaces/upstream-deps-same-name/deps/b/the-name.wit new file mode 100644 index 0000000000..ca32564da9 --- /dev/null +++ b/crates/wit-component/tests/interfaces/upstream-deps-same-name/deps/b/the-name.wit @@ -0,0 +1,4 @@ +package foo:b; +interface the-name { + type ty = u8; +} diff --git a/crates/wit-component/tests/interfaces/upstream-deps-same-name/foo.wit b/crates/wit-component/tests/interfaces/upstream-deps-same-name/foo.wit new file mode 100644 index 0000000000..3c8e180b55 --- /dev/null +++ b/crates/wit-component/tests/interfaces/upstream-deps-same-name/foo.wit @@ -0,0 +1,6 @@ +package foo:foo; + +interface a { + use foo:a/the-name.{ty}; + use foo:b/the-name.{ty as ty2}; +} diff --git a/crates/wit-component/tests/interfaces/upstream-deps-same-name/foo.wit.print b/crates/wit-component/tests/interfaces/upstream-deps-same-name/foo.wit.print new file mode 100644 index 0000000000..4f16d68b3e --- /dev/null +++ b/crates/wit-component/tests/interfaces/upstream-deps-same-name/foo.wit.print @@ -0,0 +1,7 @@ +package foo:foo + +interface a { + use foo:a/the-name.{ty} + use foo:b/the-name.{ty as ty2} +} + diff --git a/crates/wit-component/tests/interfaces/use-chain.wat b/crates/wit-component/tests/interfaces/use-chain.wat new file mode 100644 index 0000000000..e555b67a53 --- /dev/null +++ b/crates/wit-component/tests/interfaces/use-chain.wat @@ -0,0 +1,35 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "a" (type (eq 0))) + (export (;2;) "b" (type (eq 1))) + (export (;3;) "c" (type (eq 2))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + (alias export 0 "c" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "c" (type (eq 0))) + ) + ) + (export (;1;) (interface "foo:foo/bar") (instance (type 2))) + (alias export 1 "c" (type (;3;))) + (type (;4;) + (instance + (alias outer 1 3 (type (;0;))) + (export (;1;) "c" (type (eq 0))) + ) + ) + (export (;2;) (interface "foo:foo/baz") (instance (type 4))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/use-chain.wit b/crates/wit-component/tests/interfaces/use-chain.wit new file mode 100644 index 0000000000..11cab91bb8 --- /dev/null +++ b/crates/wit-component/tests/interfaces/use-chain.wit @@ -0,0 +1,15 @@ +package foo:foo; + +interface foo { + type a = u32; + type b = a; + type c = b; +} + +interface bar { + use foo.{c}; +} + +interface baz { + use bar.{c}; +} diff --git a/crates/wit-component/tests/interfaces/use-chain.wit.print b/crates/wit-component/tests/interfaces/use-chain.wit.print new file mode 100644 index 0000000000..fc19fb45ab --- /dev/null +++ b/crates/wit-component/tests/interfaces/use-chain.wit.print @@ -0,0 +1,18 @@ +package foo:foo + +interface foo { + type a = u32 + + type b = a + + type c = b +} + +interface bar { + use foo.{c} +} + +interface baz { + use bar.{c} +} + diff --git a/crates/wit-component/tests/interfaces/use-for-type.wat b/crates/wit-component/tests/interfaces/use-for-type.wat new file mode 100644 index 0000000000..dd19b86589 --- /dev/null +++ b/crates/wit-component/tests/interfaces/use-for-type.wat @@ -0,0 +1,31 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance) + ) + (export (;0;) (interface "foo:foo/foo") (instance (type 0))) + (type (;1;) + (instance + (type (;0;) u8) + (export (;1;) "t" (type (eq 0))) + ) + ) + (export (;1;) (interface "foo:foo/bar") (instance (type 1))) + (alias export 1 "t" (type (;2;))) + (type (;3;) + (instance + (alias outer 1 2 (type (;0;))) + (export (;1;) "t" (type (eq 0))) + (type (;2;) (record (field "a" 1))) + (export (;3;) "bar" (type (eq 2))) + ) + ) + (export (;2;) (interface "foo:foo/baz") (instance (type 3))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/use-for-type.wit b/crates/wit-component/tests/interfaces/use-for-type.wit new file mode 100644 index 0000000000..d090d61e74 --- /dev/null +++ b/crates/wit-component/tests/interfaces/use-for-type.wit @@ -0,0 +1,16 @@ +package foo:foo; + +interface foo { +} + +interface bar { + type t = u8; +} + +interface baz { + use bar.{t}; + + record bar { + a: t, + } +} diff --git a/crates/wit-component/tests/interfaces/use-for-type.wit.print b/crates/wit-component/tests/interfaces/use-for-type.wit.print new file mode 100644 index 0000000000..9659920938 --- /dev/null +++ b/crates/wit-component/tests/interfaces/use-for-type.wit.print @@ -0,0 +1,17 @@ +package foo:foo + +interface foo { +} + +interface bar { + type t = u8 +} + +interface baz { + use bar.{t} + + record bar { + a: t, + } +} + diff --git a/crates/wit-component/tests/interfaces/variants.wat b/crates/wit-component/tests/interfaces/variants.wat new file mode 100644 index 0000000000..a239f02a0c --- /dev/null +++ b/crates/wit-component/tests/interfaces/variants.wat @@ -0,0 +1,191 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (enum "a")) + (export (;1;) "e1" (type (eq 0))) + (type (;2;) (record (field "f" u8))) + (export (;3;) "single" (type (eq 2))) + (type (;4;) (variant (case "a") (case "c" 1) (case "d" string) (case "e" 3) (case "f") (case "g" u32))) + (export (;5;) "v1" (type (eq 4))) + (type (;6;) (variant (case "a" s32) (case "b" float32))) + (export (;7;) "casts1" (type (eq 6))) + (type (;8;) (variant (case "a" float64) (case "b" float32))) + (export (;9;) "casts2" (type (eq 8))) + (type (;10;) (variant (case "a" float64) (case "b" u64))) + (export (;11;) "casts3" (type (eq 10))) + (type (;12;) (variant (case "a" u32) (case "b" s64))) + (export (;13;) "casts4" (type (eq 12))) + (type (;14;) (variant (case "a" float32) (case "b" s64))) + (export (;15;) "casts5" (type (eq 14))) + (type (;16;) (tuple float32 u32)) + (type (;17;) (tuple u32 u32)) + (type (;18;) (variant (case "a" 16) (case "b" 17))) + (export (;19;) "casts6" (type (eq 18))) + (type (;20;) (enum "bad1" "bad2")) + (export (;21;) "my-errno" (type (eq 20))) + (type (;22;) (func (param "x" 1))) + (export (;0;) "e1-arg" (func (type 22))) + (type (;23;) (func (result 1))) + (export (;1;) "e1-result" (func (type 23))) + (type (;24;) (func (param "x" 5))) + (export (;2;) "v1-arg" (func (type 24))) + (type (;25;) (func (result 5))) + (export (;3;) "v1-result" (func (type 25))) + (type (;26;) (func (param "x" bool))) + (export (;4;) "bool-arg" (func (type 26))) + (type (;27;) (func (result bool))) + (export (;5;) "bool-result" (func (type 27))) + (type (;28;) (option bool)) + (type (;29;) (tuple u32)) + (type (;30;) (option 29)) + (type (;31;) (option u32)) + (type (;32;) (option 1)) + (type (;33;) (option float32)) + (type (;34;) (option 28)) + (type (;35;) (func (param "a" 28) (param "b" 30) (param "c" 31) (param "d" 32) (param "e" 33) (param "g" 34))) + (export (;6;) "option-arg" (func (type 35))) + (type (;36;) (tuple 28 30 31 32 33 34)) + (type (;37;) (func (result 36))) + (export (;7;) "option-result" (func (type 37))) + (type (;38;) (tuple 7 9 11 13 15 19)) + (type (;39;) (func (param "a" 7) (param "b" 9) (param "c" 11) (param "d" 13) (param "e" 15) (param "f" 19) (result 38))) + (export (;8;) "casts" (func (type 39))) + (type (;40;) (result)) + (type (;41;) (result (error 1))) + (type (;42;) (result 1)) + (type (;43;) (result 29 (error 29))) + (type (;44;) (result u32 (error 5))) + (type (;45;) (list u8)) + (type (;46;) (result string (error 45))) + (type (;47;) (func (param "a" 40) (param "b" 41) (param "c" 42) (param "d" 43) (param "e" 44) (param "f" 46))) + (export (;9;) "expected-arg" (func (type 47))) + (type (;48;) (tuple 40 41 42 43 44 46)) + (type (;49;) (func (result 48))) + (export (;10;) "expected-result" (func (type 49))) + (type (;50;) (result s32 (error 21))) + (type (;51;) (func (result 50))) + (export (;11;) "return-expected-sugar" (func (type 51))) + (type (;52;) (result (error 21))) + (type (;53;) (func (result 52))) + (export (;12;) "return-expected-sugar2" (func (type 53))) + (type (;54;) (result 21 (error 21))) + (type (;55;) (func (result 54))) + (export (;13;) "return-expected-sugar3" (func (type 55))) + (type (;56;) (tuple s32 u32)) + (type (;57;) (result 56 (error 21))) + (type (;58;) (func (result 57))) + (export (;14;) "return-expected-sugar4" (func (type 58))) + (type (;59;) (option s32)) + (type (;60;) (func (result 59))) + (export (;15;) "return-option-sugar" (func (type 60))) + (type (;61;) (option 21)) + (type (;62;) (func (result 61))) + (export (;16;) "return-option-sugar2" (func (type 62))) + (type (;63;) (result u32 (error s32))) + (type (;64;) (func (result 63))) + (export (;17;) "expected-simple" (func (type 64))) + ) + ) + (export (;0;) (interface "foo:variants/variants") (instance (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (enum "a")) + (export (;1;) "e1" (type (eq 0))) + (type (;2;) (record (field "f" u8))) + (export (;3;) "single" (type (eq 2))) + (type (;4;) (variant (case "a") (case "c" 1) (case "d" string) (case "e" 3) (case "f") (case "g" u32))) + (export (;5;) "v1" (type (eq 4))) + (type (;6;) (variant (case "a" s32) (case "b" float32))) + (export (;7;) "casts1" (type (eq 6))) + (type (;8;) (variant (case "a" float64) (case "b" float32))) + (export (;9;) "casts2" (type (eq 8))) + (type (;10;) (variant (case "a" float64) (case "b" u64))) + (export (;11;) "casts3" (type (eq 10))) + (type (;12;) (variant (case "a" u32) (case "b" s64))) + (export (;13;) "casts4" (type (eq 12))) + (type (;14;) (variant (case "a" float32) (case "b" s64))) + (export (;15;) "casts5" (type (eq 14))) + (type (;16;) (tuple float32 u32)) + (type (;17;) (tuple u32 u32)) + (type (;18;) (variant (case "a" 16) (case "b" 17))) + (export (;19;) "casts6" (type (eq 18))) + (type (;20;) (enum "bad1" "bad2")) + (export (;21;) "my-errno" (type (eq 20))) + (type (;22;) (func (param "x" 1))) + (export (;0;) "e1-arg" (func (type 22))) + (type (;23;) (func (result 1))) + (export (;1;) "e1-result" (func (type 23))) + (type (;24;) (func (param "x" 5))) + (export (;2;) "v1-arg" (func (type 24))) + (type (;25;) (func (result 5))) + (export (;3;) "v1-result" (func (type 25))) + (type (;26;) (func (param "x" bool))) + (export (;4;) "bool-arg" (func (type 26))) + (type (;27;) (func (result bool))) + (export (;5;) "bool-result" (func (type 27))) + (type (;28;) (option bool)) + (type (;29;) (tuple u32)) + (type (;30;) (option 29)) + (type (;31;) (option u32)) + (type (;32;) (option 1)) + (type (;33;) (option float32)) + (type (;34;) (option 28)) + (type (;35;) (func (param "a" 28) (param "b" 30) (param "c" 31) (param "d" 32) (param "e" 33) (param "g" 34))) + (export (;6;) "option-arg" (func (type 35))) + (type (;36;) (tuple 28 30 31 32 33 34)) + (type (;37;) (func (result 36))) + (export (;7;) "option-result" (func (type 37))) + (type (;38;) (tuple 7 9 11 13 15 19)) + (type (;39;) (func (param "a" 7) (param "b" 9) (param "c" 11) (param "d" 13) (param "e" 15) (param "f" 19) (result 38))) + (export (;8;) "casts" (func (type 39))) + (type (;40;) (result)) + (type (;41;) (result (error 1))) + (type (;42;) (result 1)) + (type (;43;) (result 29 (error 29))) + (type (;44;) (result u32 (error 5))) + (type (;45;) (list u8)) + (type (;46;) (result string (error 45))) + (type (;47;) (func (param "a" 40) (param "b" 41) (param "c" 42) (param "d" 43) (param "e" 44) (param "f" 46))) + (export (;9;) "expected-arg" (func (type 47))) + (type (;48;) (tuple 40 41 42 43 44 46)) + (type (;49;) (func (result 48))) + (export (;10;) "expected-result" (func (type 49))) + (type (;50;) (result s32 (error 21))) + (type (;51;) (func (result 50))) + (export (;11;) "return-expected-sugar" (func (type 51))) + (type (;52;) (result (error 21))) + (type (;53;) (func (result 52))) + (export (;12;) "return-expected-sugar2" (func (type 53))) + (type (;54;) (result 21 (error 21))) + (type (;55;) (func (result 54))) + (export (;13;) "return-expected-sugar3" (func (type 55))) + (type (;56;) (tuple s32 u32)) + (type (;57;) (result 56 (error 21))) + (type (;58;) (func (result 57))) + (export (;14;) "return-expected-sugar4" (func (type 58))) + (type (;59;) (option s32)) + (type (;60;) (func (result 59))) + (export (;15;) "return-option-sugar" (func (type 60))) + (type (;61;) (option 21)) + (type (;62;) (func (result 61))) + (export (;16;) "return-option-sugar2" (func (type 62))) + (type (;63;) (result u32 (error s32))) + (type (;64;) (func (result 63))) + (export (;17;) "expected-simple" (func (type 64))) + ) + ) + (import (interface "foo:variants/variants") (instance (;0;) (type 0))) + ) + ) + (export (;0;) (interface "foo:variants/variants-world") (component (type 1))) + ) + ) + (export (;1;) (interface "foo:variants/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/variants.wit b/crates/wit-component/tests/interfaces/variants.wit new file mode 100644 index 0000000000..f0374769f1 --- /dev/null +++ b/crates/wit-component/tests/interfaces/variants.wit @@ -0,0 +1,78 @@ +package foo:variants; + +interface variants { + enum e1 { + a, + } + + record single { + f: u8, + } + + variant v1 { + a, + c(e1), + d(string), + e(single), + f, + g(u32), + } + + variant casts1 { + a(s32), + b(float32), + } + + variant casts2 { + a(float64), + b(float32), + } + + variant casts3 { + a(float64), + b(u64), + } + + variant casts4 { + a(u32), + b(s64), + } + + variant casts5 { + a(float32), + b(s64), + } + + variant casts6 { + a(tuple), + b(tuple), + } + + enum my-errno { + bad1, + bad2, + } + + e1-arg: func(x: e1); + e1-result: func() -> e1; + v1-arg: func(x: v1); + v1-result: func() -> v1; + bool-arg: func(x: bool); + bool-result: func() -> bool; + option-arg: func(a: option, b: option>, c: option, d: option, e: option, g: option>); + option-result: func() -> tuple, option>, option, option, option, option>>; + casts: func(a: casts1, b: casts2, c: casts3, d: casts4, e: casts5, f: casts6) -> tuple; + expected-arg: func(a: result, b: result<_, e1>, c: result, d: result, tuple>, e: result, f: result>); + expected-result: func() -> tuple, result, result, tuple>, result, result>>; + return-expected-sugar: func() -> result; + return-expected-sugar2: func() -> result<_, my-errno>; + return-expected-sugar3: func() -> result; + return-expected-sugar4: func() -> result, my-errno>; + return-option-sugar: func() -> option; + return-option-sugar2: func() -> option; + expected-simple: func() -> result; +} + +world variants-world { + import variants; +} diff --git a/crates/wit-component/tests/interfaces/variants.wit.print b/crates/wit-component/tests/interfaces/variants.wit.print new file mode 100644 index 0000000000..f41e19a01b --- /dev/null +++ b/crates/wit-component/tests/interfaces/variants.wit.print @@ -0,0 +1,95 @@ +package foo:variants + +interface variants { + enum e1 { + a, + } + + record single { + f: u8, + } + + variant v1 { + a, + c(e1), + d(string), + e(single), + f, + g(u32), + } + + variant casts1 { + a(s32), + b(float32), + } + + variant casts2 { + a(float64), + b(float32), + } + + variant casts3 { + a(float64), + b(u64), + } + + variant casts4 { + a(u32), + b(s64), + } + + variant casts5 { + a(float32), + b(s64), + } + + variant casts6 { + a(tuple), + b(tuple), + } + + enum my-errno { + bad1, + bad2, + } + + e1-arg: func(x: e1) + + e1-result: func() -> e1 + + v1-arg: func(x: v1) + + v1-result: func() -> v1 + + bool-arg: func(x: bool) + + bool-result: func() -> bool + + option-arg: func(a: option, b: option>, c: option, d: option, e: option, g: option>) + + option-result: func() -> tuple, option>, option, option, option, option>> + + casts: func(a: casts1, b: casts2, c: casts3, d: casts4, e: casts5, f: casts6) -> tuple + + expected-arg: func(a: result, b: result<_, e1>, c: result, d: result, tuple>, e: result, f: result>) + + expected-result: func() -> tuple, result, result, tuple>, result, result>> + + return-expected-sugar: func() -> result + + return-expected-sugar2: func() -> result<_, my-errno> + + return-expected-sugar3: func() -> result + + return-expected-sugar4: func() -> result, my-errno> + + return-option-sugar: func() -> option + + return-option-sugar2: func() -> option + + expected-simple: func() -> result +} + +world variants-world { + import variants +} diff --git a/crates/wit-component/tests/interfaces/wasi-http.wat b/crates/wit-component/tests/interfaces/wasi-http.wat new file mode 100644 index 0000000000..6442487648 --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http.wat @@ -0,0 +1,410 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "pollable" (type (eq 0))) + ) + ) + (import (interface "wasi:poll/poll") (instance (;0;) (type 0))) + (alias export 0 "pollable" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "pollable" (type (eq 0))) + (type (;2;) (record (field "f" u8))) + (export (;3;) "stream-error" (type (eq 2))) + (type (;4;) u32) + (export (;5;) "input-stream" (type (eq 4))) + (type (;6;) u32) + (export (;7;) "output-stream" (type (eq 6))) + ) + ) + (import (interface "wasi:io/streams") (instance (;1;) (type 2))) + (alias export 1 "input-stream" (type (;3;))) + (alias export 1 "output-stream" (type (;4;))) + (type (;5;) + (instance + (alias outer 1 3 (type (;0;))) + (export (;1;) "input-stream" (type (eq 0))) + (alias outer 1 4 (type (;2;))) + (export (;3;) "output-stream" (type (eq 2))) + (alias outer 1 1 (type (;4;))) + (export (;5;) "pollable" (type (eq 4))) + (type (;6;) (variant (case "get") (case "head") (case "post") (case "put") (case "delete") (case "connect") (case "options") (case "trace") (case "patch") (case "other" string))) + (export (;7;) "method" (type (eq 6))) + (type (;8;) (variant (case "HTTP") (case "HTTPS") (case "other" string))) + (export (;9;) "scheme" (type (eq 8))) + (type (;10;) (variant (case "invalid-url" string) (case "timeout-error" string) (case "protocol-error" string) (case "unexpected-error" string))) + (export (;11;) "error" (type (eq 10))) + (type (;12;) u32) + (export (;13;) "fields" (type (eq 12))) + (export (;14;) "headers" (type (eq 13))) + (export (;15;) "trailers" (type (eq 13))) + (export (;16;) "incoming-stream" (type (eq 1))) + (export (;17;) "outgoing-stream" (type (eq 3))) + (type (;18;) u32) + (export (;19;) "incoming-request" (type (eq 18))) + (type (;20;) u32) + (export (;21;) "outgoing-request" (type (eq 20))) + (type (;22;) (option u32)) + (type (;23;) (record (field "connect-timeout-ms" 22) (field "first-byte-timeout-ms" 22) (field "between-bytes-timeout-ms" 22))) + (export (;24;) "request-options" (type (eq 23))) + (type (;25;) u32) + (export (;26;) "response-outparam" (type (eq 25))) + (type (;27;) u16) + (export (;28;) "status-code" (type (eq 27))) + (type (;29;) u32) + (export (;30;) "incoming-response" (type (eq 29))) + (type (;31;) u32) + (export (;32;) "outgoing-response" (type (eq 31))) + (type (;33;) u32) + (export (;34;) "future-incoming-response" (type (eq 33))) + (type (;35;) (func (param "fields" 13))) + (export (;0;) "drop-fields" (func (type 35))) + (type (;36;) (tuple string string)) + (type (;37;) (list 36)) + (type (;38;) (func (param "entries" 37) (result 13))) + (export (;1;) "new-fields" (func (type 38))) + (type (;39;) (list string)) + (type (;40;) (func (param "fields" 13) (param "name" string) (result 39))) + (export (;2;) "fields-get" (func (type 40))) + (type (;41;) (func (param "fields" 13) (param "name" string) (param "value" 39))) + (export (;3;) "fields-set" (func (type 41))) + (type (;42;) (func (param "fields" 13) (param "name" string))) + (export (;4;) "fields-delete" (func (type 42))) + (type (;43;) (func (param "fields" 13) (param "name" string) (param "value" string))) + (export (;5;) "fields-append" (func (type 43))) + (type (;44;) (func (param "fields" 13) (result 37))) + (export (;6;) "fields-entries" (func (type 44))) + (type (;45;) (func (param "fields" 13) (result 13))) + (export (;7;) "fields-clone" (func (type 45))) + (type (;46;) (option 15)) + (type (;47;) (func (param "s" 16) (result 46))) + (export (;8;) "finish-incoming-stream" (func (type 47))) + (type (;48;) (func (param "s" 17) (param "trailers" 46))) + (export (;9;) "finish-outgoing-stream" (func (type 48))) + (type (;49;) (func (param "request" 19))) + (export (;10;) "drop-incoming-request" (func (type 49))) + (type (;50;) (func (param "request" 21))) + (export (;11;) "drop-outgoing-request" (func (type 50))) + (type (;51;) (func (param "request" 19) (result 7))) + (export (;12;) "incoming-request-method" (func (type 51))) + (type (;52;) (func (param "request" 19) (result string))) + (export (;13;) "incoming-request-path" (func (type 52))) + (export (;14;) "incoming-request-query" (func (type 52))) + (type (;53;) (option 9)) + (type (;54;) (func (param "request" 19) (result 53))) + (export (;15;) "incoming-request-scheme" (func (type 54))) + (export (;16;) "incoming-request-authority" (func (type 52))) + (type (;55;) (func (param "request" 19) (result 14))) + (export (;17;) "incoming-request-headers" (func (type 55))) + (type (;56;) (result 16)) + (type (;57;) (func (param "request" 19) (result 56))) + (export (;18;) "incoming-request-consume" (func (type 57))) + (type (;58;) (func (param "method" 7) (param "path" string) (param "query" string) (param "scheme" 53) (param "authority" string) (param "headers" 14) (result 21))) + (export (;19;) "new-outgoing-request" (func (type 58))) + (type (;59;) (result 17)) + (type (;60;) (func (param "request" 21) (result 59))) + (export (;20;) "outgoing-request-write" (func (type 60))) + (type (;61;) (func (param "response" 26))) + (export (;21;) "drop-response-outparam" (func (type 61))) + (type (;62;) (result 32 (error 11))) + (type (;63;) (result)) + (type (;64;) (func (param "param" 26) (param "response" 62) (result 63))) + (export (;22;) "set-response-outparam" (func (type 64))) + (type (;65;) (func (param "response" 30))) + (export (;23;) "drop-incoming-response" (func (type 65))) + (type (;66;) (func (param "response" 32))) + (export (;24;) "drop-outgoing-response" (func (type 66))) + (type (;67;) (func (param "response" 30) (result 28))) + (export (;25;) "incoming-response-status" (func (type 67))) + (type (;68;) (func (param "response" 30) (result 14))) + (export (;26;) "incoming-response-headers" (func (type 68))) + (type (;69;) (func (param "response" 30) (result 56))) + (export (;27;) "incoming-response-consume" (func (type 69))) + (type (;70;) (func (param "status-code" 28) (param "headers" 14) (result 32))) + (export (;28;) "new-outgoing-response" (func (type 70))) + (type (;71;) (func (param "response" 32) (result 59))) + (export (;29;) "outgoing-response-write" (func (type 71))) + (type (;72;) (func (param "f" 34))) + (export (;30;) "drop-future-incoming-response" (func (type 72))) + (type (;73;) (result 30 (error 11))) + (type (;74;) (option 73)) + (type (;75;) (func (param "f" 34) (result 74))) + (export (;31;) "future-incoming-response-get" (func (type 75))) + (type (;76;) (func (param "f" 34) (result 5))) + (export (;32;) "listen-to-future-incoming-response" (func (type 76))) + ) + ) + (export (;2;) (interface "wasi:http/types") (instance (type 5))) + (alias export 2 "incoming-request" (type (;6;))) + (alias export 2 "response-outparam" (type (;7;))) + (type (;8;) + (instance + (alias outer 1 6 (type (;0;))) + (export (;1;) "incoming-request" (type (eq 0))) + (alias outer 1 7 (type (;2;))) + (export (;3;) "response-outparam" (type (eq 2))) + (type (;4;) (func (param "request" 1) (param "response-out" 3))) + (export (;0;) "handle" (func (type 4))) + ) + ) + (export (;3;) (interface "wasi:http/incoming-handler") (instance (type 8))) + (alias export 2 "outgoing-request" (type (;9;))) + (alias export 2 "request-options" (type (;10;))) + (alias export 2 "future-incoming-response" (type (;11;))) + (type (;12;) + (instance + (alias outer 1 9 (type (;0;))) + (export (;1;) "outgoing-request" (type (eq 0))) + (alias outer 1 10 (type (;2;))) + (export (;3;) "request-options" (type (eq 2))) + (alias outer 1 11 (type (;4;))) + (export (;5;) "future-incoming-response" (type (eq 4))) + (type (;6;) (option 3)) + (type (;7;) (func (param "request" 1) (param "options" 6) (result 5))) + (export (;0;) "handle" (func (type 7))) + ) + ) + (export (;4;) (interface "wasi:http/outgoing-handler") (instance (type 12))) + (type (;13;) + (component + (type (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (func (param "len" u64) (result 0))) + (export (;0;) "get-random-bytes" (func (type 1))) + (type (;2;) (func (result u64))) + (export (;1;) "get-random-u64" (func (type 2))) + (type (;3;) (tuple u64 u64)) + (type (;4;) (func (result 3))) + (export (;2;) "insecure-random" (func (type 4))) + ) + ) + (import (interface "wasi:random/random") (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (enum "trace" "debug" "info" "warn" "error")) + (export (;1;) "level" (type (eq 0))) + (type (;2;) (func (param "level" 1) (param "context" string) (param "message" string))) + (export (;0;) "log" (func (type 2))) + ) + ) + (import (interface "wasi:logging/handler") (instance (;1;) (type 1))) + (type (;2;) + (instance + (type (;0;) u32) + (export (;1;) "pollable" (type (eq 0))) + (type (;2;) (func (param "this" 1))) + (export (;0;) "drop-pollable" (func (type 2))) + (type (;3;) (list 1)) + (type (;4;) (list u8)) + (type (;5;) (func (param "in" 3) (result 4))) + (export (;1;) "poll-oneoff" (func (type 5))) + ) + ) + (import (interface "wasi:poll/poll") (instance (;2;) (type 2))) + (alias export 2 "pollable" (type (;3;))) + (type (;4;) + (instance + (alias outer 1 3 (type (;0;))) + (export (;1;) "pollable" (type (eq 0))) + (type (;2;) (record (field "f" u8))) + (export (;3;) "stream-error" (type (eq 2))) + (type (;4;) u32) + (export (;5;) "input-stream" (type (eq 4))) + (type (;6;) u32) + (export (;7;) "output-stream" (type (eq 6))) + (type (;8;) (list u8)) + (type (;9;) (tuple 8 bool)) + (type (;10;) (result 9 (error 3))) + (type (;11;) (func (param "this" 5) (param "len" u64) (result 10))) + (export (;0;) "read" (func (type 11))) + (export (;1;) "blocking-read" (func (type 11))) + (type (;12;) (tuple u64 bool)) + (type (;13;) (result 12 (error 3))) + (type (;14;) (func (param "this" 5) (param "len" u64) (result 13))) + (export (;2;) "skip" (func (type 14))) + (export (;3;) "blocking-skip" (func (type 14))) + (type (;15;) (func (param "this" 5) (result 1))) + (export (;4;) "subscribe-to-input-stream" (func (type 15))) + (type (;16;) (func (param "this" 5))) + (export (;5;) "drop-input-stream" (func (type 16))) + (type (;17;) (result u64 (error 3))) + (type (;18;) (func (param "this" 7) (param "buf" 8) (result 17))) + (export (;6;) "write" (func (type 18))) + (export (;7;) "blocking-write" (func (type 18))) + (type (;19;) (func (param "this" 7) (param "len" u64) (result 17))) + (export (;8;) "write-zeroes" (func (type 19))) + (export (;9;) "blocking-write-zeroes" (func (type 19))) + (type (;20;) (func (param "this" 7) (param "src" 5) (param "len" u64) (result 13))) + (export (;10;) "splice" (func (type 20))) + (export (;11;) "blocking-splice" (func (type 20))) + (type (;21;) (func (param "this" 7) (param "src" 5) (result 17))) + (export (;12;) "forward" (func (type 21))) + (type (;22;) (func (param "this" 7) (result 1))) + (export (;13;) "subscribe-to-output-stream" (func (type 22))) + (type (;23;) (func (param "this" 7))) + (export (;14;) "drop-output-stream" (func (type 23))) + ) + ) + (import (interface "wasi:io/streams") (instance (;3;) (type 4))) + (alias export 3 "input-stream" (type (;5;))) + (alias export 3 "output-stream" (type (;6;))) + (type (;7;) + (instance + (alias outer 1 5 (type (;0;))) + (export (;1;) "input-stream" (type (eq 0))) + (alias outer 1 6 (type (;2;))) + (export (;3;) "output-stream" (type (eq 2))) + (alias outer 1 3 (type (;4;))) + (export (;5;) "pollable" (type (eq 4))) + (type (;6;) (variant (case "get") (case "head") (case "post") (case "put") (case "delete") (case "connect") (case "options") (case "trace") (case "patch") (case "other" string))) + (export (;7;) "method" (type (eq 6))) + (type (;8;) (variant (case "HTTP") (case "HTTPS") (case "other" string))) + (export (;9;) "scheme" (type (eq 8))) + (type (;10;) (variant (case "invalid-url" string) (case "timeout-error" string) (case "protocol-error" string) (case "unexpected-error" string))) + (export (;11;) "error" (type (eq 10))) + (type (;12;) u32) + (export (;13;) "fields" (type (eq 12))) + (export (;14;) "headers" (type (eq 13))) + (export (;15;) "trailers" (type (eq 13))) + (export (;16;) "incoming-stream" (type (eq 1))) + (export (;17;) "outgoing-stream" (type (eq 3))) + (type (;18;) u32) + (export (;19;) "incoming-request" (type (eq 18))) + (type (;20;) u32) + (export (;21;) "outgoing-request" (type (eq 20))) + (type (;22;) (option u32)) + (type (;23;) (record (field "connect-timeout-ms" 22) (field "first-byte-timeout-ms" 22) (field "between-bytes-timeout-ms" 22))) + (export (;24;) "request-options" (type (eq 23))) + (type (;25;) u32) + (export (;26;) "response-outparam" (type (eq 25))) + (type (;27;) u16) + (export (;28;) "status-code" (type (eq 27))) + (type (;29;) u32) + (export (;30;) "incoming-response" (type (eq 29))) + (type (;31;) u32) + (export (;32;) "outgoing-response" (type (eq 31))) + (type (;33;) u32) + (export (;34;) "future-incoming-response" (type (eq 33))) + (type (;35;) (func (param "fields" 13))) + (export (;0;) "drop-fields" (func (type 35))) + (type (;36;) (tuple string string)) + (type (;37;) (list 36)) + (type (;38;) (func (param "entries" 37) (result 13))) + (export (;1;) "new-fields" (func (type 38))) + (type (;39;) (list string)) + (type (;40;) (func (param "fields" 13) (param "name" string) (result 39))) + (export (;2;) "fields-get" (func (type 40))) + (type (;41;) (func (param "fields" 13) (param "name" string) (param "value" 39))) + (export (;3;) "fields-set" (func (type 41))) + (type (;42;) (func (param "fields" 13) (param "name" string))) + (export (;4;) "fields-delete" (func (type 42))) + (type (;43;) (func (param "fields" 13) (param "name" string) (param "value" string))) + (export (;5;) "fields-append" (func (type 43))) + (type (;44;) (func (param "fields" 13) (result 37))) + (export (;6;) "fields-entries" (func (type 44))) + (type (;45;) (func (param "fields" 13) (result 13))) + (export (;7;) "fields-clone" (func (type 45))) + (type (;46;) (option 15)) + (type (;47;) (func (param "s" 16) (result 46))) + (export (;8;) "finish-incoming-stream" (func (type 47))) + (type (;48;) (func (param "s" 17) (param "trailers" 46))) + (export (;9;) "finish-outgoing-stream" (func (type 48))) + (type (;49;) (func (param "request" 19))) + (export (;10;) "drop-incoming-request" (func (type 49))) + (type (;50;) (func (param "request" 21))) + (export (;11;) "drop-outgoing-request" (func (type 50))) + (type (;51;) (func (param "request" 19) (result 7))) + (export (;12;) "incoming-request-method" (func (type 51))) + (type (;52;) (func (param "request" 19) (result string))) + (export (;13;) "incoming-request-path" (func (type 52))) + (export (;14;) "incoming-request-query" (func (type 52))) + (type (;53;) (option 9)) + (type (;54;) (func (param "request" 19) (result 53))) + (export (;15;) "incoming-request-scheme" (func (type 54))) + (export (;16;) "incoming-request-authority" (func (type 52))) + (type (;55;) (func (param "request" 19) (result 14))) + (export (;17;) "incoming-request-headers" (func (type 55))) + (type (;56;) (result 16)) + (type (;57;) (func (param "request" 19) (result 56))) + (export (;18;) "incoming-request-consume" (func (type 57))) + (type (;58;) (func (param "method" 7) (param "path" string) (param "query" string) (param "scheme" 53) (param "authority" string) (param "headers" 14) (result 21))) + (export (;19;) "new-outgoing-request" (func (type 58))) + (type (;59;) (result 17)) + (type (;60;) (func (param "request" 21) (result 59))) + (export (;20;) "outgoing-request-write" (func (type 60))) + (type (;61;) (func (param "response" 26))) + (export (;21;) "drop-response-outparam" (func (type 61))) + (type (;62;) (result 32 (error 11))) + (type (;63;) (result)) + (type (;64;) (func (param "param" 26) (param "response" 62) (result 63))) + (export (;22;) "set-response-outparam" (func (type 64))) + (type (;65;) (func (param "response" 30))) + (export (;23;) "drop-incoming-response" (func (type 65))) + (type (;66;) (func (param "response" 32))) + (export (;24;) "drop-outgoing-response" (func (type 66))) + (type (;67;) (func (param "response" 30) (result 28))) + (export (;25;) "incoming-response-status" (func (type 67))) + (type (;68;) (func (param "response" 30) (result 14))) + (export (;26;) "incoming-response-headers" (func (type 68))) + (type (;69;) (func (param "response" 30) (result 56))) + (export (;27;) "incoming-response-consume" (func (type 69))) + (type (;70;) (func (param "status-code" 28) (param "headers" 14) (result 32))) + (export (;28;) "new-outgoing-response" (func (type 70))) + (type (;71;) (func (param "response" 32) (result 59))) + (export (;29;) "outgoing-response-write" (func (type 71))) + (type (;72;) (func (param "f" 34))) + (export (;30;) "drop-future-incoming-response" (func (type 72))) + (type (;73;) (result 30 (error 11))) + (type (;74;) (option 73)) + (type (;75;) (func (param "f" 34) (result 74))) + (export (;31;) "future-incoming-response-get" (func (type 75))) + (type (;76;) (func (param "f" 34) (result 5))) + (export (;32;) "listen-to-future-incoming-response" (func (type 76))) + ) + ) + (import (interface "wasi:http/types") (instance (;4;) (type 7))) + (alias export 4 "outgoing-request" (type (;8;))) + (alias export 4 "request-options" (type (;9;))) + (alias export 4 "future-incoming-response" (type (;10;))) + (type (;11;) + (instance + (alias outer 1 8 (type (;0;))) + (export (;1;) "outgoing-request" (type (eq 0))) + (alias outer 1 9 (type (;2;))) + (export (;3;) "request-options" (type (eq 2))) + (alias outer 1 10 (type (;4;))) + (export (;5;) "future-incoming-response" (type (eq 4))) + (type (;6;) (option 3)) + (type (;7;) (func (param "request" 1) (param "options" 6) (result 5))) + (export (;0;) "handle" (func (type 7))) + ) + ) + (import (interface "wasi:http/outgoing-handler") (instance (;5;) (type 11))) + (alias export 4 "incoming-request" (type (;12;))) + (alias export 4 "response-outparam" (type (;13;))) + (type (;14;) + (instance + (alias outer 1 12 (type (;0;))) + (export (;1;) "incoming-request" (type (eq 0))) + (alias outer 1 13 (type (;2;))) + (export (;3;) "response-outparam" (type (eq 2))) + (type (;4;) (func (param "request" 1) (param "response-out" 3))) + (export (;0;) "handle" (func (type 4))) + ) + ) + (export (;6;) (interface "wasi:http/incoming-handler") (instance (type 14))) + ) + ) + (export (;0;) (interface "wasi:http/proxy") (component (type 13))) + ) + ) + (export (;1;) (interface "wasi:http/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/wasi-http/deps/io/streams.wit b/crates/wit-component/tests/interfaces/wasi-http/deps/io/streams.wit new file mode 100644 index 0000000000..56bf8f8201 --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/deps/io/streams.wit @@ -0,0 +1,217 @@ +package wasi:io; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +interface streams { + use wasi:poll/poll.{pollable}; + + /// An error type returned from a stream operation. Currently this + /// doesn't provide any additional information. + record stream-error { + f: u8, + } + + /// An input bytestream. In the future, this will be replaced by handle + /// types. + /// + /// This conceptually represents a `stream`. It's temporary + /// scaffolding until component-model's async features are ready. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe-to-input-stream` function to obtain a `pollable` which + /// can be polled for using `wasi_poll`. + /// + /// And at present, it is a `u32` instead of being an actual handle, until + /// the wit-bindgen implementation of handles and resources is ready. + /// + /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). + type input-stream = u32; + + /// Read bytes from a stream. + /// + /// This function returns a list of bytes containing the data that was + /// read, along with a bool which, when true, indicates that the end of the + /// stream was reached. The returned list will contain up to `len` bytes; it + /// may return fewer than requested, but not more. + /// + /// Once a stream has reached the end, subsequent calls to read or + /// `skip` will always report end-of-stream rather than producing more + /// data. + /// + /// If `len` is 0, it represents a request to read 0 bytes, which should + /// always succeed, assuming the stream hasn't reached its end yet, and + /// return an empty list. + /// + /// The len here is a `u64`, but some callees may not be able to allocate + /// a buffer as large as that would imply. + /// FIXME: describe what happens if allocation fails. + read: func( + this: input-stream, + /// The maximum number of bytes to read + len: u64 + ) -> result, bool>, stream-error>; + + /// Read bytes from a stream, with blocking. + /// + /// This is similar to `read`, except that it blocks until at least one + /// byte can be read. + blocking-read: func( + this: input-stream, + /// The maximum number of bytes to read + len: u64 + ) -> result, bool>, stream-error>; + + /// Skip bytes from a stream. + /// + /// This is similar to the `read` function, but avoids copying the + /// bytes into the instance. + /// + /// Once a stream has reached the end, subsequent calls to read or + /// `skip` will always report end-of-stream rather than producing more + /// data. + /// + /// This function returns the number of bytes skipped, along with a bool + /// indicating whether the end of the stream was reached. The returned + /// value will be at most `len`; it may be less. + skip: func( + this: input-stream, + /// The maximum number of bytes to skip. + len: u64, + ) -> result, stream-error>; + + /// Skip bytes from a stream, with blocking. + /// + /// This is similar to `skip`, except that it blocks until at least one + /// byte can be consumed. + blocking-skip: func( + this: input-stream, + /// The maximum number of bytes to skip. + len: u64, + ) -> result, stream-error>; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + subscribe-to-input-stream: func(this: input-stream) -> pollable; + + /// Dispose of the specified `input-stream`, after which it may no longer + /// be used. + drop-input-stream: func(this: input-stream); + + /// An output bytestream. In the future, this will be replaced by handle + /// types. + /// + /// This conceptually represents a `stream`. It's temporary + /// scaffolding until component-model's async features are ready. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe-to-output-stream` function to obtain a + /// `pollable` which can be polled for using `wasi_poll`. + /// + /// And at present, it is a `u32` instead of being an actual handle, until + /// the wit-bindgen implementation of handles and resources is ready. + /// + /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). + type output-stream = u32; + + /// Write bytes to a stream. + /// + /// This function returns a `u64` indicating the number of bytes from + /// `buf` that were written; it may be less than the full list. + write: func( + this: output-stream, + /// Data to write + buf: list + ) -> result; + + /// Write bytes to a stream, with blocking. + /// + /// This is similar to `write`, except that it blocks until at least one + /// byte can be written. + blocking-write: func( + this: output-stream, + /// Data to write + buf: list + ) -> result; + + /// Write multiple zero bytes to a stream. + /// + /// This function returns a `u64` indicating the number of zero bytes + /// that were written; it may be less than `len`. + write-zeroes: func( + this: output-stream, + /// The number of zero bytes to write + len: u64 + ) -> result; + + /// Write multiple zero bytes to a stream, with blocking. + /// + /// This is similar to `write-zeroes`, except that it blocks until at least + /// one byte can be written. + blocking-write-zeroes: func( + this: output-stream, + /// The number of zero bytes to write + len: u64 + ) -> result; + + /// Read from one stream and write to another. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + /// + /// Unlike other I/O functions, this function blocks until all the data + /// read from the input stream has been written to the output stream. + splice: func( + this: output-stream, + /// The stream to read from + src: input-stream, + /// The number of bytes to splice + len: u64, + ) -> result, stream-error>; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until at least + /// one byte can be read. + blocking-splice: func( + this: output-stream, + /// The stream to read from + src: input-stream, + /// The number of bytes to splice + len: u64, + ) -> result, stream-error>; + + /// Forward the entire contents of an input stream to an output stream. + /// + /// This function repeatedly reads from the input stream and writes + /// the data to the output stream, until the end of the input stream + /// is reached, or an error is encountered. + /// + /// Unlike other I/O functions, this function blocks until the end + /// of the input stream is seen and all the data has been written to + /// the output stream. + /// + /// This function returns the number of bytes transferred. + forward: func( + this: output-stream, + /// The stream to read from + src: input-stream + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// is ready to accept bytes or the other end of the stream has been closed. + subscribe-to-output-stream: func(this: output-stream) -> pollable; + + /// Dispose of the specified `output-stream`, after which it may no longer + /// be used. + drop-output-stream: func(this: output-stream); +} diff --git a/crates/wit-component/tests/interfaces/wasi-http/deps/logging/handler.wit b/crates/wit-component/tests/interfaces/wasi-http/deps/logging/handler.wit new file mode 100644 index 0000000000..83f3fba564 --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/deps/logging/handler.wit @@ -0,0 +1,34 @@ +package wasi:logging; + +/// WASI Logging is a logging API intended to let users emit log messages with +/// simple priority levels and context values. +interface handler { + /// A log level, describing a kind of message. + enum level { + /// Describes messages about the values of variables and the flow of + /// control within a program. + trace, + + /// Describes messages likely to be of interest to someone debugging a + /// program. + debug, + + /// Describes messages likely to be of interest to someone monitoring a + /// program. + info, + + /// Describes messages indicating hazardous situations. + warn, + + /// Describes messages indicating serious errors. + error, + } + + /// Emit a log message. + /// + /// A log message has a `level` describing what kind of message is being + /// sent, a context, which is an uninterpreted string meant to help + /// consumers group similar messages, and a string containing the message + /// text. + log: func(level: level, context: string, message: string); +} diff --git a/crates/wit-component/tests/interfaces/wasi-http/deps/poll/poll.wit b/crates/wit-component/tests/interfaces/wasi-http/deps/poll/poll.wit new file mode 100644 index 0000000000..1b9111cdf5 --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/deps/poll/poll.wit @@ -0,0 +1,41 @@ +package wasi:poll; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +interface poll { + /// A "pollable" handle. + /// + /// This is conceptually represents a `stream<_, _>`, or in other words, + /// a stream that one can wait on, repeatedly, but which does not itself + /// produce any data. It's temporary scaffolding until component-model's + /// async features are ready. + /// + /// And at present, it is a `u32` instead of being an actual handle, until + /// the wit-bindgen implementation of handles and resources is ready. + /// + /// `pollable` lifetimes are not automatically managed. Users must ensure + /// that they do not outlive the resource they reference. + /// + /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). + type pollable = u32; + + /// Dispose of the specified `pollable`, after which it may no longer + /// be used. + drop-pollable: func(this: pollable); + + /// Poll for completion on a set of pollables. + /// + /// The "oneoff" in the name refers to the fact that this function must do a + /// linear scan through the entire list of subscriptions, which may be + /// inefficient if the number is large and the same subscriptions are used + /// many times. In the future, this is expected to be obsoleted by the + /// component model async proposal, which will include a scalable waiting + /// facility. + /// + /// Note that the return type would ideally be `list`, but that would + /// be more difficult to polyfill given the current state of `wit-bindgen`. + /// See + /// for details. For now, we use zero to mean "not ready" and non-zero to + /// mean "ready". + poll-oneoff: func(in: list) -> list; +} diff --git a/crates/wit-component/tests/interfaces/wasi-http/deps/random/random.wit b/crates/wit-component/tests/interfaces/wasi-http/deps/random/random.wit new file mode 100644 index 0000000000..5746dedcd8 --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/deps/random/random.wit @@ -0,0 +1,44 @@ +package wasi:random; + +/// WASI Random is a random data API. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +interface random { + /// Return `len` cryptographically-secure pseudo-random bytes. + /// + /// This function must produce data from an adequately seeded + /// cryptographically-secure pseudo-random number generator (CSPRNG), so it + /// must not block, from the perspective of the calling program, and the + /// returned data is always unpredictable. + /// + /// This function must always return fresh pseudo-random data. Deterministic + /// environments must omit this function, rather than implementing it with + /// deterministic data. + get-random-bytes: func(len: u64) -> list; + + /// Return a cryptographically-secure pseudo-random `u64` value. + /// + /// This function returns the same type of pseudo-random data as + /// `get-random-bytes`, represented as a `u64`. + get-random-u64: func() -> u64; + + /// Return a 128-bit value that may contain a pseudo-random value. + /// + /// The returned value is not required to be computed from a CSPRNG, and may + /// even be entirely deterministic. Host implementations are encouraged to + /// provide pseudo-random values to any program exposed to + /// attacker-controlled content, to enable DoS protection built into many + /// languages' hash-map implementations. + /// + /// This function is intended to only be called once, by a source language + /// to initialize Denial Of Service (DoS) protection in its hash-map + /// implementation. + /// + /// # Expected future evolution + /// + /// This will likely be changed to a value import, to prevent it from being + /// called multiple times and potentially used for purposes other than DoS + /// protection. + insecure-random: func() -> tuple; +} diff --git a/crates/wit-component/tests/interfaces/wasi-http/http.wit.print b/crates/wit-component/tests/interfaces/wasi-http/http.wit.print new file mode 100644 index 0000000000..d47d8aeb72 --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/http.wit.print @@ -0,0 +1,151 @@ +package wasi:http + +interface types { + use wasi:io/streams.{input-stream, output-stream} + use wasi:poll/poll.{pollable} + + variant method { + get, + head, + post, + put, + delete, + connect, + options, + trace, + patch, + other(string), + } + + variant scheme { + HTTP, + HTTPS, + other(string), + } + + variant error { + invalid-url(string), + timeout-error(string), + protocol-error(string), + unexpected-error(string), + } + + type fields = u32 + + type headers = fields + + type trailers = fields + + type incoming-stream = input-stream + + type outgoing-stream = output-stream + + type incoming-request = u32 + + type outgoing-request = u32 + + record request-options { + connect-timeout-ms: option, + first-byte-timeout-ms: option, + between-bytes-timeout-ms: option, + } + + type response-outparam = u32 + + type status-code = u16 + + type incoming-response = u32 + + type outgoing-response = u32 + + type future-incoming-response = u32 + + drop-fields: func(fields: fields) + + new-fields: func(entries: list>) -> fields + + fields-get: func(fields: fields, name: string) -> list + + fields-set: func(fields: fields, name: string, value: list) + + fields-delete: func(fields: fields, name: string) + + fields-append: func(fields: fields, name: string, value: string) + + fields-entries: func(fields: fields) -> list> + + fields-clone: func(fields: fields) -> fields + + finish-incoming-stream: func(s: incoming-stream) -> option + + finish-outgoing-stream: func(s: outgoing-stream, trailers: option) + + drop-incoming-request: func(request: incoming-request) + + drop-outgoing-request: func(request: outgoing-request) + + incoming-request-method: func(request: incoming-request) -> method + + incoming-request-path: func(request: incoming-request) -> string + + incoming-request-query: func(request: incoming-request) -> string + + incoming-request-scheme: func(request: incoming-request) -> option + + incoming-request-authority: func(request: incoming-request) -> string + + incoming-request-headers: func(request: incoming-request) -> headers + + incoming-request-consume: func(request: incoming-request) -> result + + new-outgoing-request: func(method: method, path: string, query: string, scheme: option, authority: string, headers: headers) -> outgoing-request + + outgoing-request-write: func(request: outgoing-request) -> result + + drop-response-outparam: func(response: response-outparam) + + set-response-outparam: func(param: response-outparam, response: result) -> result + + drop-incoming-response: func(response: incoming-response) + + drop-outgoing-response: func(response: outgoing-response) + + incoming-response-status: func(response: incoming-response) -> status-code + + incoming-response-headers: func(response: incoming-response) -> headers + + incoming-response-consume: func(response: incoming-response) -> result + + new-outgoing-response: func(status-code: status-code, headers: headers) -> outgoing-response + + outgoing-response-write: func(response: outgoing-response) -> result + + drop-future-incoming-response: func(f: future-incoming-response) + + future-incoming-response-get: func(f: future-incoming-response) -> option> + + listen-to-future-incoming-response: func(f: future-incoming-response) -> pollable +} + +interface incoming-handler { + use types.{incoming-request, response-outparam} + + handle: func(request: incoming-request, response-out: response-outparam) +} + +interface outgoing-handler { + use types.{outgoing-request, request-options, future-incoming-response} + + handle: func(request: outgoing-request, options: option) -> future-incoming-response +} + +world proxy { + import wasi:random/random + import wasi:logging/handler + import wasi:poll/poll + import wasi:io/streams + import types + import outgoing-handler + + export incoming-handler +} diff --git a/crates/wit-component/tests/interfaces/wasi-http/incoming-handler.wit b/crates/wit-component/tests/interfaces/wasi-http/incoming-handler.wit new file mode 100644 index 0000000000..8667b8048f --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/incoming-handler.wit @@ -0,0 +1,26 @@ +// The `wasi:http/incoming-handler` interface is meant to be exported by +// components and called by the host in response to a new incoming HTTP +// response. +// +// NOTE: in Preview3, this interface will be merged with +// `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface +// that takes a `request` parameter and returns a `response` result. +// +interface incoming-handler { + use types.{incoming-request, response-outparam}; + + // The `handle` function takes an outparam instead of returning its response + // so that the component may stream its response while streaming any other + // request or response bodies. The callee MUST write a response to the + // `response-out` and then finish the response before returning. The caller + // is expected to start streaming the response once `set-response-outparam` + // is called and finish streaming the response when `drop-response-outparam` + // is called. The `handle` function is then allowed to continue executing + // any post-response logic before returning. While this post-response + // execution is taken off the critical path, since there is no return value, + // there is no way to report its success or failure. + handle: func( + request: incoming-request, + response-out: response-outparam + ); +} diff --git a/crates/wit-component/tests/interfaces/wasi-http/outgoing-handler.wit b/crates/wit-component/tests/interfaces/wasi-http/outgoing-handler.wit new file mode 100644 index 0000000000..c2c1932bc2 --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/outgoing-handler.wit @@ -0,0 +1,18 @@ +// The `wasi:http/outgoing-handler` interface is meant to be imported by +// components and implemented by the host. +// +// NOTE: in Preview3, this interface will be merged with +// `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface +// that takes a `request` parameter and returns a `response` result. +// +interface outgoing-handler { + use types.{outgoing-request, request-options, future-incoming-response}; + + // The parameter and result types of the `handle` function allow the caller + // to concurrently stream the bodies of the outgoing request and the incoming + // response. + handle: func( + request: outgoing-request, + options: option + ) -> future-incoming-response; +} diff --git a/crates/wit-component/tests/interfaces/wasi-http/proxy.wit b/crates/wit-component/tests/interfaces/wasi-http/proxy.wit new file mode 100644 index 0000000000..f5c8248efb --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/proxy.wit @@ -0,0 +1,24 @@ +// The `wasi:http/proxy` world captures a widely-implementable intersection of +// hosts that includes HTTP forward and reverse proxies. Components targeting +// this world may concurrently stream in and out any number of incoming and +// outgoing HTTP requests. +world proxy { + // HTTP proxies have access to time and randomness. + import wasi:random/random; + // TODO: add `import wall-clock: clocks.wall-clock` + // TODO: add `import monotonic-clock: clocks.monotonic-clock` + + // This is the default logging handler to use when user code simply wants to + // log to a developer-facing console (e.g., via `console.log()`). + import wasi:logging/handler; + + // This is the default handler to use when user code simply wants to make an + // HTTP request (e.g., via `fetch()`). + import outgoing-handler; + + // The host delivers incoming HTTP requests to a component by calling the + // `handle` function of this exported interface. A host may arbitrarily reuse + // or not reuse component instance when delivering incoming HTTP requests and + // thus a component must be able to handle 0..N calls to `handle`. + export incoming-handler; +} diff --git a/crates/wit-component/tests/interfaces/wasi-http/types.wit b/crates/wit-component/tests/interfaces/wasi-http/types.wit new file mode 100644 index 0000000000..77f07f7f8f --- /dev/null +++ b/crates/wit-component/tests/interfaces/wasi-http/types.wit @@ -0,0 +1,159 @@ +package wasi:http; + +// The `wasi:http/types` interface is meant to be imported by components to +// define the HTTP resource types and operations used by the component's +// imported and exported interfaces. +interface types { + use wasi:io/streams.{input-stream, output-stream}; + use wasi:poll/poll.{pollable}; + + // This type corresponds to HTTP standard Methods. + variant method { + get, + head, + post, + put, + delete, + connect, + options, + trace, + patch, + other(string) + } + + // This type corresponds to HTTP standard Related Schemes. + variant scheme { + HTTP, + HTTPS, + other(string) + } + + // TODO: perhaps better align with HTTP semantics? + // This type enumerates the different kinds of errors that may occur when + // initially returning a response. + variant error { + invalid-url(string), + timeout-error(string), + protocol-error(string), + unexpected-error(string) + } + + // This following block defines the `fields` resource which corresponds to + // HTTP standard Fields. Soon, when resource types are added, the `type + // fields = u32` type alias can be replaced by a proper `resource fields` + // definition containing all the functions using the method syntactic sugar. + type fields = u32; + drop-fields: func(fields: fields); + new-fields: func(entries: list>) -> fields; + fields-get: func(fields: fields, name: string) -> list; + fields-set: func(fields: fields, name: string, value: list); + fields-delete: func(fields: fields, name: string); + fields-append: func(fields: fields, name: string, value: string); + fields-entries: func(fields: fields) -> list>; + fields-clone: func(fields: fields) -> fields; + + type headers = fields; + type trailers = fields; + + // The following block defines stream types which corresponds to the HTTP + // standard Contents and Trailers. With Preview3, all of these fields can be + // replaced by a stream>. In the interim, we need to + // build on separate resource types defined by `wasi:io/streams`. The + // `finish-` functions emulate the stream's result value and MUST be called + // exactly once after the final read/write from/to the stream before dropping + // the stream. + type incoming-stream = input-stream; + type outgoing-stream = output-stream; + finish-incoming-stream: func(s: incoming-stream) -> option; + finish-outgoing-stream: func(s: outgoing-stream, trailers: option); + + // The following block defines the `incoming-request` and `outgoing-request` + // resource types that correspond to HTTP standard Requests. Soon, when + // resource types are added, the `u32` type aliases can be replaced by + // proper `resource` type definitions containing all the functions as + // methods. Later, Preview2 will allow both types to be merged together into + // a single `request` type (that uses the single `stream` type mentioned + // above). The `consume` and `write` methods may only be called once (and + // return failure thereafter). + type incoming-request = u32; + type outgoing-request = u32; + drop-incoming-request: func(request: incoming-request); + drop-outgoing-request: func(request: outgoing-request); + incoming-request-method: func(request: incoming-request) -> method; + incoming-request-path: func(request: incoming-request) -> string; + incoming-request-query: func(request: incoming-request) -> string; + incoming-request-scheme: func(request: incoming-request) -> option; + incoming-request-authority: func(request: incoming-request) -> string; + incoming-request-headers: func(request: incoming-request) -> headers; + incoming-request-consume: func(request: incoming-request) -> result; + new-outgoing-request: func( + method: method, + path: string, + query: string, + scheme: option, + authority: string, + headers: headers + ) -> outgoing-request; + outgoing-request-write: func(request: outgoing-request) -> result; + + // Additional optional parameters that can be set when making a request. + record request-options { + // The following timeouts are specific to the HTTP protocol and work + // independently of the overall timeouts passed to `io.poll.poll-oneoff`. + + // The timeout for the initial connect. + connect-timeout-ms: option, + + // The timeout for receiving the first byte of the response body. + first-byte-timeout-ms: option, + + // The timeout for receiving the next chunk of bytes in the response body + // stream. + between-bytes-timeout-ms: option + } + + // The following block defines a special resource type used by the + // `wasi:http/incoming-handler` interface. When resource types are added, this + // block can be replaced by a proper `resource response-outparam { ... }` + // definition. Later, with Preview3, the need for an outparam goes away entirely + // (the `wasi:http/handler` interface used for both incoming and outgoing can + // simply return a `stream`). + type response-outparam = u32; + drop-response-outparam: func(response: response-outparam); + set-response-outparam: func(param: response-outparam, response: result) -> result; + + // This type corresponds to the HTTP standard Status Code. + type status-code = u16; + + // The following block defines the `incoming-response` and `outgoing-response` + // resource types that correspond to HTTP standard Responses. Soon, when + // resource types are added, the `u32` type aliases can be replaced by proper + // `resource` type definitions containing all the functions as methods. Later, + // Preview2 will allow both types to be merged together into a single `response` + // type (that uses the single `stream` type mentioned above). The `consume` and + // `write` methods may only be called once (and return failure thereafter). + type incoming-response = u32; + type outgoing-response = u32; + drop-incoming-response: func(response: incoming-response); + drop-outgoing-response: func(response: outgoing-response); + incoming-response-status: func(response: incoming-response) -> status-code; + incoming-response-headers: func(response: incoming-response) -> headers; + incoming-response-consume: func(response: incoming-response) -> result; + new-outgoing-response: func( + status-code: status-code, + headers: headers + ) -> outgoing-response; + outgoing-response-write: func(response: outgoing-response) -> result; + + // The following block defines a special resource type used by the + // `wasi:http/outgoing-handler` interface to emulate + // `future>` in advance of Preview3. Given a + // `future-incoming-response`, the client can call the non-blocking `get` + // method to get the result if it is available. If the result is not available, + // the client can call `listen` to get a `pollable` that can be passed to + // `io.poll.poll-oneoff`. + type future-incoming-response = u32; + drop-future-incoming-response: func(f: future-incoming-response); + future-incoming-response-get: func(f: future-incoming-response) -> option>; + listen-to-future-incoming-response: func(f: future-incoming-response) -> pollable; +} diff --git a/crates/wit-component/tests/interfaces/world-inline-interface.wat b/crates/wit-component/tests/interfaces/world-inline-interface.wat new file mode 100644 index 0000000000..77c67eb961 --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-inline-interface.wat @@ -0,0 +1,23 @@ +(component + (type (;0;) + (component + (type (;0;) + (component + (type (;0;) + (instance) + ) + (import "foo" (instance (;0;) (type 0))) + (type (;1;) + (instance) + ) + (export (;1;) "bar" (instance (type 1))) + ) + ) + (export (;0;) (interface "foo:foo/has-inline") (component (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/world-inline-interface.wit b/crates/wit-component/tests/interfaces/world-inline-interface.wit new file mode 100644 index 0000000000..94ec5d1b1f --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-inline-interface.wit @@ -0,0 +1,6 @@ +package foo:foo; + +world has-inline { + import foo: interface {} + export bar: interface {} +} diff --git a/crates/wit-component/tests/interfaces/world-inline-interface.wit.print b/crates/wit-component/tests/interfaces/world-inline-interface.wit.print new file mode 100644 index 0000000000..ede6fa0abd --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-inline-interface.wit.print @@ -0,0 +1,9 @@ +package foo:foo + +world has-inline { + import foo: interface { + } + + export bar: interface { + } +} diff --git a/crates/wit-component/tests/interfaces/world-pkg-conflict.wat b/crates/wit-component/tests/interfaces/world-pkg-conflict.wat new file mode 100644 index 0000000000..fbd7e83927 --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-pkg-conflict.wat @@ -0,0 +1,29 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "t" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:foo/a") (instance (type 0))) + (alias export 0 "t" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (export (;1;) (interface "foo:foo/foo") (instance (type 2))) + (type (;3;) + (component) + ) + (export (;0;) (interface "foo:foo/c") (component (type 3))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/world-pkg-conflict/bar.wit b/crates/wit-component/tests/interfaces/world-pkg-conflict/bar.wit new file mode 100644 index 0000000000..80b3428095 --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-pkg-conflict/bar.wit @@ -0,0 +1,3 @@ +interface a { + type t = u32; +} diff --git a/crates/wit-component/tests/interfaces/world-pkg-conflict/foo.wit b/crates/wit-component/tests/interfaces/world-pkg-conflict/foo.wit new file mode 100644 index 0000000000..1233bad418 --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-pkg-conflict/foo.wit @@ -0,0 +1,9 @@ +package foo:foo; + +world c { + +} + +interface foo { + use a.{t}; +} diff --git a/crates/wit-component/tests/interfaces/world-pkg-conflict/foo.wit.print b/crates/wit-component/tests/interfaces/world-pkg-conflict/foo.wit.print new file mode 100644 index 0000000000..ffc2995e97 --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-pkg-conflict/foo.wit.print @@ -0,0 +1,12 @@ +package foo:foo + +interface a { + type t = u32 +} + +interface foo { + use a.{t} +} + +world c { +} diff --git a/crates/wit-component/tests/interfaces/world-top-level.wat b/crates/wit-component/tests/interfaces/world-top-level.wat new file mode 100644 index 0000000000..901850f349 --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-top-level.wat @@ -0,0 +1,44 @@ +(component + (type (;0;) + (component + (type (;0;) + (component + (type (;0;) + (instance) + ) + (import "some-interface" (instance (;0;) (type 0))) + (type (;1;) (func)) + (import "foo" (func (;0;) (type 1))) + (type (;2;) (func (param "arg" u32))) + (import "bar" (func (;1;) (type 2))) + (export (;2;) "foo2" (func (type 1))) + (type (;3;) (func (result u32))) + (export (;3;) "bar2" (func (type 3))) + (type (;4;) + (instance) + ) + (export (;1;) "another-interface" (instance (type 4))) + ) + ) + (export (;0;) (interface "foo:foo/foo") (component (type 0))) + (type (;1;) + (component + (type (;0;) (func)) + (import "foo" (func (;0;) (type 0))) + ) + ) + (export (;1;) (interface "foo:foo/just-import") (component (type 1))) + (type (;2;) + (component + (type (;0;) (func)) + (export (;0;) "foo" (func (type 0))) + ) + ) + (export (;2;) (interface "foo:foo/just-export") (component (type 2))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/world-top-level.wit b/crates/wit-component/tests/interfaces/world-top-level.wit new file mode 100644 index 0000000000..e964709f99 --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-top-level.wit @@ -0,0 +1,20 @@ +package foo:foo; + +world foo { + import foo: func(); + export foo2: func(); + + import bar: func(arg: u32); + export bar2: func() -> u32; + + import some-interface: interface {} + export another-interface: interface {} +} + +world just-import { + import foo: func(); +} + +world just-export { + export foo: func(); +} diff --git a/crates/wit-component/tests/interfaces/world-top-level.wit.print b/crates/wit-component/tests/interfaces/world-top-level.wit.print new file mode 100644 index 0000000000..b5f4997a3f --- /dev/null +++ b/crates/wit-component/tests/interfaces/world-top-level.wit.print @@ -0,0 +1,19 @@ +package foo:foo + +world foo { + import some-interface: interface { + } + import foo: func() + import bar: func(arg: u32) + + export foo2: func() + export bar2: func() -> u32 + export another-interface: interface { + } +} +world just-import { + import foo: func() +} +world just-export { + export foo: func() +} diff --git a/crates/wit-component/tests/interfaces/worlds-with-types.wat b/crates/wit-component/tests/interfaces/worlds-with-types.wat new file mode 100644 index 0000000000..4175e4f443 --- /dev/null +++ b/crates/wit-component/tests/interfaces/worlds-with-types.wat @@ -0,0 +1,45 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "foo" (type (eq 0))) + ) + ) + (export (;0;) (interface "foo:foo/import-me") (instance (type 0))) + (type (;1;) + (component + (type (;0;) (record (field "f" u8))) + (import "foo" (type (;1;) (eq 0))) + (import "bar" (type (;2;) (eq 1))) + (type (;3;) (func (param "a" 1) (result 2))) + (import "a" (func (;0;) (type 3))) + (export (;1;) "b" (func (type 3))) + ) + ) + (export (;0;) (interface "foo:foo/simple") (component (type 1))) + (type (;2;) + (component + (type (;0;) + (instance + (type (;0;) u32) + (export (;1;) "foo" (type (eq 0))) + ) + ) + (import (interface "foo:foo/import-me") (instance (;0;) (type 0))) + (alias export 0 "foo" (type (;1;))) + (import "foo" (type (;2;) (eq 1))) + (type (;3;) (func (param "a" 2))) + (import "a" (func (;0;) (type 3))) + (export (;1;) "b" (func (type 3))) + ) + ) + (export (;1;) (interface "foo:foo/with-imports") (component (type 2))) + ) + ) + (export (;1;) (interface "foo:foo/wit") (type 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/worlds-with-types.wit b/crates/wit-component/tests/interfaces/worlds-with-types.wit new file mode 100644 index 0000000000..6e315792bc --- /dev/null +++ b/crates/wit-component/tests/interfaces/worlds-with-types.wit @@ -0,0 +1,23 @@ +package foo:foo; + +world simple { + record foo { + f: u8, + } + + type bar = foo; + + import a: func(a: foo) -> bar; + export b: func(a: foo) -> bar; +} + +interface import-me { + type foo = u32; +} + +world with-imports { + use import-me.{foo}; + + import a: func(a: foo); + export b: func(a: foo); +} diff --git a/crates/wit-component/tests/interfaces/worlds-with-types.wit.print b/crates/wit-component/tests/interfaces/worlds-with-types.wit.print new file mode 100644 index 0000000000..e508351879 --- /dev/null +++ b/crates/wit-component/tests/interfaces/worlds-with-types.wit.print @@ -0,0 +1,24 @@ +package foo:foo + +interface import-me { + type foo = u32 +} + +world simple { + import a: func(a: foo) -> bar + + record foo { + f: u8, + } + + type bar = foo + + export b: func(a: foo) -> bar +} +world with-imports { + import import-me + import a: func(a: foo) + use import-me.{foo} + + export b: func(a: foo) +} diff --git a/crates/wit-component/tests/linking.rs b/crates/wit-component/tests/linking.rs new file mode 100644 index 0000000000..7b7d0ac383 --- /dev/null +++ b/crates/wit-component/tests/linking.rs @@ -0,0 +1,219 @@ +use { + anyhow::{Context, Result}, + std::{borrow::Cow, path::Path}, + wasm_encoder::{CustomSection, Encode as _, Section as _}, + wit_component::StringEncoding, + wit_parser::{Resolve, UnresolvedPackage}, +}; + +const FOO: &str = r#" +(module + (@dylink.0 + (mem-info (memory 4 4)) + (needed "libc.so") + ) + (type (func)) + (type (func (param i32) (result i32))) + (import "env" "memory" (memory 1)) + (import "env" "__indirect_function_table" (table 0 funcref)) + (import "env" "__stack_pointer" (global $__stack_pointer (mut i32))) + (import "env" "__memory_base" (global $__memory_base i32)) + (import "env" "__table_base" (global $__table_base i32)) + (import "env" "malloc" (func $malloc (type 1))) + (import "env" "abort" (func $abort (type 0))) + (import "GOT.mem" "um" (global $um (mut i32))) + (import "test:test/test" "bar" (func $bar (type 1))) + (func $__wasm_call_ctors (type 0)) + (func $__wasm_apply_data_relocs (type 0)) + (func $foo (type 1) (param i32) (result i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + global.set $__stack_pointer + + i32.const 4 + call $malloc + + i32.const 0 + i32.eq + if + call $abort + unreachable + end + + local.get 0 + global.get $um + i32.load offset=16 + i32.add + i32.const 42 + i32.add + + call $bar + + global.get $__stack_pointer + i32.const 16 + i32.add + global.set $__stack_pointer + ) + (global i32 i32.const 0) + (export "__wasm_call_ctors" (func $__wasm_call_ctors)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "foo" (func $foo)) + (export "well" (global 4)) + (data $.data (global.get $__memory_base) "\04\00\00\00") +) +"#; + +const BAR: &str = r#" +(module + (@dylink.0 + (mem-info (memory 20 4)) + (needed "libfoo.so") + ) + (type (func (param i32) (result i32))) + (type (func)) + (import "env" "memory" (memory 1)) + (import "env" "__indirect_function_table" (table 0 funcref)) + (import "env" "__memory_base" (global $__memory_base i32)) + (import "env" "__table_base" (global $__table_base i32)) + (import "env" "foo" (func $foo (type 0))) + (import "GOT.mem" "well" (global $well (mut i32))) + (func $__wasm_call_ctors (type 1)) + (func $__wasm_apply_data_relocs (type 1)) + (func $bar (type 0) (param i32) (result i32) + local.get 0 + call $foo + global.get $well + i32.load + i32.add + ) + (global i32 i32.const 0) + (export "__wasm_call_ctors" (func $__wasm_call_ctors)) + (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) + (export "test:test/test#bar" (func $bar)) + (export "um" (global 3)) + (data $.data (global.get $__memory_base) "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00") +) +"#; + +const LIBC: &str = r#" +(module + (@dylink.0) + (type (func)) + (type (func (param i32) (result i32))) + (import "GOT.mem" "__heap_base" (global $__heap_base (mut i32))) + (import "GOT.mem" "__heap_end" (global $__heap_end (mut i32))) + (global $heap (mut i32) i32.const 0) + (func $start (type 0) + global.get $__heap_base + global.set $heap + ) + (func $malloc (type 1) (param i32) (result i32) + global.get $heap + global.get $heap + local.get 0 + i32.add + global.set $heap + ) + (func $abort (type 0) + unreachable + ) + (export "malloc" (func $malloc)) + (export "abort" (func $abort)) + (start $start) +) +"#; + +const WIT: &str = r#" +package test:test; + +interface test { + bar: func(v: s32) -> s32; +} + +world bar { + import test; + export test; +} +"#; + +fn encode(wat: &str, wit: Option<&str>) -> Result> { + let mut module = wat::parse_str(wat)?; + + if let Some(wit) = wit { + let mut resolve = Resolve::default(); + let pkg = resolve.push(UnresolvedPackage::parse(Path::new("wit"), wit)?)?; + let world = resolve.select_world(pkg, None)?; + let component_type = + wit_component::metadata::encode(&resolve, world, StringEncoding::UTF8, None)?; + + let section = CustomSection { + name: Cow::Borrowed("component-type"), + data: Cow::Borrowed(&component_type), + }; + + module.push(section.id()); + section.encode(&mut module); + } + + wasmparser::validate(&module)?; + + Ok(module) +} + +#[test] +fn linking() -> Result<()> { + let component = [ + ("libfoo.so", FOO, None), + ("libbar.so", BAR, Some(WIT)), + ("libc.so", LIBC, None), + ] + .into_iter() + .try_fold( + wit_component::Linker::default().validate(true), + |linker, (name, wat, wit)| { + linker.library( + name, + &encode(wat, wit).with_context(|| name.to_owned())?, + false, + ) + }, + )? + .encode()?; + + #[cfg(target_family = "wasm")] + { + _ = component; + } + + #[cfg(not(target_family = "wasm"))] + { + use { + anyhow::anyhow, + wasmtime::{ + component::{Component, Linker}, + Config, Engine, Store, + }, + }; + + let mut config = Config::new(); + config.wasm_component_model(true); + + let engine = Engine::new(&config)?; + let mut linker = Linker::new(&engine); + linker + .instance("test:test/test")? + .func_wrap("bar", |_store, (v,): (i32,)| Ok((v + 7,)))?; + let mut store = Store::new(&engine, ()); + let instance = linker.instantiate(&mut store, &Component::new(&engine, &component)?)?; + let func = instance + .exports(&mut store) + .instance("test:test/test") + .ok_or_else(|| anyhow!("instance `test:test/test` not found"))? + .typed_func::<(i32,), (i32,)>("bar")?; + + assert_eq!(65, func.call(&mut store, (7,))?.0); + } + + Ok(()) +} diff --git a/crates/wit-component/tests/merge.rs b/crates/wit-component/tests/merge.rs new file mode 100644 index 0000000000..6176b1c113 --- /dev/null +++ b/crates/wit-component/tests/merge.rs @@ -0,0 +1,157 @@ +use anyhow::{Context, Result}; +use pretty_assertions::assert_eq; +use std::collections::HashSet; +use std::{fs, path::Path}; +use wit_component::WitPrinter; +use wit_parser::{Resolve, TypeOwner, WorldItem}; + +/// This is a test which iterates over the `tests/merge` directory and treats +/// each subdirectory as its own test. Each subdirectory has an `into` and a +/// `from` folder which represent two different `Resolve` sets, each with their +/// own set of dependencies as well. +/// +/// Each test will merge the `from` into the `into` and assert that everything +/// is valid along the way. On successful merge the resulting documents +/// are printed and asserted against expectations. Failures assert the +/// correct error message. +#[test] +fn merging() -> Result<()> { + drop(env_logger::try_init()); + + for entry in fs::read_dir("tests/merge")? { + let path = entry?.path(); + if !path.is_dir() { + continue; + } + + let test_case = path.file_stem().unwrap().to_str().unwrap(); + println!("testing {test_case}"); + + let mut from = Resolve::default(); + from.push_dir(&path.join("from"))?; + let mut into = Resolve::default(); + into.push_dir(&path.join("into"))?; + + assert_valid_resolve(&from); + assert_valid_resolve(&into); + + match into.merge(from) { + Ok(_) => { + assert!( + !test_case.starts_with("bad-"), + "should have failed to merge" + ); + assert_valid_resolve(&into); + for (id, pkg) in into.packages.iter() { + let expected = path + .join("merge") + .join(&pkg.name.name) + .with_extension("wit"); + let output = WitPrinter::default().print(&into, id)?; + assert_output(&expected, &output)?; + } + } + Err(e) => { + assert!(test_case.starts_with("bad-"), "failed to merge with {e:?}"); + assert_output(&path.join("error.txt"), &format!("{e:?}"))?; + } + } + } + + Ok(()) +} + +fn assert_output(expected: &Path, actual: &str) -> Result<()> { + if std::env::var_os("BLESS").is_some() { + fs::create_dir_all(expected.parent().unwrap())?; + fs::write(expected, actual).with_context(|| format!("failed to write {expected:?}"))?; + } else { + assert_eq!( + fs::read_to_string(expected) + .with_context(|| format!("failed to read {expected:?}"))? + .replace("\r\n", "\n"), + actual, + "expectation `{}` did not match actual", + expected.display(), + ); + } + Ok(()) +} + +fn assert_valid_resolve(resolve: &Resolve) { + let mut package_interfaces = Vec::new(); + let mut package_worlds = Vec::new(); + for (id, pkg) in resolve.packages.iter() { + let mut interfaces = HashSet::new(); + for (name, iface) in pkg.interfaces.iter() { + assert!(interfaces.insert(*iface)); + let iface = &resolve.interfaces[*iface]; + assert_eq!(name, iface.name.as_ref().unwrap()); + assert_eq!(iface.package.unwrap(), id); + } + package_interfaces.push(pkg.interfaces.values().copied().collect::>()); + let mut worlds = HashSet::new(); + for (name, world) in pkg.worlds.iter() { + assert!(worlds.insert(*world)); + let world = &resolve.worlds[*world]; + assert_eq!(*name, world.name); + assert_eq!(world.package.unwrap(), id); + } + package_worlds.push(pkg.worlds.values().copied().collect::>()); + } + + let mut interface_types = Vec::new(); + for (id, iface) in resolve.interfaces.iter() { + assert!(resolve.packages.get(iface.package.unwrap()).is_some()); + if iface.name.is_some() { + assert!(package_interfaces[iface.package.unwrap().index()].contains(&id)); + } + + for (name, ty) in iface.types.iter() { + let ty = &resolve.types[*ty]; + assert_eq!(ty.name.as_ref(), Some(name)); + assert_eq!(ty.owner, TypeOwner::Interface(id)); + } + interface_types.push(iface.types.values().copied().collect::>()); + for (name, f) in iface.functions.iter() { + assert_eq!(*name, f.name); + } + } + + let mut world_types = Vec::new(); + for (id, world) in resolve.worlds.iter() { + assert!(resolve.packages.get(world.package.unwrap()).is_some()); + assert!(package_worlds[world.package.unwrap().index()].contains(&id)); + + let mut types = HashSet::new(); + for (name, item) in world.imports.iter().chain(world.exports.iter()) { + match item { + WorldItem::Interface(_) => {} + WorldItem::Function(f) => { + assert_eq!(f.name, name.clone().unwrap_name()); + } + WorldItem::Type(ty) => { + assert!(types.insert(*ty)); + let ty = &resolve.types[*ty]; + assert_eq!(ty.name, Some(name.clone().unwrap_name())); + assert_eq!(ty.owner, TypeOwner::World(id)); + } + } + } + world_types.push(types); + } + + for (ty_id, ty) in resolve.types.iter() { + match ty.owner { + TypeOwner::Interface(id) => { + assert!(resolve.interfaces.get(id).is_some()); + assert!(interface_types[id.index()].contains(&ty_id)); + } + TypeOwner::World(id) => { + assert!(resolve.worlds.get(id).is_some()); + assert!(world_types[id.index()].contains(&ty_id)); + } + TypeOwner::None => {} + } + } +} diff --git a/crates/wit-component/tests/merge/bad-interface1/error.txt b/crates/wit-component/tests/merge/bad-interface1/error.txt new file mode 100644 index 0000000000..951bb365d3 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface1/error.txt @@ -0,0 +1,5 @@ +failed to merge package `foo:foo` into existing copy + +Caused by: + 0: failed to merge interface `a` + 1: expected type `a` to be present \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-interface1/from/a.wit b/crates/wit-component/tests/merge/bad-interface1/from/a.wit new file mode 100644 index 0000000000..7815d4c689 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface1/from/a.wit @@ -0,0 +1,5 @@ +package foo:%from; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-interface1/from/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-interface1/from/deps/foo/a.wit new file mode 100644 index 0000000000..0ceaac52d8 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface1/from/deps/foo/a.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface a { + type a = u32; +} diff --git a/crates/wit-component/tests/merge/bad-interface1/into/a.wit b/crates/wit-component/tests/merge/bad-interface1/into/a.wit new file mode 100644 index 0000000000..3ba73ddd33 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface1/into/a.wit @@ -0,0 +1,5 @@ +package foo:into; + +interface a { + use foo:foo/a.{b}; +} diff --git a/crates/wit-component/tests/merge/bad-interface1/into/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-interface1/into/deps/foo/a.wit new file mode 100644 index 0000000000..d4335c93a6 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface1/into/deps/foo/a.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface a { + type b = s32; +} diff --git a/crates/wit-component/tests/merge/bad-interface2/error.txt b/crates/wit-component/tests/merge/bad-interface2/error.txt new file mode 100644 index 0000000000..bbb5f232b2 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface2/error.txt @@ -0,0 +1,5 @@ +failed to merge package `foo:foo` into existing copy + +Caused by: + 0: failed to merge interface `a` + 1: expected function `a` to be present \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-interface2/from/a.wit b/crates/wit-component/tests/merge/bad-interface2/from/a.wit new file mode 100644 index 0000000000..74e6d0c545 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface2/from/a.wit @@ -0,0 +1,5 @@ +package foo:%from; + +interface a { + use foo:foo/a.{t}; +} diff --git a/crates/wit-component/tests/merge/bad-interface2/from/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-interface2/from/deps/foo/a.wit new file mode 100644 index 0000000000..cac06d9ff2 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface2/from/deps/foo/a.wit @@ -0,0 +1,7 @@ +package foo:foo; + +interface a { + type t = u32; + + a: func(); +} diff --git a/crates/wit-component/tests/merge/bad-interface2/into/a.wit b/crates/wit-component/tests/merge/bad-interface2/into/a.wit new file mode 100644 index 0000000000..d1179471b4 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface2/into/a.wit @@ -0,0 +1,5 @@ +package foo:into; + +interface a { + use foo:foo/a.{t}; +} diff --git a/crates/wit-component/tests/merge/bad-interface2/into/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-interface2/into/deps/foo/a.wit new file mode 100644 index 0000000000..1163885a03 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-interface2/into/deps/foo/a.wit @@ -0,0 +1,7 @@ +package foo:foo; + +interface a { + type t = u32; + + b: func(); +} diff --git a/crates/wit-component/tests/merge/bad-world1/error.txt b/crates/wit-component/tests/merge/bad-world1/error.txt new file mode 100644 index 0000000000..f04e2ed0c2 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world1/error.txt @@ -0,0 +1,5 @@ +failed to merge package `foo:foo` into existing copy + +Caused by: + 0: failed to merge world `foo` + 1: import `b` not found in target world \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world1/from/a.wit b/crates/wit-component/tests/merge/bad-world1/from/a.wit new file mode 100644 index 0000000000..6abdb6dd6c --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world1/from/a.wit @@ -0,0 +1,4 @@ +package foo:%from; +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world1/from/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world1/from/deps/foo/a.wit new file mode 100644 index 0000000000..d0243ca0ed --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world1/from/deps/foo/a.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { + import b: interface { + type a = u32; + } +} diff --git a/crates/wit-component/tests/merge/bad-world1/into/a.wit b/crates/wit-component/tests/merge/bad-world1/into/a.wit new file mode 100644 index 0000000000..902cda15c1 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world1/into/a.wit @@ -0,0 +1,4 @@ +package foo:into; +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world1/into/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world1/into/deps/foo/a.wit new file mode 100644 index 0000000000..3f7ebb72c4 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world1/into/deps/foo/a.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { + import a; +} diff --git a/crates/wit-component/tests/merge/bad-world2/error.txt b/crates/wit-component/tests/merge/bad-world2/error.txt new file mode 100644 index 0000000000..bca74e7b04 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world2/error.txt @@ -0,0 +1,5 @@ +failed to merge package `foo:foo` into existing copy + +Caused by: + 0: failed to merge world `foo` + 1: world contains different number of imports than expected \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world2/from/a.wit b/crates/wit-component/tests/merge/bad-world2/from/a.wit new file mode 100644 index 0000000000..7815d4c689 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world2/from/a.wit @@ -0,0 +1,5 @@ +package foo:%from; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world2/from/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world2/from/deps/foo/a.wit new file mode 100644 index 0000000000..b7e7ada193 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world2/from/deps/foo/a.wit @@ -0,0 +1,8 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { +} diff --git a/crates/wit-component/tests/merge/bad-world2/into/a.wit b/crates/wit-component/tests/merge/bad-world2/into/a.wit new file mode 100644 index 0000000000..3c1df58c95 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world2/into/a.wit @@ -0,0 +1,5 @@ +package foo:into; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world2/into/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world2/into/deps/foo/a.wit new file mode 100644 index 0000000000..3f7ebb72c4 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world2/into/deps/foo/a.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { + import a; +} diff --git a/crates/wit-component/tests/merge/bad-world3/error.txt b/crates/wit-component/tests/merge/bad-world3/error.txt new file mode 100644 index 0000000000..daf6860fff --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world3/error.txt @@ -0,0 +1,5 @@ +failed to merge package `foo:foo` into existing copy + +Caused by: + 0: failed to merge world `foo` + 1: world contains different number of exports than expected \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world3/from/a.wit b/crates/wit-component/tests/merge/bad-world3/from/a.wit new file mode 100644 index 0000000000..7815d4c689 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world3/from/a.wit @@ -0,0 +1,5 @@ +package foo:%from; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world3/from/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world3/from/deps/foo/a.wit new file mode 100644 index 0000000000..b7e7ada193 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world3/from/deps/foo/a.wit @@ -0,0 +1,8 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { +} diff --git a/crates/wit-component/tests/merge/bad-world3/into/a.wit b/crates/wit-component/tests/merge/bad-world3/into/a.wit new file mode 100644 index 0000000000..3c1df58c95 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world3/into/a.wit @@ -0,0 +1,5 @@ +package foo:into; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world3/into/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world3/into/deps/foo/a.wit new file mode 100644 index 0000000000..78b5ed5841 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world3/into/deps/foo/a.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { + export a; +} diff --git a/crates/wit-component/tests/merge/bad-world4/error.txt b/crates/wit-component/tests/merge/bad-world4/error.txt new file mode 100644 index 0000000000..5cf21c9247 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world4/error.txt @@ -0,0 +1,5 @@ +failed to merge package `foo:foo` into existing copy + +Caused by: + 0: failed to merge world `foo` + 1: export `b` not found in target world \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world4/from/a.wit b/crates/wit-component/tests/merge/bad-world4/from/a.wit new file mode 100644 index 0000000000..7815d4c689 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world4/from/a.wit @@ -0,0 +1,5 @@ +package foo:%from; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world4/from/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world4/from/deps/foo/a.wit new file mode 100644 index 0000000000..f9babcd631 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world4/from/deps/foo/a.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { + export b: interface { + type a = u32; + } +} diff --git a/crates/wit-component/tests/merge/bad-world4/into/a.wit b/crates/wit-component/tests/merge/bad-world4/into/a.wit new file mode 100644 index 0000000000..3c1df58c95 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world4/into/a.wit @@ -0,0 +1,5 @@ +package foo:into; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world4/into/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world4/into/deps/foo/a.wit new file mode 100644 index 0000000000..78b5ed5841 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world4/into/deps/foo/a.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { + export a; +} diff --git a/crates/wit-component/tests/merge/bad-world5/error.txt b/crates/wit-component/tests/merge/bad-world5/error.txt new file mode 100644 index 0000000000..9eb40e7551 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world5/error.txt @@ -0,0 +1,5 @@ +failed to merge package `foo:foo` into existing copy + +Caused by: + 0: failed to merge world `foo` + 1: import `a` not found in target world \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world5/from/a.wit b/crates/wit-component/tests/merge/bad-world5/from/a.wit new file mode 100644 index 0000000000..7815d4c689 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world5/from/a.wit @@ -0,0 +1,5 @@ +package foo:%from; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world5/from/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world5/from/deps/foo/a.wit new file mode 100644 index 0000000000..791d5b6e5e --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world5/from/deps/foo/a.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { + import a: interface { + type a = u32; + } +} diff --git a/crates/wit-component/tests/merge/bad-world5/into/a.wit b/crates/wit-component/tests/merge/bad-world5/into/a.wit new file mode 100644 index 0000000000..3c1df58c95 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world5/into/a.wit @@ -0,0 +1,5 @@ +package foo:into; + +interface a { + use foo:foo/a.{a}; +} diff --git a/crates/wit-component/tests/merge/bad-world5/into/deps/foo/a.wit b/crates/wit-component/tests/merge/bad-world5/into/deps/foo/a.wit new file mode 100644 index 0000000000..3f7ebb72c4 --- /dev/null +++ b/crates/wit-component/tests/merge/bad-world5/into/deps/foo/a.wit @@ -0,0 +1,9 @@ +package foo:foo; + +interface a { + type a = u32; +} + +world foo { + import a; +} diff --git a/crates/wit-component/tests/merge/success/from/a.wit b/crates/wit-component/tests/merge/success/from/a.wit new file mode 100644 index 0000000000..d181c7f53e --- /dev/null +++ b/crates/wit-component/tests/merge/success/from/a.wit @@ -0,0 +1,7 @@ +package foo:%from; + +interface a { + use foo:foo/only-from.{r}; + + foo: func(); +} diff --git a/crates/wit-component/tests/merge/success/from/deps/foo/only-from.wit b/crates/wit-component/tests/merge/success/from/deps/foo/only-from.wit new file mode 100644 index 0000000000..459cdd4b22 --- /dev/null +++ b/crates/wit-component/tests/merge/success/from/deps/foo/only-from.wit @@ -0,0 +1,5 @@ +interface only-from { + record r {} + + foo: func() -> r; +} diff --git a/crates/wit-component/tests/merge/success/from/deps/foo/shared.wit b/crates/wit-component/tests/merge/success/from/deps/foo/shared.wit new file mode 100644 index 0000000000..a3b65ebeb9 --- /dev/null +++ b/crates/wit-component/tests/merge/success/from/deps/foo/shared.wit @@ -0,0 +1,25 @@ +package foo:foo; + +interface shared-only-from { + variant v { + c1, + } + + bar: func(x: v); + + use foo:only-from-dep/a.{a}; +} + +interface shared-items { + type a = u32; +} + +world shared-world { + import shared-items; + + export shared-items; + + type c = u32; + + import d: interface {} +} diff --git a/crates/wit-component/tests/merge/success/from/deps/only-from-dep/a.wit b/crates/wit-component/tests/merge/success/from/deps/only-from-dep/a.wit new file mode 100644 index 0000000000..0f11910980 --- /dev/null +++ b/crates/wit-component/tests/merge/success/from/deps/only-from-dep/a.wit @@ -0,0 +1,5 @@ +package foo:only-from-dep; + +interface a { + type a = u32; +} diff --git a/crates/wit-component/tests/merge/success/into/b.wit b/crates/wit-component/tests/merge/success/into/b.wit new file mode 100644 index 0000000000..ae3681207b --- /dev/null +++ b/crates/wit-component/tests/merge/success/into/b.wit @@ -0,0 +1,7 @@ +package foo:into; + +interface b { + use foo:foo/only-into.{r}; + + foo: func(); +} diff --git a/crates/wit-component/tests/merge/success/into/deps/foo/only-into.wit b/crates/wit-component/tests/merge/success/into/deps/foo/only-into.wit new file mode 100644 index 0000000000..60f96e4bbd --- /dev/null +++ b/crates/wit-component/tests/merge/success/into/deps/foo/only-into.wit @@ -0,0 +1,5 @@ +interface only-into { + record r {} + + foo: func() -> r; +} diff --git a/crates/wit-component/tests/merge/success/into/deps/foo/shared.wit b/crates/wit-component/tests/merge/success/into/deps/foo/shared.wit new file mode 100644 index 0000000000..bd9e90c0fe --- /dev/null +++ b/crates/wit-component/tests/merge/success/into/deps/foo/shared.wit @@ -0,0 +1,23 @@ +package foo:foo; + +interface shared-only-into { + variant v { + c1, + } + + bar: func(x: v); +} + +interface shared-items { + type a = u32; +} + +world shared-world { + import shared-items; + + export shared-items; + + type c = u32; + + import d: interface {} +} diff --git a/crates/wit-component/tests/merge/success/merge/foo.wit b/crates/wit-component/tests/merge/success/merge/foo.wit new file mode 100644 index 0000000000..6d99577b59 --- /dev/null +++ b/crates/wit-component/tests/merge/success/merge/foo.wit @@ -0,0 +1,47 @@ +package foo:foo + +interface only-into { + record r { + } + + foo: func() -> r +} + +interface shared-only-into { + variant v { + c1, + } + + bar: func(x: v) +} + +interface shared-items { + type a = u32 +} + +interface only-from { + record r { + } + + foo: func() -> r +} + +interface shared-only-from { + use foo:only-from-dep/a.{a} + + variant v { + c1, + } + + bar: func(x: v) +} + +world shared-world { + import shared-items + import d: interface { + } + + type c = u32 + + export shared-items +} diff --git a/crates/wit-component/tests/merge/success/merge/from.wit b/crates/wit-component/tests/merge/success/merge/from.wit new file mode 100644 index 0000000000..3561136b84 --- /dev/null +++ b/crates/wit-component/tests/merge/success/merge/from.wit @@ -0,0 +1,8 @@ +package foo:%from + +interface a { + use foo:foo/only-from.{r} + + foo: func() +} + diff --git a/crates/wit-component/tests/merge/success/merge/into.wit b/crates/wit-component/tests/merge/success/merge/into.wit new file mode 100644 index 0000000000..4e61e7f5c4 --- /dev/null +++ b/crates/wit-component/tests/merge/success/merge/into.wit @@ -0,0 +1,8 @@ +package foo:into + +interface b { + use foo:foo/only-into.{r} + + foo: func() +} + diff --git a/crates/wit-component/tests/merge/success/merge/only-from-dep.wit b/crates/wit-component/tests/merge/success/merge/only-from-dep.wit new file mode 100644 index 0000000000..3381d36cda --- /dev/null +++ b/crates/wit-component/tests/merge/success/merge/only-from-dep.wit @@ -0,0 +1,6 @@ +package foo:only-from-dep + +interface a { + type a = u32 +} + diff --git a/crates/wit-component/tests/targets.rs b/crates/wit-component/tests/targets.rs new file mode 100644 index 0000000000..23579b7f50 --- /dev/null +++ b/crates/wit-component/tests/targets.rs @@ -0,0 +1,93 @@ +use anyhow::{Context, Result}; +use std::{fs, path::Path}; +use wit_parser::{Resolve, UnresolvedPackage, WorldId}; + +/// Tests whether a component targets a world. +/// +/// This test looks in the `targets/` directory for test cases. +/// +/// The expected input files for a test case are: +/// +/// * [required] `test.wat` -- contains the component to test +/// encoded as a component produced via the `embed` and `new` +/// subcommands of `wasm-tools component`. +/// * [required] `test.wit` -- WIT package describing the target +/// world to use when checking conformance. +/// +/// And the output file is: +/// * `error.txt` - the expected error message if the synthetic +/// component constructed for testing is a invalid component encoding. +/// NOTE: an invalid encoding here indicates that the targets check has failed. +/// +/// Run the test with the environment variable `BLESS` set to update `error.txt`. +/// +/// Each test is effectively executing as: +/// ```wasm-tools component targets -w foobar test.wit test.wat``` +#[test] +fn targets() -> Result<()> { + drop(env_logger::try_init()); + + for entry in fs::read_dir("tests/targets")? { + let path = entry?.path(); + if !path.is_dir() { + continue; + } + + let test_case = path.file_stem().unwrap().to_str().unwrap(); + println!("testing {test_case}"); + + let (resolve, world) = load_test_wit(&path)?; + + let component = wat::parse_file(path.join("test.wat")) + .with_context(|| "failed to parse component WAT".to_string())?; + + match wit_component::targets(&resolve, world, &component) { + Ok(_) => { + assert!( + !test_case.starts_with("error-"), + "should have failed targets check" + ); + } + Err(e) => { + assert!(test_case.starts_with("error-"), "{e:?}"); + assert_output(&path.join("error.txt"), &format!("{e:?}"))?; + } + } + } + + Ok(()) +} + +fn assert_output(expected: &Path, actual: &str) -> Result<()> { + if std::env::var_os("BLESS").is_some() { + fs::create_dir_all(expected.parent().unwrap())?; + fs::write(expected, actual).with_context(|| format!("failed to write {expected:?}"))?; + } else { + assert_eq!( + fs::read_to_string(expected) + .with_context(|| format!("failed to read {expected:?}"))? + .replace("\r\n", "\n"), + actual, + "expectation `{}` did not match actual", + expected.display(), + ); + } + Ok(()) +} + +fn load_test_wit(path: &Path) -> Result<(Resolve, WorldId)> { + const TEST_TARGET_WORLD_ID: &str = "foobar"; + + let test_wit_path = path.join("test.wit"); + let package = + UnresolvedPackage::parse_file(&test_wit_path).context("failed to parse WIT package")?; + + let mut resolve = Resolve::default(); + let package_id = resolve.push(package)?; + + let world_id = resolve + .select_world(package_id, Some(TEST_TARGET_WORLD_ID)) + .with_context(|| "failed to select world from package".to_string())?; + + Ok((resolve, world_id)) +} diff --git a/crates/wit-component/tests/targets/error-missing-export/error.txt b/crates/wit-component/tests/targets/error-missing-export/error.txt new file mode 100644 index 0000000000..ebfccba10d --- /dev/null +++ b/crates/wit-component/tests/targets/error-missing-export/error.txt @@ -0,0 +1,5 @@ +failed to validate encoded bytes + +Caused by: + type mismatch for import `foobar` + missing export named `test:foo/bar` (at offset 0x1d5) \ No newline at end of file diff --git a/crates/wit-component/tests/targets/error-missing-export/test.wat b/crates/wit-component/tests/targets/error-missing-export/test.wat new file mode 100644 index 0000000000..89a159ce6a --- /dev/null +++ b/crates/wit-component/tests/targets/error-missing-export/test.wat @@ -0,0 +1,39 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (func (;0;) (type 0) + unreachable + ) + (func (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 0) + (export "test:foo/foo#f" (func 0)) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 1)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "cabi_realloc" (core func (;0;))) + (type (;0;) (func)) + (alias core export 0 "test:foo/foo#f" (core func (;1;))) + (func (;0;) (type 0) (canon lift (core func 1))) + (component (;0;) + (type (;0;) (func)) + (import "import-func-f" (func (;0;) (type 0))) + (type (;1;) (func)) + (export (;1;) "f" (func 0) (func (type 1))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-f" (func 0)) + ) + ) + (@producers + (processed-by "wit-component" "0.11.0") + ) + (export (;1;) (interface "test:foo/foo") (instance 0)) +) \ No newline at end of file diff --git a/crates/wit-component/tests/targets/error-missing-export/test.wit b/crates/wit-component/tests/targets/error-missing-export/test.wit new file mode 100644 index 0000000000..d9112a6292 --- /dev/null +++ b/crates/wit-component/tests/targets/error-missing-export/test.wit @@ -0,0 +1,18 @@ +package test:foo; + +interface bar { + f: func(); +} + +interface foo { + f: func(); +} + +world foobar { + export bar; + export foo; +} + +world foo-only { + export foo; +} diff --git a/crates/wit-component/tests/targets/error-missing-import/error.txt b/crates/wit-component/tests/targets/error-missing-import/error.txt new file mode 100644 index 0000000000..3a55fb02c5 --- /dev/null +++ b/crates/wit-component/tests/targets/error-missing-import/error.txt @@ -0,0 +1,5 @@ +failed to validate encoded bytes + +Caused by: + type mismatch for import `foobar` + missing import named `test:foo/foo` (at offset 0x175) \ No newline at end of file diff --git a/crates/wit-component/tests/targets/error-missing-import/test.wat b/crates/wit-component/tests/targets/error-missing-import/test.wat new file mode 100644 index 0000000000..9ee1813480 --- /dev/null +++ b/crates/wit-component/tests/targets/error-missing-import/test.wat @@ -0,0 +1,37 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "f" (func (type 0))) + ) + ) + (import (interface "test:foo/foo") (instance (;0;) (type 0))) + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "test:foo/foo" "f" (func (;0;) (type 0))) + (func (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 0) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 1)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (alias export 0 "f" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;0;) + (export "f" (func 0)) + ) + (core instance (;1;) (instantiate 0 + (with "test:foo/foo" (instance 0)) + ) + ) + (@producers + (processed-by "wit-component" "0.11.0") + ) + (alias core export 1 "memory" (core memory (;0;))) + (alias core export 1 "cabi_realloc" (core func (;1;))) +) \ No newline at end of file diff --git a/crates/wit-component/tests/targets/error-missing-import/test.wit b/crates/wit-component/tests/targets/error-missing-import/test.wit new file mode 100644 index 0000000000..be6d4b910d --- /dev/null +++ b/crates/wit-component/tests/targets/error-missing-import/test.wit @@ -0,0 +1,13 @@ +package test:foo; + +interface foo { + f: func(); +} + +world foobar { + export foo; +} + +world imports { + import foo; +} diff --git a/crates/wit-component/tests/targets/success-empty/test.wat b/crates/wit-component/tests/targets/success-empty/test.wat new file mode 100644 index 0000000000..04743950ba --- /dev/null +++ b/crates/wit-component/tests/targets/success-empty/test.wat @@ -0,0 +1 @@ +(component) \ No newline at end of file diff --git a/crates/wit-component/tests/targets/success-empty/test.wit b/crates/wit-component/tests/targets/success-empty/test.wit new file mode 100644 index 0000000000..cd086dbdef --- /dev/null +++ b/crates/wit-component/tests/targets/success-empty/test.wit @@ -0,0 +1,9 @@ +package test:foo; + +interface foo { + f: func(); +} + +world foobar { + import foo; +} diff --git a/crates/wit-component/tests/targets/success/test.wat b/crates/wit-component/tests/targets/success/test.wat new file mode 100644 index 0000000000..ad10aeb1eb --- /dev/null +++ b/crates/wit-component/tests/targets/success/test.wat @@ -0,0 +1,56 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (func (;0;) (type 0) + unreachable + ) + (func (;1;) (type 0) + unreachable + ) + (func (;2;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 0) + (export "test:foo/bar#f" (func 0)) + (export "test:foo/foo#f" (func 1)) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 2)) + (@producers + (processed-by "wit-component" "0.11.0") + ) + ) + (core instance (;0;) (instantiate 0)) + (alias core export 0 "memory" (core memory (;0;))) + (alias core export 0 "cabi_realloc" (core func (;0;))) + (type (;0;) (func)) + (alias core export 0 "test:foo/bar#f" (core func (;1;))) + (func (;0;) (type 0) (canon lift (core func 1))) + (component (;0;) + (type (;0;) (func)) + (import "import-func-f" (func (;0;) (type 0))) + (type (;1;) (func)) + (export (;1;) "f" (func 0) (func (type 1))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-f" (func 0)) + ) + ) + (export (;1;) (interface "test:foo/bar") (instance 0)) + (alias core export 0 "test:foo/foo#f" (core func (;2;))) + (func (;1;) (type 0) (canon lift (core func 2))) + (component (;1;) + (type (;0;) (func)) + (import "import-func-f" (func (;0;) (type 0))) + (type (;1;) (func)) + (export (;1;) "f" (func 0) (func (type 1))) + ) + (instance (;2;) (instantiate 1 + (with "import-func-f" (func 1)) + ) + ) + (@producers + (processed-by "wit-component" "0.11.0") + ) + (export (;3;) (interface "test:foo/foo") (instance 2)) +) \ No newline at end of file diff --git a/crates/wit-component/tests/targets/success/test.wit b/crates/wit-component/tests/targets/success/test.wit new file mode 100644 index 0000000000..d6c437c706 --- /dev/null +++ b/crates/wit-component/tests/targets/success/test.wit @@ -0,0 +1,14 @@ +package test:foo; + +interface bar { + f: func(); +} + +interface foo { + f: func(); +} + +world foobar { + export bar; + export foo; +} diff --git a/crates/wit-component/tests/wit.rs b/crates/wit-component/tests/wit.rs new file mode 100644 index 0000000000..b4859b3365 --- /dev/null +++ b/crates/wit-component/tests/wit.rs @@ -0,0 +1,59 @@ +use anyhow::Result; +use wit_component::{is_wasm_binary_or_wat, parse_wit_from_path}; + +const EXAMPLE_MODULE_WAT: &str = r#" +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + ) +) +"#; + +/// Ensure that parse_wit_from_path works with directories +#[test] +fn parse_wit_dir() -> Result<()> { + drop(env_logger::try_init()); + + let (resolver, package_id) = parse_wit_from_path("tests/wit/parse-dir/wit")?; + assert!(resolver + .select_world(package_id, "foo-world".into()) + .is_ok()); + + Ok(()) +} + +/// Ensure that parse_wit_from_path works for a single file +#[test] +fn parse_wit_file() -> Result<()> { + drop(env_logger::try_init()); + + let (resolver, package_id) = parse_wit_from_path("tests/wit/parse-dir/wit/deps/bar/bar.wit")?; + resolver.select_world(package_id, "bar-world".into())?; + assert!(resolver + .interfaces + .iter() + .any(|(_, iface)| iface.name == Some("bar".into()))); + + Ok(()) +} + +/// Ensure that parse_with_from_path fails for missing paths +#[test] +fn parse_wit_missing_path() -> Result<()> { + drop(env_logger::try_init()); + + assert!(parse_wit_from_path("tests/nonexistent/path").is_err()); + + Ok(()) +} + +/// Ensure that is_wasm_binary_or_wat works for binaries +#[test] +fn check_wasm_from_bytes() -> Result<()> { + drop(env_logger::try_init()); + + assert!(is_wasm_binary_or_wat(wat::parse_str(EXAMPLE_MODULE_WAT)?)); + + Ok(()) +} diff --git a/crates/wit-component/tests/wit/parse-dir/wit/deps/bar/bar.wit b/crates/wit-component/tests/wit/parse-dir/wit/deps/bar/bar.wit new file mode 100644 index 0000000000..e99a448580 --- /dev/null +++ b/crates/wit-component/tests/wit/parse-dir/wit/deps/bar/bar.wit @@ -0,0 +1,9 @@ +package foo:bar; + +interface bar { + f: func() -> bool; +} + +world bar-world { + export bar; +} \ No newline at end of file diff --git a/crates/wit-component/tests/wit/parse-dir/wit/world.wit b/crates/wit-component/tests/wit/parse-dir/wit/world.wit new file mode 100644 index 0000000000..e3c326bd5d --- /dev/null +++ b/crates/wit-component/tests/wit/parse-dir/wit/world.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo-world { + import foo:bar/bar; +} diff --git a/crates/wit-parser/.gitignore b/crates/wit-parser/.gitignore new file mode 100644 index 0000000000..a9d37c560c --- /dev/null +++ b/crates/wit-parser/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/crates/wit-parser/Cargo.toml b/crates/wit-parser/Cargo.toml new file mode 100644 index 0000000000..b99a2b56ce --- /dev/null +++ b/crates/wit-parser/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "wit-parser" +authors = ["Alex Crichton "] +version = "0.12.0" +edition.workspace = true +license = "Apache-2.0 WITH LLVM-exception" +readme = "README.md" +repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-parser" +homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-parser" +documentation = "https://docs.rs/wit-parser" +description = """ +Tooling for parsing `*.wit` files and working with their contents. +""" + +[dependencies] +id-arena = "2" +anyhow = { workspace = true } +indexmap = { workspace = true, features = ["serde"] } +unicode-xid = "0.2.2" +log = { workspace = true } +semver = { workspace = true } +serde = { workspace = true } +serde_derive = { workspace = true } +serde_json = "1.0.105" + +[dev-dependencies] +rayon = "1" +env_logger = { workspace = true } +pretty_assertions = { workspace = true } + +[[test]] +name = "all" +harness = false diff --git a/crates/wit-parser/README.md b/crates/wit-parser/README.md new file mode 100644 index 0000000000..f82dc2651a --- /dev/null +++ b/crates/wit-parser/README.md @@ -0,0 +1,13 @@ +# `wit-parser` + +A Rust crate for parsing and interpreting the [`*.wit`][wit] text format. This +text format is used to describe the imports and exports of a [component]. + +[wit]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md +[component]: https://github.com/webassembly/component-model + +This crate is a low-level tooling crate which is intended to be integrated +further into toolchains elsewhere and isn't necessarily interacted with on a +day-to-day basis. Internally it supports parsing a `*.wit` document into a +structured AST. Additionally it implements mechanisms of the canonical ABI to +assist in binding the canonical ABI into various languages. diff --git a/crates/wit-parser/fuzz/.gitignore b/crates/wit-parser/fuzz/.gitignore new file mode 100644 index 0000000000..ff2738685d --- /dev/null +++ b/crates/wit-parser/fuzz/.gitignore @@ -0,0 +1,2 @@ +artifacts +corpus diff --git a/crates/wit-parser/fuzz/Cargo.toml b/crates/wit-parser/fuzz/Cargo.toml new file mode 100644 index 0000000000..6be0c5262c --- /dev/null +++ b/crates/wit-parser/fuzz/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "wit-parser-fuzz" +version = "0.0.1" +publish = false +edition.workspace = true + +[package.metadata] +cargo-fuzz = true + +[dependencies] +arbitrary = { workspace = true, features = ['derive'] } +env_logger = { workspace = true } +libfuzzer-sys = { workspace = true } +log = { workspace = true } +wasmprinter = { workspace = true } +wit-parser = { workspace = true } + +[[bin]] +name = "parse" +path = "fuzz_targets/parse.rs" +test = false +doc = false diff --git a/crates/wit-parser/fuzz/fuzz_targets/parse.rs b/crates/wit-parser/fuzz/fuzz_targets/parse.rs new file mode 100644 index 0000000000..4bc47fb839 --- /dev/null +++ b/crates/wit-parser/fuzz/fuzz_targets/parse.rs @@ -0,0 +1,14 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: &[u8]| { + drop(env_logger::try_init()); + + let data = match std::str::from_utf8(data) { + Ok(s) => s, + Err(_) => return, + }; + + drop(wit_parser::UnresolvedPackage::parse("foo".as_ref(), &data)); +}); diff --git a/crates/wit-parser/src/abi.rs b/crates/wit-parser/src/abi.rs new file mode 100644 index 0000000000..b542acf000 --- /dev/null +++ b/crates/wit-parser/src/abi.rs @@ -0,0 +1,241 @@ +use crate::{Function, Handle, Int, Resolve, Type, TypeDefKind}; + +/// A raw WebAssembly signature with params and results. +#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] +pub struct WasmSignature { + /// The WebAssembly parameters of this function. + pub params: Vec, + + /// The WebAssembly results of this function. + pub results: Vec, + + /// Whether or not this signature is passing all of its parameters + /// indirectly through a pointer within `params`. + /// + /// Note that `params` still reflects the true wasm paramters of this + /// function, this is auxiliary information for code generators if + /// necessary. + pub indirect_params: bool, + + /// Whether or not this signature is using a return pointer to store the + /// result of the function, which is reflected either in `params` or + /// `results` depending on the context this function is used (e.g. an import + /// or an export). + pub retptr: bool, +} + +/// Enumerates wasm types used by interface types when lowering/lifting. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum WasmType { + I32, + I64, + F32, + F64, + // NOTE: we don't lower interface types to any other Wasm type, + // e.g. externref, so we don't need to define them here. +} + +fn join(a: WasmType, b: WasmType) -> WasmType { + use WasmType::*; + + match (a, b) { + (I32, I32) | (I64, I64) | (F32, F32) | (F64, F64) => a, + + (I32, F32) | (F32, I32) => I32, + + (_, I64 | F64) | (I64 | F64, _) => I64, + } +} + +impl From for WasmType { + fn from(i: Int) -> WasmType { + match i { + Int::U8 | Int::U16 | Int::U32 => WasmType::I32, + Int::U64 => WasmType::I64, + } + } +} + +/// We use a different ABI for wasm importing functions exported by the host +/// than for wasm exporting functions imported by the host. +/// +/// Note that this reflects the flavor of ABI we generate, and not necessarily +/// the way the resulting bindings will be used by end users. See the comments +/// on the `Direction` enum in gen-core for details. +/// +/// The bindings ABI has a concept of a "guest" and a "host". There are two +/// variants of the ABI, one specialized for the "guest" importing and calling +/// a function defined and exported in the "host", and the other specialized for +/// the "host" importing and calling a function defined and exported in the "guest". +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum AbiVariant { + /// The guest is importing and calling the function. + GuestImport, + /// The guest is defining and exporting the function. + GuestExport, +} + +impl Resolve { + /// Get the WebAssembly type signature for this interface function + /// + /// The first entry returned is the list of parameters and the second entry + /// is the list of results for the wasm function signature. + pub fn wasm_signature(&self, variant: AbiVariant, func: &Function) -> WasmSignature { + const MAX_FLAT_PARAMS: usize = 16; + const MAX_FLAT_RESULTS: usize = 1; + + let mut params = Vec::new(); + let mut indirect_params = false; + for (_, param) in func.params.iter() { + self.push_flat(param, &mut params); + } + + if params.len() > MAX_FLAT_PARAMS { + params.truncate(0); + params.push(WasmType::I32); + indirect_params = true; + } + + let mut results = Vec::new(); + for ty in func.results.iter_types() { + self.push_flat(ty, &mut results) + } + + let mut retptr = false; + + // Rust/C don't support multi-value well right now, so if a function + // would have multiple results then instead truncate it. Imports take a + // return pointer to write into and exports return a pointer they wrote + // into. + if results.len() > MAX_FLAT_RESULTS { + retptr = true; + results.truncate(0); + match variant { + AbiVariant::GuestImport => { + params.push(WasmType::I32); + } + AbiVariant::GuestExport => { + results.push(WasmType::I32); + } + } + } + + WasmSignature { + params, + indirect_params, + results, + retptr, + } + } + + /// Appends the flat wasm types representing `ty` onto the `result` + /// list provided. + pub fn push_flat(&self, ty: &Type, result: &mut Vec) { + match ty { + Type::Bool + | Type::S8 + | Type::U8 + | Type::S16 + | Type::U16 + | Type::S32 + | Type::U32 + | Type::Char => result.push(WasmType::I32), + + Type::U64 | Type::S64 => result.push(WasmType::I64), + Type::Float32 => result.push(WasmType::F32), + Type::Float64 => result.push(WasmType::F64), + Type::String => { + result.push(WasmType::I32); + result.push(WasmType::I32); + } + + Type::Id(id) => match &self.types[*id].kind { + TypeDefKind::Type(t) => self.push_flat(t, result), + + TypeDefKind::Handle(Handle::Own(_) | Handle::Borrow(_)) => { + result.push(WasmType::I32); + } + + TypeDefKind::Resource => todo!(), + + TypeDefKind::Record(r) => { + for field in r.fields.iter() { + self.push_flat(&field.ty, result); + } + } + + TypeDefKind::Tuple(t) => { + for ty in t.types.iter() { + self.push_flat(ty, result); + } + } + + TypeDefKind::Flags(r) => { + for _ in 0..r.repr().count() { + result.push(WasmType::I32); + } + } + + TypeDefKind::List(_) => { + result.push(WasmType::I32); + result.push(WasmType::I32); + } + + TypeDefKind::Variant(v) => { + result.push(v.tag().into()); + self.push_flat_variants(v.cases.iter().map(|c| c.ty.as_ref()), result); + } + + TypeDefKind::Enum(e) => result.push(e.tag().into()), + + TypeDefKind::Option(t) => { + result.push(WasmType::I32); + self.push_flat_variants([None, Some(t)], result); + } + + TypeDefKind::Result(r) => { + result.push(WasmType::I32); + self.push_flat_variants([r.ok.as_ref(), r.err.as_ref()], result); + } + + TypeDefKind::Future(_) => { + result.push(WasmType::I32); + } + + TypeDefKind::Stream(_) => { + result.push(WasmType::I32); + } + + TypeDefKind::Unknown => unreachable!(), + }, + } + } + + fn push_flat_variants<'a>( + &self, + tys: impl IntoIterator>, + result: &mut Vec, + ) { + let mut temp = Vec::new(); + let start = result.len(); + + // Push each case's type onto a temporary vector, and then + // merge that vector into our final list starting at + // `start`. Note that this requires some degree of + // "unification" so we can handle things like `Result` where that turns into `[i32 i32]` where the second + // `i32` might be the `f32` bitcasted. + for ty in tys { + if let Some(ty) = ty { + self.push_flat(ty, &mut temp); + + for (i, ty) in temp.drain(..).enumerate() { + match result.get_mut(start + i) { + Some(prev) => *prev = join(*prev, ty), + None => result.push(ty), + } + } + } + } + } +} diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs new file mode 100644 index 0000000000..4f386c2603 --- /dev/null +++ b/crates/wit-parser/src/ast.rs @@ -0,0 +1,1340 @@ +use crate::{Error, UnresolvedPackage}; +use anyhow::{bail, Context, Result}; +use lex::{Span, Token, Tokenizer}; +use semver::Version; +use std::borrow::Cow; +use std::convert::TryFrom; +use std::fmt; +use std::path::{Path, PathBuf}; + +pub mod lex; + +pub use resolve::Resolver; +mod resolve; +pub mod toposort; + +pub use lex::validate_id; + +pub struct Ast<'a> { + package_id: Option>, + items: Vec>, +} + +impl<'a> Ast<'a> { + pub fn parse(lexer: &mut Tokenizer<'a>) -> Result { + let mut items = Vec::new(); + let mut package_id = None; + let mut docs = parse_docs(lexer)?; + if lexer.eat(Token::Package)? { + let package_docs = std::mem::take(&mut docs); + package_id = Some(PackageName::parse(lexer, package_docs)?); + lexer.expect_semicolon()?; + docs = parse_docs(lexer)?; + } + while lexer.clone().next()?.is_some() { + items.push(AstItem::parse(lexer, docs)?); + docs = parse_docs(lexer)?; + } + Ok(Self { package_id, items }) + } + + fn for_each_path<'b>( + &'b self, + mut f: impl FnMut( + Option<&'b Id<'a>>, + &'b UsePath<'a>, + Option<&'b [UseName<'a>]>, + WorldOrInterface, + ) -> Result<()>, + ) -> Result<()> { + for item in self.items.iter() { + match item { + AstItem::World(world) => { + // Visit imports here first before exports to help preserve + // round-tripping of documents because printing a world puts + // imports first but textually they can be listed with + // exports first. + let mut imports = Vec::new(); + let mut exports = Vec::new(); + for item in world.items.iter() { + match item { + WorldItem::Use(u) => { + f(None, &u.from, Some(&u.names), WorldOrInterface::Interface)? + } + WorldItem::Include(i) => { + f(Some(&world.name), &i.from, None, WorldOrInterface::World)? + } + WorldItem::Type(_) => {} + WorldItem::Import(Import { kind, .. }) => imports.push(kind), + WorldItem::Export(Export { kind, .. }) => exports.push(kind), + } + } + + let mut visit_kind = |kind: &'b ExternKind<'a>| match kind { + ExternKind::Interface(_, items) => { + for item in items { + match item { + InterfaceItem::Use(u) => f( + None, + &u.from, + Some(&u.names), + WorldOrInterface::Interface, + )?, + _ => {} + } + } + Ok(()) + } + ExternKind::Path(path) => f(None, path, None, WorldOrInterface::Interface), + ExternKind::Func(..) => Ok(()), + }; + + for kind in imports { + visit_kind(kind)?; + } + for kind in exports { + visit_kind(kind)?; + } + } + AstItem::Interface(i) => { + for item in i.items.iter() { + match item { + InterfaceItem::Use(u) => f( + Some(&i.name), + &u.from, + Some(&u.names), + WorldOrInterface::Interface, + )?, + _ => {} + } + } + } + AstItem::Use(u) => { + // At the top-level, we don't know if this is a world or an interface + // It is up to the resolver to decides how to handle this ambiguity. + f(None, &u.item, None, WorldOrInterface::Unknown)?; + } + } + } + Ok(()) + } +} + +enum AstItem<'a> { + Interface(Interface<'a>), + World(World<'a>), + Use(ToplevelUse<'a>), +} + +impl<'a> AstItem<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + match tokens.clone().next()? { + Some((_span, Token::Interface)) => Interface::parse(tokens, docs).map(Self::Interface), + Some((_span, Token::World)) => World::parse(tokens, docs).map(Self::World), + Some((_span, Token::Use)) => ToplevelUse::parse(tokens).map(Self::Use), + other => Err(err_expected(tokens, "`world`, `interface` or `use`", other).into()), + } + } +} + +#[derive(Debug, Clone)] +struct PackageName<'a> { + docs: Docs<'a>, + span: Span, + namespace: Id<'a>, + name: Id<'a>, + version: Option<(Span, Version)>, +} + +impl<'a> PackageName<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + let namespace = parse_id(tokens)?; + tokens.expect(Token::Colon)?; + let name = parse_id(tokens)?; + let version = parse_opt_version(tokens)?; + Ok(PackageName { + docs, + span: Span { + start: namespace.span.start, + end: version + .as_ref() + .map(|(s, _)| s.end) + .unwrap_or(name.span.end), + }, + namespace, + name, + version, + }) + } + + fn package_name(&self) -> crate::PackageName { + crate::PackageName { + namespace: self.namespace.name.to_string(), + name: self.name.name.to_string(), + version: self.version.as_ref().map(|(_, v)| v.clone()), + } + } +} + +struct ToplevelUse<'a> { + item: UsePath<'a>, + as_: Option>, +} + +impl<'a> ToplevelUse<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result { + tokens.expect(Token::Use)?; + let item = UsePath::parse(tokens)?; + let as_ = if tokens.eat(Token::As)? { + Some(parse_id(tokens)?) + } else { + None + }; + tokens.expect_semicolon()?; + Ok(ToplevelUse { item, as_ }) + } +} + +struct World<'a> { + docs: Docs<'a>, + name: Id<'a>, + items: Vec>, +} + +impl<'a> World<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + tokens.expect(Token::World)?; + let name = parse_id(tokens)?; + let items = Self::parse_items(tokens)?; + Ok(World { docs, name, items }) + } + + fn parse_items(tokens: &mut Tokenizer<'a>) -> Result>> { + tokens.expect(Token::LeftBrace)?; + let mut items = Vec::new(); + loop { + let docs = parse_docs(tokens)?; + if tokens.eat(Token::RightBrace)? { + break; + } + items.push(WorldItem::parse(tokens, docs)?); + } + Ok(items) + } +} + +enum WorldItem<'a> { + Import(Import<'a>), + Export(Export<'a>), + Use(Use<'a>), + Type(TypeDef<'a>), + Include(Include<'a>), +} + +impl<'a> WorldItem<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result> { + match tokens.clone().next()? { + Some((_span, Token::Import)) => Import::parse(tokens, docs).map(WorldItem::Import), + Some((_span, Token::Export)) => Export::parse(tokens, docs).map(WorldItem::Export), + Some((_span, Token::Use)) => Use::parse(tokens).map(WorldItem::Use), + Some((_span, Token::Type)) => TypeDef::parse(tokens, docs).map(WorldItem::Type), + Some((_span, Token::Flags)) => TypeDef::parse_flags(tokens, docs).map(WorldItem::Type), + Some((_span, Token::Resource)) => { + TypeDef::parse_resource(tokens, docs).map(WorldItem::Type) + } + Some((_span, Token::Record)) => { + TypeDef::parse_record(tokens, docs).map(WorldItem::Type) + } + Some((_span, Token::Variant)) => { + TypeDef::parse_variant(tokens, docs).map(WorldItem::Type) + } + Some((_span, Token::Enum)) => TypeDef::parse_enum(tokens, docs).map(WorldItem::Type), + Some((_span, Token::Include)) => Include::parse(tokens).map(WorldItem::Include), + other => Err(err_expected( + tokens, + "`import`, `export`, `include`, `use`, or type definition", + other, + ) + .into()), + } + } +} + +struct Import<'a> { + docs: Docs<'a>, + kind: ExternKind<'a>, +} + +impl<'a> Import<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result> { + tokens.expect(Token::Import)?; + let kind = ExternKind::parse(tokens)?; + Ok(Import { docs, kind }) + } +} + +struct Export<'a> { + docs: Docs<'a>, + kind: ExternKind<'a>, +} + +impl<'a> Export<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result> { + tokens.expect(Token::Export)?; + let kind = ExternKind::parse(tokens)?; + Ok(Export { docs, kind }) + } +} + +enum ExternKind<'a> { + Interface(Id<'a>, Vec>), + Path(UsePath<'a>), + Func(Id<'a>, Func<'a>), +} + +impl<'a> ExternKind<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result> { + // Create a copy of the token stream to test out if this is a function + // or an interface import. In those situations the token stream gets + // reset to the state of the clone and we continue down those paths. + // + // If neither a function nor an interface appears here though then the + // clone is thrown away and the original token stream is parsed for an + // interface. This will redo the original ID parse and the original + // colon parse, but that shouldn't be too too bad perf-wise. + let mut clone = tokens.clone(); + let id = parse_id(&mut clone)?; + if clone.eat(Token::Colon)? { + // import foo: func(...) + if clone.clone().eat(Token::Func)? { + *tokens = clone; + let ret = ExternKind::Func(id, Func::parse(tokens)?); + tokens.expect_semicolon()?; + return Ok(ret); + } + + // import foo: interface { ... } + if clone.eat(Token::Interface)? { + *tokens = clone; + return Ok(ExternKind::Interface(id, Interface::parse_items(tokens)?)); + } + } + + // import foo + // import foo/bar + // import foo:bar/baz + let ret = ExternKind::Path(UsePath::parse(tokens)?); + tokens.expect_semicolon()?; + Ok(ret) + } + + fn span(&self) -> Span { + match self { + ExternKind::Interface(id, _) => id.span, + ExternKind::Path(UsePath::Id(id)) => id.span, + ExternKind::Path(UsePath::Package { name, .. }) => name.span, + ExternKind::Func(id, _) => id.span, + } + } +} + +struct Interface<'a> { + docs: Docs<'a>, + name: Id<'a>, + items: Vec>, +} + +impl<'a> Interface<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + tokens.expect(Token::Interface)?; + let name = parse_id(tokens)?; + let items = Self::parse_items(tokens)?; + Ok(Interface { docs, name, items }) + } + + pub(super) fn parse_items(tokens: &mut Tokenizer<'a>) -> Result>> { + tokens.expect(Token::LeftBrace)?; + let mut items = Vec::new(); + loop { + let docs = parse_docs(tokens)?; + if tokens.eat(Token::RightBrace)? { + break; + } + items.push(InterfaceItem::parse(tokens, docs)?); + } + Ok(items) + } +} + +#[derive(Debug)] +pub enum WorldOrInterface { + World, + Interface, + Unknown, +} + +enum InterfaceItem<'a> { + TypeDef(TypeDef<'a>), + Func(NamedFunc<'a>), + Use(Use<'a>), +} + +struct Use<'a> { + from: UsePath<'a>, + names: Vec>, +} + +#[derive(Debug)] +enum UsePath<'a> { + Id(Id<'a>), + Package { id: PackageName<'a>, name: Id<'a> }, +} + +impl<'a> UsePath<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result { + let id = parse_id(tokens)?; + if tokens.eat(Token::Colon)? { + // `foo:bar/baz@1.0` + let namespace = id; + let pkg_name = parse_id(tokens)?; + tokens.expect(Token::Slash)?; + let name = parse_id(tokens)?; + let version = parse_opt_version(tokens)?; + Ok(UsePath::Package { + id: PackageName { + docs: Default::default(), + span: Span { + start: namespace.span.start, + end: pkg_name.span.end, + }, + namespace, + name: pkg_name, + version, + }, + name, + }) + } else { + // `foo` + Ok(UsePath::Id(id)) + } + } + + fn name(&self) -> &Id<'a> { + match self { + UsePath::Id(id) => id, + UsePath::Package { name, .. } => name, + } + } +} + +struct UseName<'a> { + name: Id<'a>, + as_: Option>, +} + +impl<'a> Use<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result { + tokens.expect(Token::Use)?; + let from = UsePath::parse(tokens)?; + tokens.expect(Token::Period)?; + tokens.expect(Token::LeftBrace)?; + + let mut names = Vec::new(); + while !tokens.eat(Token::RightBrace)? { + let mut name = UseName { + name: parse_id(tokens)?, + as_: None, + }; + if tokens.eat(Token::As)? { + name.as_ = Some(parse_id(tokens)?); + } + names.push(name); + if !tokens.eat(Token::Comma)? { + tokens.expect(Token::RightBrace)?; + break; + } + } + tokens.expect_semicolon()?; + Ok(Use { from, names }) + } +} + +struct Include<'a> { + from: UsePath<'a>, + names: Vec>, +} + +struct IncludeName<'a> { + name: Id<'a>, + as_: Id<'a>, +} + +impl<'a> Include<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result { + tokens.expect(Token::Include)?; + let from = UsePath::parse(tokens)?; + + let names = if tokens.eat(Token::With)? { + parse_list( + tokens, + Token::LeftBrace, + Token::RightBrace, + |_docs, tokens| { + let name = parse_id(tokens)?; + tokens.expect(Token::As)?; + let as_ = parse_id(tokens)?; + Ok(IncludeName { name, as_ }) + }, + )? + } else { + tokens.expect_semicolon()?; + Vec::new() + }; + + Ok(Include { from, names }) + } +} + +#[derive(Debug, Clone)] +pub struct Id<'a> { + name: &'a str, + span: Span, +} + +impl<'a> From<&'a str> for Id<'a> { + fn from(s: &'a str) -> Id<'a> { + Id { + name: s.into(), + span: Span { start: 0, end: 0 }, + } + } +} + +#[derive(Debug, Clone)] +pub struct Docs<'a> { + docs: Vec>, + span: Span, +} + +impl<'a> Default for Docs<'a> { + fn default() -> Self { + Self { + docs: Default::default(), + span: Span { start: 0, end: 0 }, + } + } +} + +struct TypeDef<'a> { + docs: Docs<'a>, + name: Id<'a>, + ty: Type<'a>, +} + +enum Type<'a> { + Bool, + U8, + U16, + U32, + U64, + S8, + S16, + S32, + S64, + Float32, + Float64, + Char, + String, + Name(Id<'a>), + List(Box>), + Handle(Handle<'a>), + Resource(Resource<'a>), + Record(Record<'a>), + Flags(Flags<'a>), + Variant(Variant<'a>), + Tuple(Vec>), + Enum(Enum<'a>), + Option(Box>), + Result(Result_<'a>), + Future(Option>>), + Stream(Stream<'a>), +} + +enum Handle<'a> { + Own { resource: Id<'a> }, + Borrow { resource: Id<'a> }, +} + +struct Resource<'a> { + funcs: Vec>, +} + +enum ResourceFunc<'a> { + Method(NamedFunc<'a>), + Static(NamedFunc<'a>), + Constructor(NamedFunc<'a>), +} + +impl<'a> ResourceFunc<'a> { + fn parse(docs: Docs<'a>, tokens: &mut Tokenizer<'a>) -> Result { + match tokens.clone().next()? { + Some((span, Token::Constructor)) => { + tokens.expect(Token::Constructor)?; + tokens.expect(Token::LeftParen)?; + let params = parse_list_trailer(tokens, Token::RightParen, |_docs, tokens| { + let name = parse_id(tokens)?; + tokens.expect(Token::Colon)?; + let ty = Type::parse(tokens)?; + Ok((name, ty)) + })?; + tokens.expect_semicolon()?; + Ok(ResourceFunc::Constructor(NamedFunc { + docs, + name: Id { + span, + name: "constructor", + }, + func: Func { + params, + results: ResultList::Named(Vec::new()), + }, + })) + } + Some((_span, Token::Id | Token::ExplicitId)) => { + let name = parse_id(tokens)?; + tokens.expect(Token::Colon)?; + let ctor = if tokens.eat(Token::Static)? { + ResourceFunc::Static + } else { + ResourceFunc::Method + }; + let func = Func::parse(tokens)?; + tokens.expect_semicolon()?; + Ok(ctor(NamedFunc { docs, name, func })) + } + other => Err(err_expected(tokens, "`constructor` or identifier", other).into()), + } + } + + fn named_func(&self) -> &NamedFunc<'a> { + use ResourceFunc::*; + match self { + Method(f) | Static(f) | Constructor(f) => f, + } + } +} + +struct Record<'a> { + fields: Vec>, +} + +struct Field<'a> { + docs: Docs<'a>, + name: Id<'a>, + ty: Type<'a>, +} + +struct Flags<'a> { + flags: Vec>, +} + +struct Flag<'a> { + docs: Docs<'a>, + name: Id<'a>, +} + +struct Variant<'a> { + span: Span, + cases: Vec>, +} + +struct Case<'a> { + docs: Docs<'a>, + name: Id<'a>, + ty: Option>, +} + +struct Enum<'a> { + span: Span, + cases: Vec>, +} + +struct EnumCase<'a> { + docs: Docs<'a>, + name: Id<'a>, +} + +struct Result_<'a> { + ok: Option>>, + err: Option>>, +} + +struct Stream<'a> { + element: Option>>, + end: Option>>, +} + +struct NamedFunc<'a> { + docs: Docs<'a>, + name: Id<'a>, + func: Func<'a>, +} + +type ParamList<'a> = Vec<(Id<'a>, Type<'a>)>; + +enum ResultList<'a> { + Named(ParamList<'a>), + Anon(Type<'a>), +} + +struct Func<'a> { + params: ParamList<'a>, + results: ResultList<'a>, +} + +impl<'a> Func<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result> { + fn parse_params<'a>(tokens: &mut Tokenizer<'a>, left_paren: bool) -> Result> { + if left_paren { + tokens.expect(Token::LeftParen)?; + }; + parse_list_trailer(tokens, Token::RightParen, |_docs, tokens| { + let name = parse_id(tokens)?; + tokens.expect(Token::Colon)?; + let ty = Type::parse(tokens)?; + Ok((name, ty)) + }) + } + + tokens.expect(Token::Func)?; + let params = parse_params(tokens, true)?; + let results = if tokens.eat(Token::RArrow)? { + // If we eat a '(', parse the remainder of the named + // result types. Otherwise parse a single anonymous type. + if tokens.eat(Token::LeftParen)? { + let results = parse_params(tokens, false)?; + ResultList::Named(results) + } else { + let ty = Type::parse(tokens)?; + ResultList::Anon(ty) + } + } else { + ResultList::Named(Vec::new()) + }; + Ok(Func { params, results }) + } +} + +impl<'a> InterfaceItem<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result> { + match tokens.clone().next()? { + Some((_span, Token::Type)) => TypeDef::parse(tokens, docs).map(InterfaceItem::TypeDef), + Some((_span, Token::Flags)) => { + TypeDef::parse_flags(tokens, docs).map(InterfaceItem::TypeDef) + } + Some((_span, Token::Enum)) => { + TypeDef::parse_enum(tokens, docs).map(InterfaceItem::TypeDef) + } + Some((_span, Token::Variant)) => { + TypeDef::parse_variant(tokens, docs).map(InterfaceItem::TypeDef) + } + Some((_span, Token::Resource)) => { + TypeDef::parse_resource(tokens, docs).map(InterfaceItem::TypeDef) + } + Some((_span, Token::Record)) => { + TypeDef::parse_record(tokens, docs).map(InterfaceItem::TypeDef) + } + Some((_span, Token::Id)) | Some((_span, Token::ExplicitId)) => { + NamedFunc::parse(tokens, docs).map(InterfaceItem::Func) + } + Some((_span, Token::Use)) => Use::parse(tokens).map(InterfaceItem::Use), + other => Err(err_expected(tokens, "`type`, `resource` or `func`", other).into()), + } + } +} + +impl<'a> TypeDef<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + tokens.expect(Token::Type)?; + let name = parse_id(tokens)?; + tokens.expect(Token::Equals)?; + let ty = Type::parse(tokens)?; + tokens.expect_semicolon()?; + Ok(TypeDef { docs, name, ty }) + } + + fn parse_flags(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + tokens.expect(Token::Flags)?; + let name = parse_id(tokens)?; + let ty = Type::Flags(Flags { + flags: parse_list( + tokens, + Token::LeftBrace, + Token::RightBrace, + |docs, tokens| { + let name = parse_id(tokens)?; + Ok(Flag { docs, name }) + }, + )?, + }); + Ok(TypeDef { docs, name, ty }) + } + + fn parse_resource(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + tokens.expect(Token::Resource)?; + let name = parse_id(tokens)?; + let mut funcs = Vec::new(); + if tokens.eat(Token::LeftBrace)? { + while !tokens.eat(Token::RightBrace)? { + funcs.push(ResourceFunc::parse(parse_docs(tokens)?, tokens)?); + } + } else { + tokens.expect_semicolon()?; + } + let ty = Type::Resource(Resource { funcs }); + Ok(TypeDef { docs, name, ty }) + } + + fn parse_record(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + tokens.expect(Token::Record)?; + let name = parse_id(tokens)?; + let ty = Type::Record(Record { + fields: parse_list( + tokens, + Token::LeftBrace, + Token::RightBrace, + |docs, tokens| { + let name = parse_id(tokens)?; + tokens.expect(Token::Colon)?; + let ty = Type::parse(tokens)?; + Ok(Field { docs, name, ty }) + }, + )?, + }); + Ok(TypeDef { docs, name, ty }) + } + + fn parse_variant(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + tokens.expect(Token::Variant)?; + let name = parse_id(tokens)?; + let ty = Type::Variant(Variant { + span: name.span, + cases: parse_list( + tokens, + Token::LeftBrace, + Token::RightBrace, + |docs, tokens| { + let name = parse_id(tokens)?; + let ty = if tokens.eat(Token::LeftParen)? { + let ty = Type::parse(tokens)?; + tokens.expect(Token::RightParen)?; + Some(ty) + } else { + None + }; + Ok(Case { docs, name, ty }) + }, + )?, + }); + Ok(TypeDef { docs, name, ty }) + } + + fn parse_enum(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + tokens.expect(Token::Enum)?; + let name = parse_id(tokens)?; + let ty = Type::Enum(Enum { + span: name.span, + cases: parse_list( + tokens, + Token::LeftBrace, + Token::RightBrace, + |docs, tokens| { + let name = parse_id(tokens)?; + Ok(EnumCase { docs, name }) + }, + )?, + }); + Ok(TypeDef { docs, name, ty }) + } +} + +impl<'a> NamedFunc<'a> { + fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { + let name = parse_id(tokens)?; + tokens.expect(Token::Colon)?; + let func = Func::parse(tokens)?; + tokens.expect_semicolon()?; + Ok(NamedFunc { docs, name, func }) + } +} + +fn parse_id<'a>(tokens: &mut Tokenizer<'a>) -> Result> { + match tokens.next()? { + Some((span, Token::Id)) => Ok(Id { + name: tokens.parse_id(span)?, + span, + }), + Some((span, Token::ExplicitId)) => Ok(Id { + name: tokens.parse_explicit_id(span)?, + span, + }), + other => Err(err_expected(tokens, "an identifier or string", other).into()), + } +} + +fn parse_opt_version(tokens: &mut Tokenizer<'_>) -> Result> { + if !tokens.eat(Token::At)? { + return Ok(None); + } + let start = tokens.expect(Token::Integer)?.start; + tokens.expect(Token::Period)?; + tokens.expect(Token::Integer)?; + tokens.expect(Token::Period)?; + let end = tokens.expect(Token::Integer)?.end; + let mut span = Span { start, end }; + eat_ids(tokens, Token::Minus, &mut span)?; + eat_ids(tokens, Token::Plus, &mut span)?; + let string = tokens.get_span(span); + let version = Version::parse(string).map_err(|e| Error { + span, + msg: e.to_string(), + })?; + return Ok(Some((span, version))); + + fn eat_ids(tokens: &mut Tokenizer<'_>, prefix: Token, end: &mut Span) -> Result<()> { + if !tokens.eat(prefix)? { + return Ok(()); + } + loop { + match tokens.next()? { + Some((span, Token::Id)) | Some((span, Token::Integer)) => end.end = span.end, + other => break Err(err_expected(tokens, "an id or integer", other).into()), + } + + // If there's no trailing period, then this semver identifier is + // done. + let mut clone = tokens.clone(); + if !clone.eat(Token::Period)? { + break Ok(()); + } + + // If there's more to the identifier, then eat the period for real + // and continue + if clone.eat(Token::Id)? || clone.eat(Token::Integer)? { + tokens.eat(Token::Period)?; + continue; + } + + // Otherwise for something like `use foo:bar/baz@1.2.3+foo.{` stop + // the parsing here. + break Ok(()); + } + } +} + +fn parse_docs<'a>(tokens: &mut Tokenizer<'a>) -> Result> { + let mut docs = Docs::default(); + let mut clone = tokens.clone(); + let mut started = false; + while let Some((span, token)) = clone.next_raw()? { + match token { + Token::Whitespace => {} + Token::Comment => { + let comment = tokens.get_span(span); + if comment.starts_with("///") || (comment.starts_with("/**") && comment != "/**/") { + if !started { + docs.span.start = span.start; + started = true; + } + let trailing_ws = comment + .bytes() + .rev() + .take_while(|ch| ch.is_ascii_whitespace()) + .count(); + docs.span.end = span.end - (trailing_ws as u32); + docs.docs.push(comment.into()); + } + } + _ => break, + }; + *tokens = clone.clone(); + } + Ok(docs) +} + +impl<'a> Type<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result { + match tokens.next()? { + Some((_span, Token::U8)) => Ok(Type::U8), + Some((_span, Token::U16)) => Ok(Type::U16), + Some((_span, Token::U32)) => Ok(Type::U32), + Some((_span, Token::U64)) => Ok(Type::U64), + Some((_span, Token::S8)) => Ok(Type::S8), + Some((_span, Token::S16)) => Ok(Type::S16), + Some((_span, Token::S32)) => Ok(Type::S32), + Some((_span, Token::S64)) => Ok(Type::S64), + Some((_span, Token::Float32)) => Ok(Type::Float32), + Some((_span, Token::Float64)) => Ok(Type::Float64), + Some((_span, Token::Char)) => Ok(Type::Char), + + // tuple + Some((_span, Token::Tuple)) => { + let types = parse_list( + tokens, + Token::LessThan, + Token::GreaterThan, + |_docs, tokens| Type::parse(tokens), + )?; + Ok(Type::Tuple(types)) + } + + Some((_span, Token::Bool)) => Ok(Type::Bool), + Some((_span, Token::String_)) => Ok(Type::String), + + // list + Some((_span, Token::List)) => { + tokens.expect(Token::LessThan)?; + let ty = Type::parse(tokens)?; + tokens.expect(Token::GreaterThan)?; + Ok(Type::List(Box::new(ty))) + } + + // option + Some((_span, Token::Option_)) => { + tokens.expect(Token::LessThan)?; + let ty = Type::parse(tokens)?; + tokens.expect(Token::GreaterThan)?; + Ok(Type::Option(Box::new(ty))) + } + + // result + // result<_, E> + // result + // result + Some((_span, Token::Result_)) => { + let mut ok = None; + let mut err = None; + + if tokens.eat(Token::LessThan)? { + if tokens.eat(Token::Underscore)? { + tokens.expect(Token::Comma)?; + err = Some(Box::new(Type::parse(tokens)?)); + } else { + ok = Some(Box::new(Type::parse(tokens)?)); + if tokens.eat(Token::Comma)? { + err = Some(Box::new(Type::parse(tokens)?)); + } + }; + tokens.expect(Token::GreaterThan)?; + }; + Ok(Type::Result(Result_ { ok, err })) + } + + // future + // future + Some((_span, Token::Future)) => { + let mut ty = None; + + if tokens.eat(Token::LessThan)? { + ty = Some(Box::new(Type::parse(tokens)?)); + tokens.expect(Token::GreaterThan)?; + }; + Ok(Type::Future(ty)) + } + + // stream + // stream<_, Z> + // stream + // stream + Some((_span, Token::Stream)) => { + let mut element = None; + let mut end = None; + + if tokens.eat(Token::LessThan)? { + if tokens.eat(Token::Underscore)? { + tokens.expect(Token::Comma)?; + end = Some(Box::new(Type::parse(tokens)?)); + } else { + element = Some(Box::new(Type::parse(tokens)?)); + if tokens.eat(Token::Comma)? { + end = Some(Box::new(Type::parse(tokens)?)); + } + }; + tokens.expect(Token::GreaterThan)?; + }; + Ok(Type::Stream(Stream { element, end })) + } + + // own + Some((_span, Token::Own)) => { + tokens.expect(Token::LessThan)?; + let resource = parse_id(tokens)?; + tokens.expect(Token::GreaterThan)?; + Ok(Type::Handle(Handle::Own { resource })) + } + + // borrow + Some((_span, Token::Borrow)) => { + tokens.expect(Token::LessThan)?; + let resource = parse_id(tokens)?; + tokens.expect(Token::GreaterThan)?; + Ok(Type::Handle(Handle::Borrow { resource })) + } + + // `foo` + Some((span, Token::Id)) => Ok(Type::Name(Id { + name: tokens.parse_id(span)?.into(), + span, + })), + // `%foo` + Some((span, Token::ExplicitId)) => Ok(Type::Name(Id { + name: tokens.parse_explicit_id(span)?.into(), + span, + })), + + other => Err(err_expected(tokens, "a type", other).into()), + } + } +} + +fn parse_list<'a, T>( + tokens: &mut Tokenizer<'a>, + start: Token, + end: Token, + parse: impl FnMut(Docs<'a>, &mut Tokenizer<'a>) -> Result, +) -> Result> { + tokens.expect(start)?; + parse_list_trailer(tokens, end, parse) +} + +fn parse_list_trailer<'a, T>( + tokens: &mut Tokenizer<'a>, + end: Token, + mut parse: impl FnMut(Docs<'a>, &mut Tokenizer<'a>) -> Result, +) -> Result> { + let mut items = Vec::new(); + loop { + // get docs before we skip them to try to eat the end token + let docs = parse_docs(tokens)?; + + // if we found an end token then we're done + if tokens.eat(end)? { + break; + } + + let item = parse(docs, tokens)?; + items.push(item); + + // if there's no trailing comma then this is required to be the end, + // otherwise we go through the loop to try to get another item + if !tokens.eat(Token::Comma)? { + tokens.expect(end)?; + break; + } + } + Ok(items) +} + +fn err_expected( + tokens: &Tokenizer<'_>, + expected: &'static str, + found: Option<(Span, Token)>, +) -> Error { + match found { + Some((span, token)) => Error { + span, + msg: format!("expected {}, found {}", expected, token.describe()), + }, + None => Error { + span: Span { + start: u32::try_from(tokens.input().len()).unwrap(), + end: u32::try_from(tokens.input().len()).unwrap(), + }, + msg: format!("expected {}, found eof", expected), + }, + } +} + +/// A listing of source files which are used to get parsed into an +/// [`UnresolvedPackage`]. +#[derive(Clone, Default)] +pub struct SourceMap { + sources: Vec, + offset: u32, + require_semicolons: Option, +} + +#[derive(Clone)] +struct Source { + offset: u32, + path: PathBuf, + contents: String, +} + +impl SourceMap { + /// Creates a new empty source map. + pub fn new() -> SourceMap { + SourceMap::default() + } + + #[doc(hidden)] // NB: only here for a transitionary period + pub fn set_require_semicolons(&mut self, enable: bool) { + self.require_semicolons = Some(enable); + } + + /// Reads the file `path` on the filesystem and appends its contents to this + /// [`SourceMap`]. + pub fn push_file(&mut self, path: &Path) -> Result<()> { + let contents = std::fs::read_to_string(path) + .with_context(|| format!("failed to read file {path:?}"))?; + self.push(path, contents); + Ok(()) + } + + /// Appends the given contents with the given path into this source map. + /// + /// The `path` provided is not read from the filesystem and is instead only + /// used during error messages. Each file added to a [`SourceMap`] is + /// used to create the final parsed package namely by unioning all the + /// interfaces and worlds defined together. Note that each file has its own + /// personal namespace, however, for top-level `use` and such. + pub fn push(&mut self, path: &Path, contents: impl Into) { + let contents = contents.into(); + let new_offset = self.offset + u32::try_from(contents.len()).unwrap(); + self.sources.push(Source { + offset: self.offset, + path: path.to_path_buf(), + contents, + }); + self.offset = new_offset; + } + + /// Parses the files added to this source map into an [`UnresolvedPackage`]. + pub fn parse(self) -> Result { + let mut doc = self.rewrite_error(|| { + let mut resolver = Resolver::default(); + let mut srcs = self.sources.iter().collect::>(); + srcs.sort_by_key(|src| &src.path); + for src in srcs { + let mut tokens = Tokenizer::new(&src.contents, src.offset, self.require_semicolons) + .with_context(|| format!("failed to tokenize path: {}", src.path.display()))?; + let ast = Ast::parse(&mut tokens)?; + resolver.push(ast).with_context(|| { + format!("failed to start resolving path: {}", src.path.display()) + })?; + } + resolver.resolve() + })?; + doc.source_map = self; + Ok(doc) + } + + pub(crate) fn rewrite_error(&self, f: F) -> Result + where + F: FnOnce() -> Result, + { + let err = match f() { + Ok(t) => return Ok(t), + Err(e) => e, + }; + if let Some(parse) = err.downcast_ref::() { + let msg = self.highlight_err(parse.span.start, Some(parse.span.end), parse); + bail!("{msg}") + } + + if let Some(lex) = err.downcast_ref::() { + let pos = match lex { + lex::Error::Unexpected(at, _) + | lex::Error::UnterminatedComment(at) + | lex::Error::Wanted { at, .. } + | lex::Error::InvalidCharInId(at, _) + | lex::Error::IdPartEmpty(at) + | lex::Error::InvalidEscape(at, _) => *at, + }; + let msg = self.highlight_err(pos, None, lex); + bail!("{msg}") + } + + if let Some(sort) = err.downcast_ref::() { + let span = match sort { + toposort::Error::NonexistentDep { span, .. } + | toposort::Error::Cycle { span, .. } => *span, + }; + let msg = self.highlight_err(span.start, Some(span.end), sort); + bail!("{msg}") + } + + Err(err) + } + + fn highlight_err(&self, start: u32, end: Option, err: impl fmt::Display) -> String { + let i = match self.sources.binary_search_by_key(&start, |src| src.offset) { + Ok(i) => i, + Err(i) => i - 1, + }; + let src = &self.sources[i]; + let start = usize::try_from(start - src.offset).unwrap(); + let end = end.map(|end| usize::try_from(end - src.offset).unwrap()); + let (line, col) = linecol_in(start, &src.contents); + let snippet = src.contents.lines().nth(line).unwrap_or(""); + let mut msg = format!( + "\ +{err} + --> {file}:{line}:{col} + | + {line:4} | {snippet} + | {marker:>0$}", + col + 1, + file = src.path.display(), + line = line + 1, + col = col + 1, + marker = "^", + ); + if let Some(end) = end { + if let Some(s) = src.contents.get(start..end) { + for _ in s.chars().skip(1) { + msg.push('-'); + } + } + } + return msg; + + fn linecol_in(pos: usize, text: &str) -> (usize, usize) { + let mut cur = 0; + // Use split_terminator instead of lines so that if there is a `\r`, + // it is included in the offset calculation. The `+1` values below + // account for the `\n`. + for (i, line) in text.split_terminator('\n').enumerate() { + if cur + line.len() + 1 > pos { + return (i, pos - cur); + } + cur += line.len() + 1; + } + (text.lines().count(), 0) + } + } + + /// Returns an iterator over all filenames added to this source map. + pub fn source_files(&self) -> impl Iterator { + self.sources.iter().map(|src| src.path.as_path()) + } +} + +pub(crate) enum AstUsePath { + Name(String), + Package(crate::PackageName, String), +} + +pub(crate) fn parse_use_path(s: &str) -> Result { + let mut tokens = Tokenizer::new(s, 0, Some(true))?; + let path = UsePath::parse(&mut tokens)?; + if tokens.next()?.is_some() { + bail!("trailing tokens in path specifier"); + } + Ok(match path { + UsePath::Id(id) => AstUsePath::Name(id.name.to_string()), + UsePath::Package { id, name } => { + AstUsePath::Package(id.package_name(), name.name.to_string()) + } + }) +} diff --git a/crates/wit-parser/src/ast/lex.rs b/crates/wit-parser/src/ast/lex.rs new file mode 100644 index 0000000000..fb7a5e2ba7 --- /dev/null +++ b/crates/wit-parser/src/ast/lex.rs @@ -0,0 +1,737 @@ +use anyhow::{bail, Result}; +use std::char; +use std::convert::TryFrom; +use std::fmt; +use std::str; +use unicode_xid::UnicodeXID; + +use self::Token::*; + +#[derive(Clone)] +pub struct Tokenizer<'a> { + input: &'a str, + span_offset: u32, + chars: CrlfFold<'a>, + require_semicolons: bool, +} + +#[derive(Clone)] +struct CrlfFold<'a> { + chars: str::CharIndices<'a>, +} + +/// A span, designating a range of bytes where a token is located. +#[derive(Eq, PartialEq, Debug, Clone, Copy)] +pub struct Span { + /// The start of the range. + pub start: u32, + /// The end of the range (exclusive). + pub end: u32, +} + +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum Token { + Whitespace, + Comment, + + Equals, + Comma, + Colon, + Period, + Semicolon, + LeftParen, + RightParen, + LeftBrace, + RightBrace, + LessThan, + GreaterThan, + RArrow, + Star, + At, + Slash, + Plus, + Minus, + + Use, + Type, + Func, + U8, + U16, + U32, + U64, + S8, + S16, + S32, + S64, + Float32, + Float64, + Char, + Record, + Resource, + Own, + Borrow, + Flags, + Variant, + Enum, + Bool, + String_, + Option_, + Result_, + Future, + Stream, + List, + Underscore, + As, + From_, + Static, + Interface, + Tuple, + Import, + Export, + World, + Package, + Constructor, + + Id, + ExplicitId, + + Integer, + + Include, + With, +} + +#[derive(Eq, PartialEq, Debug)] +#[allow(dead_code)] +pub enum Error { + InvalidCharInId(u32, char), + IdPartEmpty(u32), + InvalidEscape(u32, char), + Unexpected(u32, char), + UnterminatedComment(u32), + Wanted { + at: u32, + expected: &'static str, + found: &'static str, + }, +} + +// NB: keep in sync with `crates/wit-component/src/printing.rs`. +const REQUIRE_SEMICOLONS_BY_DEFAULT: bool = false; + +impl<'a> Tokenizer<'a> { + pub fn new( + input: &'a str, + span_offset: u32, + require_semicolons: Option, + ) -> Result> { + detect_invalid_input(input)?; + + let mut t = Tokenizer { + input, + span_offset, + chars: CrlfFold { + chars: input.char_indices(), + }, + require_semicolons: require_semicolons.unwrap_or_else(|| { + match std::env::var("WIT_REQUIRE_SEMICOLONS") { + Ok(s) => s == "1", + Err(_) => REQUIRE_SEMICOLONS_BY_DEFAULT, + } + }), + }; + // Eat utf-8 BOM + t.eatc('\u{feff}'); + Ok(t) + } + + pub fn expect_semicolon(&mut self) -> Result<()> { + if self.require_semicolons { + self.expect(Token::Semicolon)?; + } else { + self.eat(Token::Semicolon)?; + } + Ok(()) + } + + pub fn input(&self) -> &'a str { + self.input + } + + pub fn get_span(&self, span: Span) -> &'a str { + let start = usize::try_from(span.start - self.span_offset).unwrap(); + let end = usize::try_from(span.end - self.span_offset).unwrap(); + &self.input[start..end] + } + + pub fn parse_id(&self, span: Span) -> Result<&'a str> { + let ret = self.get_span(span); + validate_id(span.start, &ret)?; + Ok(ret) + } + + pub fn parse_explicit_id(&self, span: Span) -> Result<&'a str> { + let token = self.get_span(span); + let id_part = token.strip_prefix('%').unwrap(); + validate_id(span.start, id_part)?; + Ok(id_part) + } + + pub fn next(&mut self) -> Result, Error> { + loop { + match self.next_raw()? { + Some((_, Token::Whitespace)) | Some((_, Token::Comment)) => {} + other => break Ok(other), + } + } + } + + pub fn next_raw(&mut self) -> Result, Error> { + let (str_start, ch) = match self.chars.next() { + Some(pair) => pair, + None => return Ok(None), + }; + let start = self.span_offset + u32::try_from(str_start).unwrap(); + let token = match ch { + '\n' | '\t' | ' ' => { + // Eat all contiguous whitespace tokens + while self.eatc(' ') || self.eatc('\t') || self.eatc('\n') {} + Whitespace + } + '/' => { + // Eat a line comment if it's `//...` + if self.eatc('/') { + for (_, ch) in &mut self.chars { + if ch == '\n' { + break; + } + } + Comment + // eat a block comment if it's `/*...` + } else if self.eatc('*') { + let mut depth = 1; + while depth > 0 { + let (_, ch) = match self.chars.next() { + Some(pair) => pair, + None => return Err(Error::UnterminatedComment(start)), + }; + match ch { + '/' if self.eatc('*') => depth += 1, + '*' if self.eatc('/') => depth -= 1, + _ => {} + } + } + Comment + } else { + Slash + } + } + '=' => Equals, + ',' => Comma, + ':' => Colon, + '.' => Period, + ';' => Semicolon, + '(' => LeftParen, + ')' => RightParen, + '{' => LeftBrace, + '}' => RightBrace, + '<' => LessThan, + '>' => GreaterThan, + '*' => Star, + '@' => At, + '-' => { + if self.eatc('>') { + RArrow + } else { + Minus + } + } + '+' => Plus, + '%' => { + let mut iter = self.chars.clone(); + if let Some((_, ch)) = iter.next() { + if is_keylike_start(ch) { + self.chars = iter.clone(); + while let Some((_, ch)) = iter.next() { + if !is_keylike_continue(ch) { + break; + } + self.chars = iter.clone(); + } + } + } + ExplicitId + } + ch if is_keylike_start(ch) => { + let remaining = self.chars.chars.as_str().len(); + let mut iter = self.chars.clone(); + while let Some((_, ch)) = iter.next() { + if !is_keylike_continue(ch) { + break; + } + self.chars = iter.clone(); + } + let str_end = + str_start + ch.len_utf8() + (remaining - self.chars.chars.as_str().len()); + match &self.input[str_start..str_end] { + "use" => Use, + "type" => Type, + "func" => Func, + "u8" => U8, + "u16" => U16, + "u32" => U32, + "u64" => U64, + "s8" => S8, + "s16" => S16, + "s32" => S32, + "s64" => S64, + "float32" => Float32, + "float64" => Float64, + "char" => Char, + "resource" => Resource, + "own" => Own, + "borrow" => Borrow, + "record" => Record, + "flags" => Flags, + "variant" => Variant, + "enum" => Enum, + "bool" => Bool, + "string" => String_, + "option" => Option_, + "result" => Result_, + "future" => Future, + "stream" => Stream, + "list" => List, + "_" => Underscore, + "as" => As, + "from" => From_, + "static" => Static, + "interface" => Interface, + "tuple" => Tuple, + "world" => World, + "import" => Import, + "export" => Export, + "package" => Package, + "constructor" => Constructor, + "include" => Include, + "with" => With, + _ => Id, + } + } + + ch if ch.is_ascii_digit() => { + let mut iter = self.chars.clone(); + while let Some((_, ch)) = iter.next() { + if !ch.is_ascii_digit() { + break; + } + self.chars = iter.clone(); + } + + Integer + } + + ch => return Err(Error::Unexpected(start, ch)), + }; + let end = match self.chars.clone().next() { + Some((i, _)) => i, + None => self.input.len(), + }; + + let end = self.span_offset + u32::try_from(end).unwrap(); + Ok(Some((Span { start, end }, token))) + } + + pub fn eat(&mut self, expected: Token) -> Result { + let mut other = self.clone(); + match other.next()? { + Some((_span, found)) if expected == found => { + *self = other; + Ok(true) + } + Some(_) => Ok(false), + None => Ok(false), + } + } + + pub fn expect(&mut self, expected: Token) -> Result { + match self.next()? { + Some((span, found)) => { + if expected == found { + Ok(span) + } else { + Err(Error::Wanted { + at: span.start, + expected: expected.describe(), + found: found.describe(), + }) + } + } + None => Err(Error::Wanted { + at: self.span_offset + u32::try_from(self.input.len()).unwrap(), + expected: expected.describe(), + found: "eof", + }), + } + } + + fn eatc(&mut self, ch: char) -> bool { + let mut iter = self.chars.clone(); + match iter.next() { + Some((_, ch2)) if ch == ch2 => { + self.chars = iter; + true + } + _ => false, + } + } +} + +impl<'a> Iterator for CrlfFold<'a> { + type Item = (usize, char); + + fn next(&mut self) -> Option<(usize, char)> { + self.chars.next().map(|(i, c)| { + if c == '\r' { + let mut attempt = self.chars.clone(); + if let Some((_, '\n')) = attempt.next() { + self.chars = attempt; + return (i, '\n'); + } + } + (i, c) + }) + } +} + +fn detect_invalid_input(input: &str) -> Result<()> { + // Disallow specific codepoints. + let mut line = 1; + for ch in input.chars() { + match ch { + '\n' => line += 1, + '\r' | '\t' => {} + + // Bidirectional override codepoints can be used to craft source code that + // appears to have a different meaning than its actual meaning. See + // [CVE-2021-42574] for background and motivation. + // + // [CVE-2021-42574]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-42574 + '\u{202a}' | '\u{202b}' | '\u{202c}' | '\u{202d}' | '\u{202e}' | '\u{2066}' + | '\u{2067}' | '\u{2068}' | '\u{2069}' => { + bail!( + "Input contains bidirectional override codepoint {:?} at line {}", + ch.escape_unicode(), + line + ); + } + + // Disallow several characters which are deprecated or discouraged in Unicode. + // + // U+149 deprecated; see Unicode 13.0.0, sec. 7.1 Latin, Compatibility Digraphs. + // U+673 deprecated; see Unicode 13.0.0, sec. 9.2 Arabic, Additional Vowel Marks. + // U+F77 and U+F79 deprecated; see Unicode 13.0.0, sec. 13.4 Tibetan, Vowels. + // U+17A3 and U+17A4 deprecated, and U+17B4 and U+17B5 discouraged; see + // Unicode 13.0.0, sec. 16.4 Khmer, Characters Whose Use Is Discouraged. + '\u{149}' | '\u{673}' | '\u{f77}' | '\u{f79}' | '\u{17a3}' | '\u{17a4}' + | '\u{17b4}' | '\u{17b5}' => { + bail!( + "Codepoint {:?} at line {} is discouraged by Unicode", + ch.escape_unicode(), + line + ); + } + + // Disallow control codes other than the ones explicitly recognized above, + // so that viewing a wit file on a terminal doesn't have surprising side + // effects or appear to have a different meaning than its actual meaning. + ch if ch.is_control() => { + bail!("Control code '{}' at line {}", ch.escape_unicode(), line); + } + + _ => {} + } + } + + Ok(()) +} + +fn is_keylike_start(ch: char) -> bool { + // Lex any XID start, `_`, or '-'. These aren't all valid identifier chars, + // but we'll diagnose that after we've lexed the full string. + UnicodeXID::is_xid_start(ch) || ch == '_' || ch == '-' +} + +fn is_keylike_continue(ch: char) -> bool { + // Lex any XID continue (which includes `_`) or '-'. + UnicodeXID::is_xid_continue(ch) || ch == '-' +} + +pub fn validate_id(start: u32, id: &str) -> Result<(), Error> { + // IDs must have at least one part. + if id.is_empty() { + return Err(Error::IdPartEmpty(start)); + } + + // Ids consist of parts separated by '-'s. + for part in id.split('-') { + // Parts must be non-empty and contain either all ASCII lowercase or + // all ASCII uppercase. + let upper = match part.chars().next() { + None => return Err(Error::IdPartEmpty(start)), + Some(first) => { + if first.is_ascii_lowercase() { + false + } else if first.is_ascii_uppercase() { + true + } else { + return Err(Error::InvalidCharInId(start, first)); + } + } + }; + + for ch in part.chars() { + if ch.is_ascii_digit() { + // Digits are accepted in both uppercase and lowercase segments. + } else if upper { + if !ch.is_ascii_uppercase() { + return Err(Error::InvalidCharInId(start, ch)); + } + } else if !ch.is_ascii_lowercase() { + return Err(Error::InvalidCharInId(start, ch)); + } + } + } + + Ok(()) +} + +impl Token { + pub fn describe(&self) -> &'static str { + match self { + Whitespace => "whitespace", + Comment => "a comment", + Equals => "'='", + Comma => "','", + Colon => "':'", + Period => "'.'", + Semicolon => "';'", + LeftParen => "'('", + RightParen => "')'", + LeftBrace => "'{'", + RightBrace => "'}'", + LessThan => "'<'", + GreaterThan => "'>'", + Use => "keyword `use`", + Type => "keyword `type`", + Func => "keyword `func`", + U8 => "keyword `u8`", + U16 => "keyword `u16`", + U32 => "keyword `u32`", + U64 => "keyword `u64`", + S8 => "keyword `s8`", + S16 => "keyword `s16`", + S32 => "keyword `s32`", + S64 => "keyword `s64`", + Float32 => "keyword `float32`", + Float64 => "keyword `float64`", + Char => "keyword `char`", + Own => "keyword `own`", + Borrow => "keyword `borrow`", + Resource => "keyword `resource`", + Record => "keyword `record`", + Flags => "keyword `flags`", + Variant => "keyword `variant`", + Enum => "keyword `enum`", + Bool => "keyword `bool`", + String_ => "keyword `string`", + Option_ => "keyword `option`", + Result_ => "keyword `result`", + Future => "keyword `future`", + Stream => "keyword `stream`", + List => "keyword `list`", + Underscore => "keyword `_`", + Id => "an identifier", + ExplicitId => "an '%' identifier", + RArrow => "`->`", + Star => "`*`", + At => "`@`", + Slash => "`/`", + Plus => "`+`", + Minus => "`-`", + As => "keyword `as`", + From_ => "keyword `from`", + Static => "keyword `static`", + Interface => "keyword `interface`", + Tuple => "keyword `tuple`", + Import => "keyword `import`", + Export => "keyword `export`", + World => "keyword `world`", + Package => "keyword `package`", + Constructor => "keyword `constructor`", + Integer => "an integer", + Include => "keyword `include`", + With => "keyword `with`", + } + } +} + +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Unexpected(_, ch) => write!(f, "unexpected character {:?}", ch), + Error::UnterminatedComment(_) => write!(f, "unterminated block comment"), + Error::Wanted { + expected, found, .. + } => write!(f, "expected {}, found {}", expected, found), + Error::InvalidCharInId(_, ch) => write!(f, "invalid character in identifier {:?}", ch), + Error::IdPartEmpty(_) => write!(f, "identifiers must have characters between '-'s"), + Error::InvalidEscape(_, ch) => write!(f, "invalid escape in string {:?}", ch), + } + } +} + +#[test] +fn test_validate_id() { + validate_id(0, "apple").unwrap(); + validate_id(0, "apple-pear").unwrap(); + validate_id(0, "apple-pear-grape").unwrap(); + validate_id(0, "a0").unwrap(); + validate_id(0, "a").unwrap(); + validate_id(0, "a-a").unwrap(); + validate_id(0, "bool").unwrap(); + validate_id(0, "APPLE").unwrap(); + validate_id(0, "APPLE-PEAR").unwrap(); + validate_id(0, "APPLE-PEAR-GRAPE").unwrap(); + validate_id(0, "apple-PEAR-grape").unwrap(); + validate_id(0, "APPLE-pear-GRAPE").unwrap(); + validate_id(0, "ENOENT").unwrap(); + validate_id(0, "is-XML").unwrap(); + + assert!(validate_id(0, "").is_err()); + assert!(validate_id(0, "0").is_err()); + assert!(validate_id(0, "%").is_err()); + assert!(validate_id(0, "$").is_err()); + assert!(validate_id(0, "0a").is_err()); + assert!(validate_id(0, ".").is_err()); + assert!(validate_id(0, "·").is_err()); + assert!(validate_id(0, "a a").is_err()); + assert!(validate_id(0, "_").is_err()); + assert!(validate_id(0, "-").is_err()); + assert!(validate_id(0, "a-").is_err()); + assert!(validate_id(0, "-a").is_err()); + assert!(validate_id(0, "Apple").is_err()); + assert!(validate_id(0, "applE").is_err()); + assert!(validate_id(0, "-apple-pear").is_err()); + assert!(validate_id(0, "apple-pear-").is_err()); + assert!(validate_id(0, "apple_pear").is_err()); + assert!(validate_id(0, "apple.pear").is_err()); + assert!(validate_id(0, "apple pear").is_err()); + assert!(validate_id(0, "apple/pear").is_err()); + assert!(validate_id(0, "apple|pear").is_err()); + assert!(validate_id(0, "apple-Pear").is_err()); + assert!(validate_id(0, "apple-0").is_err()); + assert!(validate_id(0, "()()").is_err()); + assert!(validate_id(0, "").is_err()); + assert!(validate_id(0, "*").is_err()); + assert!(validate_id(0, "apple\u{5f3}pear").is_err()); + assert!(validate_id(0, "apple\u{200c}pear").is_err()); + assert!(validate_id(0, "apple\u{200d}pear").is_err()); + assert!(validate_id(0, "apple--pear").is_err()); + assert!(validate_id(0, "_apple").is_err()); + assert!(validate_id(0, "apple_").is_err()); + assert!(validate_id(0, "_Znwj").is_err()); + assert!(validate_id(0, "__i386").is_err()); + assert!(validate_id(0, "__i386__").is_err()); + assert!(validate_id(0, "Москва").is_err()); + assert!(validate_id(0, "garçon-hühnervögel-Москва-東京").is_err()); + assert!(validate_id(0, "😼").is_err(), "non-identifier"); + assert!(validate_id(0, "\u{212b}").is_err(), "non-ascii"); +} + +#[test] +fn test_tokenizer() { + fn collect(s: &str) -> Result> { + let mut t = Tokenizer::new(s, 0, Some(true))?; + let mut tokens = Vec::new(); + while let Some(token) = t.next()? { + tokens.push(token.1); + } + Ok(tokens) + } + + assert_eq!(collect("").unwrap(), vec![]); + assert_eq!(collect("_").unwrap(), vec![Token::Underscore]); + assert_eq!(collect("apple").unwrap(), vec![Token::Id]); + assert_eq!(collect("apple-pear").unwrap(), vec![Token::Id]); + assert_eq!(collect("apple--pear").unwrap(), vec![Token::Id]); + assert_eq!(collect("apple-Pear").unwrap(), vec![Token::Id]); + assert_eq!(collect("apple-pear-grape").unwrap(), vec![Token::Id]); + assert_eq!(collect("apple pear").unwrap(), vec![Token::Id, Token::Id]); + assert_eq!(collect("_a_p_p_l_e_").unwrap(), vec![Token::Id]); + assert_eq!(collect("garçon").unwrap(), vec![Token::Id]); + assert_eq!(collect("hühnervögel").unwrap(), vec![Token::Id]); + assert_eq!(collect("москва").unwrap(), vec![Token::Id]); + assert_eq!(collect("東京").unwrap(), vec![Token::Id]); + assert_eq!( + collect("garçon-hühnervögel-москва-東京").unwrap(), + vec![Token::Id] + ); + assert_eq!(collect("a0").unwrap(), vec![Token::Id]); + assert_eq!(collect("a").unwrap(), vec![Token::Id]); + assert_eq!(collect("%a").unwrap(), vec![Token::ExplicitId]); + assert_eq!(collect("%a-a").unwrap(), vec![Token::ExplicitId]); + assert_eq!(collect("%bool").unwrap(), vec![Token::ExplicitId]); + assert_eq!(collect("%").unwrap(), vec![Token::ExplicitId]); + assert_eq!(collect("APPLE").unwrap(), vec![Token::Id]); + assert_eq!(collect("APPLE-PEAR").unwrap(), vec![Token::Id]); + assert_eq!(collect("APPLE-PEAR-GRAPE").unwrap(), vec![Token::Id]); + assert_eq!(collect("apple-PEAR-grape").unwrap(), vec![Token::Id]); + assert_eq!(collect("APPLE-pear-GRAPE").unwrap(), vec![Token::Id]); + assert_eq!(collect("ENOENT").unwrap(), vec![Token::Id]); + assert_eq!(collect("is-XML").unwrap(), vec![Token::Id]); + + assert_eq!(collect("func").unwrap(), vec![Token::Func]); + assert_eq!( + collect("a: func()").unwrap(), + vec![ + Token::Id, + Token::Colon, + Token::Func, + Token::LeftParen, + Token::RightParen + ] + ); + + assert_eq!(collect("resource").unwrap(), vec![Token::Resource]); + + assert_eq!(collect("own").unwrap(), vec![Token::Own]); + assert_eq!( + collect("own").unwrap(), + vec![Token::Own, Token::LessThan, Token::Id, Token::GreaterThan] + ); + + assert_eq!(collect("borrow").unwrap(), vec![Token::Borrow]); + assert_eq!( + collect("borrow").unwrap(), + vec![ + Token::Borrow, + Token::LessThan, + Token::Id, + Token::GreaterThan + ] + ); + + assert!(collect("\u{149}").is_err(), "strongly discouraged"); + assert!(collect("\u{673}").is_err(), "strongly discouraged"); + assert!(collect("\u{17a3}").is_err(), "strongly discouraged"); + assert!(collect("\u{17a4}").is_err(), "strongly discouraged"); + assert!(collect("\u{202a}").is_err(), "bidirectional override"); + assert!(collect("\u{2068}").is_err(), "bidirectional override"); + assert!(collect("\u{0}").is_err(), "control code"); + assert!(collect("\u{b}").is_err(), "control code"); + assert!(collect("\u{c}").is_err(), "control code"); + assert!(collect("\u{85}").is_err(), "control code"); +} diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs new file mode 100644 index 0000000000..b1c9d08d0b --- /dev/null +++ b/crates/wit-parser/src/ast/resolve.rs @@ -0,0 +1,1425 @@ +use super::{Error, ParamList, ResultList, WorldOrInterface}; +use crate::ast::toposort::toposort; +use crate::*; +use anyhow::{bail, Result}; +use indexmap::IndexMap; +use std::collections::{HashMap, HashSet}; +use std::mem; + +#[derive(Default)] +pub struct Resolver<'a> { + /// Current package name learned through the ASTs pushed onto this resolver. + package_name: Option, + + /// Package docs. + package_docs: Docs, + + /// All WIT files which are going to be resolved together. + asts: Vec>, + + // Arenas that get plumbed to the final `UnresolvedPackage` + types: Arena, + interfaces: Arena, + worlds: Arena, + + // Interning structure for types which-need-not-be-named such as + // `list` and such. + anon_types: HashMap, + + /// The index within `self.ast_items` that lookups should go through. This + /// is updated as the ASTs are walked. + cur_ast_index: usize, + + /// A map per `ast::Ast` which keeps track of the file's top level names in + /// scope. This maps each name onto either a world or an interface, handling + /// things like `use` at the top level. + ast_items: Vec>, + + /// A map for the entire package being created of all names defined within, + /// along with the ID they're mapping to. + package_items: IndexMap<&'a str, AstItem>, + + /// A per-interface map of name to item-in-the-interface. This is the same + /// length as `self.types` and is pushed to whenever `self.types` is pushed + /// to. + interface_types: Vec>, + + /// Metadata about foreign dependencies which are not defined in this + /// package. This map is keyed by the name of the package being imported + /// from. The next level of key is the name of the interface being imported + /// from, and the final value is the assigned ID of the interface. + foreign_deps: IndexMap>, + + /// All interfaces that are present within `self.foreign_deps`. + foreign_interfaces: HashSet, + + foreign_worlds: HashSet, + + /// The current type lookup scope which will eventually make its way into + /// `self.interface_types`. + type_lookup: IndexMap<&'a str, (TypeOrItem, Span)>, + + /// An assigned span for where all types inserted into `self.types` as + /// imported from foreign interfaces. These types all show up first in the + /// `self.types` arena and this span is used to generate an error message + /// pointing to it if the item isn't actually defined. + unknown_type_spans: Vec, + + /// Spans for each world in `self.world` to assign for each import/export + /// for later error reporting. + world_item_spans: Vec<(Vec, Vec)>, + + /// Spans for each world in `self.world` + world_spans: Vec, + + /// The span of each interface's definition which is used for error + /// reporting during the final `Resolve` phase. + interface_spans: Vec, + + /// Spans per entry in `self.foreign_deps` for where the dependency was + /// introduced to print an error message if necessary. + foreign_dep_spans: Vec, + + include_world_spans: Vec, + + /// A list of `TypeDefKind::Unknown` types which are required to be + /// resources when this package is resolved against its dependencies. + required_resource_types: Vec<(TypeId, Span)>, +} + +#[derive(PartialEq, Eq, Hash)] +enum Key { + Variant(Vec<(String, Option)>), + BorrowHandle(TypeId), + Record(Vec<(String, Type)>), + Flags(Vec), + Tuple(Vec), + Enum(Vec), + List(Type), + Option(Type), + Result(Option, Option), + Future(Option), + Stream(Option, Option), +} + +enum TypeItem<'a, 'b> { + Use(&'b ast::Use<'a>), + Def(&'b ast::TypeDef<'a>), +} + +enum TypeOrItem { + Type(TypeId), + Item(&'static str), +} + +impl<'a> Resolver<'a> { + pub(crate) fn push(&mut self, ast: ast::Ast<'a>) -> Result<()> { + // As each WIT file is pushed into this resolver keep track of the + // current package name assigned. Only one file needs to mention it, but + // if multiple mention it then they must all match. + if let Some(cur) = &ast.package_id { + let cur_name = cur.package_name(); + if let Some(prev) = &self.package_name { + if cur_name != *prev { + bail!(Error { + span: cur.span, + msg: format!( + "package identifier `{cur_name}` does not match \ + previous package name of `{prev}`" + ), + }) + } + } + self.package_name = Some(cur_name); + + // At most one 'package' item can have doc comments. + let docs = self.docs(&cur.docs); + if docs.contents.is_some() { + if self.package_docs.contents.is_some() { + bail!(Error { + span: cur.docs.span, + msg: "found doc comments on multiple 'package' items".into(), + }) + } + self.package_docs = docs; + } + } + self.asts.push(ast); + Ok(()) + } + + pub(crate) fn resolve(&mut self) -> Result { + // At least one of the WIT files must have a `package` annotation. + let name = match &self.package_name { + Some(name) => name.clone(), + None => bail!("no `package` header was found in any WIT file for this package"), + }; + + // First populate information about foreign dependencies and the general + // structure of the package. This should resolve the "base" of many + // `use` statements and additionally generate a topological ordering of + // all interfaces in the package to visit. + let asts = mem::take(&mut self.asts); + self.populate_foreign_deps(&asts); + let (iface_order, world_order) = self.populate_ast_items(&asts)?; + self.populate_foreign_types(&asts)?; + + // Use the topological ordering of all interfaces to resolve all + // interfaces in-order. Note that a reverse-mapping from ID to AST is + // generated here to assist with this. + let mut iface_id_to_ast = IndexMap::new(); + let mut world_id_to_ast = IndexMap::new(); + for (i, ast) in asts.iter().enumerate() { + for item in ast.items.iter() { + match item { + ast::AstItem::Interface(iface) => { + let id = match self.ast_items[i][iface.name.name] { + AstItem::Interface(id) => id, + AstItem::World(_) => unreachable!(), + }; + iface_id_to_ast.insert(id, (iface, i)); + } + ast::AstItem::World(world) => { + let id = match self.ast_items[i][world.name.name] { + AstItem::World(id) => id, + AstItem::Interface(_) => unreachable!(), + }; + world_id_to_ast.insert(id, (world, i)); + } + ast::AstItem::Use(_) => {} + } + } + } + + for id in iface_order { + let (interface, i) = &iface_id_to_ast[&id]; + self.cur_ast_index = *i; + self.resolve_interface(id, &interface.items, &interface.docs)?; + } + + for id in world_order { + let (world, i) = &world_id_to_ast[&id]; + self.cur_ast_index = *i; + self.resolve_world(id, world)?; + } + + Ok(UnresolvedPackage { + name, + docs: mem::take(&mut self.package_docs), + worlds: mem::take(&mut self.worlds), + types: mem::take(&mut self.types), + interfaces: mem::take(&mut self.interfaces), + foreign_deps: self + .foreign_deps + .iter() + .map(|(name, deps)| { + ( + name.clone(), + deps.iter() + .map(|(name, id)| (name.to_string(), *id)) + .collect(), + ) + }) + .collect(), + unknown_type_spans: mem::take(&mut self.unknown_type_spans), + world_item_spans: mem::take(&mut self.world_item_spans), + interface_spans: mem::take(&mut self.interface_spans), + world_spans: mem::take(&mut self.world_spans), + foreign_dep_spans: mem::take(&mut self.foreign_dep_spans), + source_map: SourceMap::default(), + include_world_spans: mem::take(&mut self.include_world_spans), + required_resource_types: mem::take(&mut self.required_resource_types), + }) + } + + /// Registers all foreign dependencies made within the ASTs provided. + /// + /// This will populate the `self.foreign_{deps,interfaces,worlds}` maps with all + /// `UsePath::Package` entries. + fn populate_foreign_deps(&mut self, asts: &[ast::Ast<'a>]) { + let mut foreign_deps = mem::take(&mut self.foreign_deps); + let mut foreign_interfaces = mem::take(&mut self.foreign_interfaces); + let mut foreign_worlds = mem::take(&mut self.foreign_worlds); + for ast in asts { + ast.for_each_path(|_, path, _names, world_or_iface| { + let (id, name) = match path { + ast::UsePath::Package { id, name } => (id, name), + _ => return Ok(()), + }; + + let deps = foreign_deps.entry(id.package_name()).or_insert_with(|| { + self.foreign_dep_spans.push(id.span); + IndexMap::new() + }); + let id = *deps.entry(name.name).or_insert_with(|| { + match world_or_iface { + WorldOrInterface::World => { + log::trace!( + "creating a world for foreign dep: {}/{}", + id.package_name(), + name.name + ); + AstItem::World(self.alloc_world(name.span, true)) + } + WorldOrInterface::Interface | WorldOrInterface::Unknown => { + // Currently top-level `use` always assumes an interface, so the + // `Unknown` case is the same as `Interface`. + log::trace!( + "creating an interface for foreign dep: {}/{}", + id.package_name(), + name.name + ); + AstItem::Interface(self.alloc_interface(name.span)) + } + } + }); + + let _ = match id { + AstItem::Interface(id) => foreign_interfaces.insert(id), + AstItem::World(id) => foreign_worlds.insert(id), + }; + + Ok(()) + }) + .unwrap(); + } + self.foreign_deps = foreign_deps; + self.foreign_interfaces = foreign_interfaces; + self.foreign_worlds = foreign_worlds; + } + + fn alloc_interface(&mut self, span: Span) -> InterfaceId { + self.interface_types.push(IndexMap::new()); + self.interface_spans.push(span); + self.interfaces.alloc(Interface { + name: None, + types: IndexMap::new(), + docs: Docs::default(), + functions: IndexMap::new(), + package: None, + }) + } + + fn alloc_world(&mut self, span: Span, dummy_span: bool) -> WorldId { + self.world_spans.push(span); + if dummy_span { + self.world_item_spans.push((Vec::new(), Vec::new())); + } + self.worlds.alloc(World { + name: String::new(), + docs: Docs::default(), + exports: IndexMap::new(), + imports: IndexMap::new(), + package: None, + includes: Default::default(), + include_names: Default::default(), + }) + } + + /// This method will create a `World` and an `Interface` for all items + /// present in the specified set of ASTs. Additionally maps for each AST are + /// generated for resolving use-paths later on. + fn populate_ast_items( + &mut self, + asts: &[ast::Ast<'a>], + ) -> Result<(Vec, Vec)> { + let mut package_items = IndexMap::new(); + + // Validate that all worlds and interfaces have unique names within this + // package across all ASTs which make up the package. + let mut names = HashMap::new(); + let mut ast_namespaces = Vec::new(); + let mut order = IndexMap::new(); + for ast in asts { + let mut ast_ns = IndexMap::new(); + for item in ast.items.iter() { + match item { + ast::AstItem::Interface(i) => { + if package_items.insert(i.name.name, i.name.span).is_some() { + bail!(Error { + span: i.name.span, + msg: format!("duplicate item named `{}`", i.name.name), + }) + } + let prev = ast_ns.insert(i.name.name, ()); + assert!(prev.is_none()); + let prev = order.insert(i.name.name, Vec::new()); + assert!(prev.is_none()); + let prev = names.insert(i.name.name, item); + assert!(prev.is_none()); + } + ast::AstItem::World(w) => { + if package_items.insert(w.name.name, w.name.span).is_some() { + bail!(Error { + span: w.name.span, + msg: format!("duplicate item named `{}`", w.name.name), + }) + } + let prev = ast_ns.insert(w.name.name, ()); + assert!(prev.is_none()); + let prev = order.insert(w.name.name, Vec::new()); + assert!(prev.is_none()); + let prev = names.insert(w.name.name, item); + assert!(prev.is_none()); + } + // These are processed down below. + ast::AstItem::Use(_) => {} + } + } + ast_namespaces.push(ast_ns); + } + + // Next record dependencies between interfaces as induced via `use` + // paths. This step is used to perform a topological sort of all + // interfaces to ensure there are no cycles and to generate an ordering + // which we can resolve in. + enum ItemSource<'a> { + Foreign, + Local(ast::Id<'a>), + } + + for ast in asts { + // Record, in the context of this file, what all names are defined + // at the top level and whether they point to other items in this + // package or foreign items. Foreign deps are ignored for + // topological ordering. + let mut ast_ns = IndexMap::new(); + for item in ast.items.iter() { + let (name, src) = match item { + ast::AstItem::Use(u) => { + let name = u.as_.as_ref().unwrap_or(u.item.name()); + let src = match &u.item { + ast::UsePath::Id(id) => ItemSource::Local(id.clone()), + ast::UsePath::Package { .. } => ItemSource::Foreign, + }; + (name, src) + } + ast::AstItem::Interface(i) => (&i.name, ItemSource::Local(i.name.clone())), + ast::AstItem::World(w) => (&w.name, ItemSource::Local(w.name.clone())), + }; + if ast_ns.insert(name.name, (name.span, src)).is_some() { + bail!(Error { + span: name.span, + msg: format!("duplicate name `{}` in this file", name.name), + }); + } + } + + // With this file's namespace information look at all `use` paths + // and record dependencies between interfaces. + ast.for_each_path(|iface, path, _names, _| { + // If this import isn't contained within an interface then it's + // in a world and it doesn't need to participate in our + // topo-sort. + let iface = match iface { + Some(name) => name, + None => return Ok(()), + }; + let used_name = match path { + ast::UsePath::Id(id) => id, + ast::UsePath::Package { .. } => return Ok(()), + }; + match ast_ns.get(used_name.name) { + Some((_, ItemSource::Foreign)) => return Ok(()), + Some((_, ItemSource::Local(id))) => { + order[iface.name].push(id.clone()); + } + None => match package_items.get(used_name.name) { + Some(_) => { + order[iface.name].push(used_name.clone()); + } + None => { + bail!(Error { + span: used_name.span, + msg: format!( + "interface or world `{name}` not found in package", + name = used_name.name + ), + }) + } + }, + } + Ok(()) + })?; + } + + let order = toposort("interface or world", &order)?; + log::debug!("toposort for interfaces and worlds in order: {:?}", order); + + // Allocate interfaces in-order now that the ordering is defined. This + // is then used to build up internal maps for each AST which are stored + // in `self.ast_items`. + let mut ids = IndexMap::new(); + let mut iface_id_order = Vec::new(); + let mut world_id_order = Vec::new(); + for name in order { + match names.get(name).unwrap() { + ast::AstItem::Interface(_) => { + let id = self.alloc_interface(package_items[name]); + self.interfaces[id].name = Some(name.to_string()); + let prev = ids.insert(name, AstItem::Interface(id)); + assert!(prev.is_none()); + iface_id_order.push(id); + } + ast::AstItem::World(_) => { + // No dummy span needs to be created because they will be created at `resolve_world` + let id = self.alloc_world(package_items[name], false); + self.worlds[id].name = name.to_string(); + let prev = ids.insert(name, AstItem::World(id)); + assert!(prev.is_none()); + world_id_order.push(id); + } + ast::AstItem::Use(_) => unreachable!(), + }; + } + for ast in asts { + let mut items = IndexMap::new(); + for item in ast.items.iter() { + let (name, ast_item) = match item { + ast::AstItem::Use(u) => { + let name = u.as_.as_ref().unwrap_or(u.item.name()); + let item = match &u.item { + ast::UsePath::Id(name) => *ids.get(name.name).ok_or_else(|| Error { + span: name.span, + msg: format!( + "interface or world `{name}` does not exist", + name = name.name + ), + })?, + ast::UsePath::Package { id, name } => { + self.foreign_deps[&id.package_name()][name.name] + } + }; + (name.name, item) + } + ast::AstItem::Interface(i) => { + let iface_item = ids[i.name.name]; + assert!(matches!(iface_item, AstItem::Interface(_))); + (i.name.name, iface_item) + } + ast::AstItem::World(w) => { + let world_item = ids[w.name.name]; + assert!(matches!(world_item, AstItem::World(_))); + (w.name.name, world_item) + } + }; + let prev = items.insert(name, ast_item); + assert!(prev.is_none()); + + // Items defined via `use` don't go into the package namespace, + // only the file namespace. + if !matches!(item, ast::AstItem::Use(_)) { + let prev = self.package_items.insert(name, ast_item); + assert!(prev.is_none()); + } + } + self.ast_items.push(items); + } + Ok((iface_id_order, world_id_order)) + } + + /// Generate a `Type::Unknown` entry for all types imported from foreign + /// packages. + /// + /// This is done after all interfaces are generated so `self.resolve_path` + /// can be used to determine if what's being imported from is a foreign + /// interface or not. + fn populate_foreign_types(&mut self, asts: &[ast::Ast<'a>]) -> Result<()> { + for (i, ast) in asts.iter().enumerate() { + self.cur_ast_index = i; + ast.for_each_path(|_, path, names, _| { + let names = match names { + Some(names) => names, + None => return Ok(()), + }; + let (item, name, span) = self.resolve_ast_item_path(path)?; + let iface = self.extract_iface_from_item(&item, &name, span)?; + if !self.foreign_interfaces.contains(&iface) { + return Ok(()); + } + + let lookup = &mut self.interface_types[iface.index()]; + for name in names { + // If this name has already been defined then use that prior + // definition, otherwise create a new type with an unknown + // representation and insert it into the various maps. + if lookup.contains_key(name.name.name) { + continue; + } + let id = self.types.alloc(TypeDef { + docs: Docs::default(), + kind: TypeDefKind::Unknown, + name: Some(name.name.name.to_string()), + owner: TypeOwner::Interface(iface), + }); + self.unknown_type_spans.push(name.name.span); + lookup.insert(name.name.name, (TypeOrItem::Type(id), name.name.span)); + self.interfaces[iface] + .types + .insert(name.name.name.to_string(), id); + } + + Ok(()) + })?; + } + Ok(()) + } + + fn resolve_world(&mut self, world_id: WorldId, world: &ast::World<'a>) -> Result { + let docs = self.docs(&world.docs); + self.worlds[world_id].docs = docs; + + self.resolve_types( + TypeOwner::World(world_id), + world.items.iter().filter_map(|i| match i { + ast::WorldItem::Use(u) => Some(TypeItem::Use(u)), + ast::WorldItem::Type(t) => Some(TypeItem::Def(t)), + ast::WorldItem::Import(_) | ast::WorldItem::Export(_) => None, + // should be handled in `wit-parser::resolve` + ast::WorldItem::Include(_) => None, + }), + )?; + + // resolve include items + let items = world.items.iter().filter_map(|i| match i { + ast::WorldItem::Include(i) => Some(i), + _ => None, + }); + for include in items { + self.resolve_include(TypeOwner::World(world_id), include)?; + } + + let mut export_spans = Vec::new(); + let mut import_spans = Vec::new(); + let mut used_names = HashMap::new(); + for (name, (item, span)) in self.type_lookup.iter() { + match *item { + TypeOrItem::Type(id) => { + let prev = used_names.insert(*name, "import"); + if let Some(prev) = prev { + return Err(Error { + span: *span, + msg: format!( + "import `{name}` conflicts with prior {prev} of same name", + ), + } + .into()); + } + self.worlds[world_id] + .imports + .insert(WorldKey::Name(name.to_string()), WorldItem::Type(id)); + import_spans.push(*span); + } + TypeOrItem::Item(_) => unreachable!(), + } + } + + let mut imported_interfaces = HashSet::new(); + let mut exported_interfaces = HashSet::new(); + for item in world.items.iter() { + let (docs, kind, desc, spans, interfaces) = match item { + ast::WorldItem::Import(import) => ( + &import.docs, + &import.kind, + "import", + &mut import_spans, + &mut imported_interfaces, + ), + ast::WorldItem::Export(export) => ( + &export.docs, + &export.kind, + "export", + &mut export_spans, + &mut exported_interfaces, + ), + + ast::WorldItem::Type(ast::TypeDef { + name, + ty: ast::Type::Resource(r), + .. + }) => { + for func in r.funcs.iter() { + import_spans.push(func.named_func().name.span); + let func = self.resolve_resource_func(func, name)?; + let prev = self.worlds[world_id] + .imports + .insert(WorldKey::Name(func.name.clone()), WorldItem::Function(func)); + // Resource names themselves are unique, and methods are + // uniquely named, so this should be possible to assert + // at this point and never trip. + assert!(prev.is_none()); + } + continue; + } + + // handled in `resolve_types` + ast::WorldItem::Use(_) | ast::WorldItem::Type(_) | ast::WorldItem::Include(_) => { + continue + } + }; + let key = match kind { + ast::ExternKind::Interface(name, _) | ast::ExternKind::Func(name, _) => { + let prev = used_names.insert(name.name, desc); + if let Some(prev) = prev { + return Err(Error { + span: kind.span(), + msg: format!( + "{desc} `{name}` conflicts with prior {prev} of same name", + name = name.name + ), + } + .into()); + } + WorldKey::Name(name.name.to_string()) + } + ast::ExternKind::Path(path) => { + let (item, name, span) = self.resolve_ast_item_path(path)?; + let id = self.extract_iface_from_item(&item, &name, span)?; + WorldKey::Interface(id) + } + }; + let world_item = self.resolve_world_item(docs, kind)?; + if let WorldItem::Interface(id) = world_item { + if !interfaces.insert(id) { + bail!(Error { + span: kind.span(), + msg: format!("interface cannot be {desc}ed more than once"), + }) + } + } + let dst = if desc == "import" { + &mut self.worlds[world_id].imports + } else { + &mut self.worlds[world_id].exports + }; + let prev = dst.insert(key, world_item); + assert!(prev.is_none()); + spans.push(kind.span()); + } + self.world_item_spans.push((import_spans, export_spans)); + self.type_lookup.clear(); + + Ok(world_id) + } + + fn resolve_world_item( + &mut self, + docs: &ast::Docs<'a>, + kind: &ast::ExternKind<'a>, + ) -> Result { + match kind { + ast::ExternKind::Interface(name, items) => { + let prev = mem::take(&mut self.type_lookup); + let id = self.alloc_interface(name.span); + self.resolve_interface(id, items, docs)?; + self.type_lookup = prev; + Ok(WorldItem::Interface(id)) + } + ast::ExternKind::Path(path) => { + let (item, name, span) = self.resolve_ast_item_path(path)?; + let id = self.extract_iface_from_item(&item, &name, span)?; + Ok(WorldItem::Interface(id)) + } + ast::ExternKind::Func(name, func) => { + let func = + self.resolve_function(docs, name.name, func, FunctionKind::Freestanding)?; + Ok(WorldItem::Function(func)) + } + } + } + + fn resolve_interface( + &mut self, + interface_id: InterfaceId, + fields: &[ast::InterfaceItem<'a>], + docs: &ast::Docs<'a>, + ) -> Result<()> { + let docs = self.docs(docs); + self.interfaces[interface_id].docs = docs; + + self.resolve_types( + TypeOwner::Interface(interface_id), + fields.iter().filter_map(|i| match i { + ast::InterfaceItem::Use(u) => Some(TypeItem::Use(u)), + ast::InterfaceItem::TypeDef(t) => Some(TypeItem::Def(t)), + ast::InterfaceItem::Func(_) => None, + }), + )?; + + for (name, (ty, _)) in self.type_lookup.iter() { + match *ty { + TypeOrItem::Type(id) => { + self.interfaces[interface_id] + .types + .insert(name.to_string(), id); + } + TypeOrItem::Item(_) => unreachable!(), + } + } + + // Finally process all function definitions now that all types are + // defined. + let mut funcs = Vec::new(); + for field in fields { + match field { + ast::InterfaceItem::Func(f) => { + self.define_interface_name(&f.name, TypeOrItem::Item("function"))?; + funcs.push(self.resolve_function( + &f.docs, + &f.name.name, + &f.func, + FunctionKind::Freestanding, + )?); + } + ast::InterfaceItem::Use(_) => {} + ast::InterfaceItem::TypeDef(ast::TypeDef { + name, + ty: ast::Type::Resource(r), + .. + }) => { + for func in r.funcs.iter() { + funcs.push(self.resolve_resource_func(func, name)?); + } + } + ast::InterfaceItem::TypeDef(_) => {} + } + } + for func in funcs { + let prev = self.interfaces[interface_id] + .functions + .insert(func.name.clone(), func); + assert!(prev.is_none()); + } + + let lookup = mem::take(&mut self.type_lookup); + self.interface_types[interface_id.index()] = lookup; + + Ok(()) + } + + fn resolve_types<'b>( + &mut self, + owner: TypeOwner, + fields: impl Iterator> + Clone, + ) -> Result<()> + where + 'a: 'b, + { + assert!(self.type_lookup.is_empty()); + + // First, populate our namespace with `use` statements + for field in fields.clone() { + match field { + TypeItem::Use(u) => { + self.resolve_use(owner, u)?; + } + TypeItem::Def(_) => {} + } + } + + // Next determine dependencies between types, perform a topological + // sort, and then define all types. This will define types in a + // topological fashion, forbid cycles, and weed out references to + // undefined types all in one go. + let mut type_deps = IndexMap::new(); + let mut type_defs = IndexMap::new(); + for field in fields { + match field { + TypeItem::Def(t) => { + let prev = type_defs.insert(t.name.name, Some(t)); + if prev.is_some() { + return Err(Error { + span: t.name.span, + msg: format!("name `{}` is defined more than once", t.name.name), + } + .into()); + } + let mut deps = Vec::new(); + collect_deps(&t.ty, &mut deps); + type_deps.insert(t.name.name, deps); + } + TypeItem::Use(u) => { + for name in u.names.iter() { + let name = name.as_.as_ref().unwrap_or(&name.name); + type_deps.insert(name.name, Vec::new()); + type_defs.insert(name.name, None); + } + } + } + } + let order = toposort("type", &type_deps)?; + for ty in order { + let def = match type_defs.remove(&ty).unwrap() { + Some(def) => def, + None => continue, + }; + let docs = self.docs(&def.docs); + let kind = self.resolve_type_def(&def.ty)?; + let id = self.types.alloc(TypeDef { + docs, + kind, + name: Some(def.name.name.to_string()), + owner, + }); + self.define_interface_name(&def.name, TypeOrItem::Type(id))?; + } + Ok(()) + } + + fn resolve_use(&mut self, owner: TypeOwner, u: &ast::Use<'a>) -> Result<()> { + let (item, name, span) = self.resolve_ast_item_path(&u.from)?; + let use_from = self.extract_iface_from_item(&item, &name, span)?; + + for name in u.names.iter() { + let lookup = &self.interface_types[use_from.index()]; + let id = match lookup.get(name.name.name) { + Some((TypeOrItem::Type(id), _)) => *id, + Some((TypeOrItem::Item(s), _)) => { + bail!(Error { + span: name.name.span, + msg: format!("cannot import {s} `{}`", name.name.name), + }) + } + None => bail!(Error { + span: name.name.span, + msg: format!("name `{}` is not defined", name.name.name), + }), + }; + let name = name.as_.as_ref().unwrap_or(&name.name); + let id = self.types.alloc(TypeDef { + docs: Docs::default(), + kind: TypeDefKind::Type(Type::Id(id)), + name: Some(name.name.to_string()), + owner, + }); + self.define_interface_name(name, TypeOrItem::Type(id))?; + } + Ok(()) + } + + /// For each name in the `include`, resolve the path of the include, add it to the self.includes + fn resolve_include(&mut self, owner: TypeOwner, i: &ast::Include<'a>) -> Result<()> { + let (item, name, span) = self.resolve_ast_item_path(&i.from)?; + let include_from = self.extract_world_from_item(&item, &name, span)?; + self.include_world_spans.push(span); + let world_id = match owner { + TypeOwner::World(id) => id, + _ => unreachable!(), + }; + self.worlds[world_id].includes.push(include_from); + self.worlds[world_id].include_names.push( + i.names + .iter() + .map(|n| IncludeName { + name: n.name.name.to_string(), + as_: n.as_.name.to_string(), + }) + .collect(), + ); + Ok(()) + } + + fn resolve_resource_func( + &mut self, + func: &ast::ResourceFunc<'_>, + resource: &ast::Id<'_>, + ) -> Result { + let resource_id = match self.type_lookup.get(resource.name) { + Some((TypeOrItem::Type(id), _)) => *id, + _ => panic!("type lookup for resource failed"), + }; + let (name, kind); + match func { + ast::ResourceFunc::Method(f) => { + name = format!("[method]{}.{}", resource.name, f.name.name); + kind = FunctionKind::Method(resource_id); + } + ast::ResourceFunc::Static(f) => { + name = format!("[static]{}.{}", resource.name, f.name.name); + kind = FunctionKind::Static(resource_id); + } + ast::ResourceFunc::Constructor(_) => { + name = format!("[constructor]{}", resource.name); + kind = FunctionKind::Constructor(resource_id); + } + } + let named_func = func.named_func(); + self.resolve_function(&named_func.docs, &name, &named_func.func, kind) + } + + fn resolve_function( + &mut self, + docs: &ast::Docs<'_>, + name: &str, + func: &ast::Func, + kind: FunctionKind, + ) -> Result { + let docs = self.docs(docs); + let params = self.resolve_params(&func.params, &kind)?; + let results = self.resolve_results(&func.results, &kind)?; + Ok(Function { + docs, + name: name.to_string(), + kind, + params, + results, + }) + } + + fn resolve_ast_item_path(&self, path: &ast::UsePath<'a>) -> Result<(AstItem, String, Span)> { + match path { + ast::UsePath::Id(id) => { + let item = self.ast_items[self.cur_ast_index] + .get(id.name) + .or_else(|| self.package_items.get(id.name)); + match item { + Some(item) => Ok((*item, id.name.into(), id.span)), + None => { + bail!(Error { + span: id.span, + msg: format!("interface or world `{}` does not exist", id.name), + }) + } + } + } + ast::UsePath::Package { id, name } => Ok(( + self.foreign_deps[&id.package_name()][name.name], + name.name.into(), + name.span, + )), + } + } + + fn extract_iface_from_item( + &self, + item: &AstItem, + name: &str, + span: Span, + ) -> Result { + match item { + AstItem::Interface(id) => Ok(*id), + AstItem::World(_) => { + bail!(Error { + span: span, + msg: format!("name `{}` is defined as a world, not an interface", name), + }) + } + } + } + + fn extract_world_from_item(&self, item: &AstItem, name: &str, span: Span) -> Result { + match item { + AstItem::World(id) => Ok(*id), + AstItem::Interface(_) => { + bail!(Error { + span: span, + msg: format!("name `{}` is defined as an interface, not a world", name), + }) + } + } + } + + fn define_interface_name(&mut self, name: &ast::Id<'a>, item: TypeOrItem) -> Result<()> { + let prev = self.type_lookup.insert(name.name, (item, name.span)); + if prev.is_some() { + Err(Error { + span: name.span, + msg: format!("name `{}` is defined more than once", name.name), + } + .into()) + } else { + Ok(()) + } + } + + fn resolve_type_def(&mut self, ty: &ast::Type<'_>) -> Result { + Ok(match ty { + ast::Type::Bool => TypeDefKind::Type(Type::Bool), + ast::Type::U8 => TypeDefKind::Type(Type::U8), + ast::Type::U16 => TypeDefKind::Type(Type::U16), + ast::Type::U32 => TypeDefKind::Type(Type::U32), + ast::Type::U64 => TypeDefKind::Type(Type::U64), + ast::Type::S8 => TypeDefKind::Type(Type::S8), + ast::Type::S16 => TypeDefKind::Type(Type::S16), + ast::Type::S32 => TypeDefKind::Type(Type::S32), + ast::Type::S64 => TypeDefKind::Type(Type::S64), + ast::Type::Float32 => TypeDefKind::Type(Type::Float32), + ast::Type::Float64 => TypeDefKind::Type(Type::Float64), + ast::Type::Char => TypeDefKind::Type(Type::Char), + ast::Type::String => TypeDefKind::Type(Type::String), + ast::Type::Name(name) => { + let id = self.resolve_type_name(name)?; + TypeDefKind::Type(Type::Id(id)) + } + ast::Type::List(list) => { + let ty = self.resolve_type(list)?; + TypeDefKind::List(ty) + } + ast::Type::Handle(handle) => TypeDefKind::Handle(match handle { + ast::Handle::Own { resource } => Handle::Own(self.validate_resource(resource)?), + ast::Handle::Borrow { resource } => { + Handle::Borrow(self.validate_resource(resource)?) + } + }), + ast::Type::Resource(resource) => { + // Validate here that the resource doesn't have any duplicate-ly + // named methods and that there's at most one constructor. + let mut ctors = 0; + let mut names = HashSet::new(); + for func in resource.funcs.iter() { + match func { + ast::ResourceFunc::Method(f) | ast::ResourceFunc::Static(f) => { + if !names.insert(&f.name.name) { + bail!(Error { + span: f.name.span, + msg: format!("duplicate function name `{}`", f.name.name), + }) + } + } + ast::ResourceFunc::Constructor(f) => { + ctors += 1; + if ctors > 1 { + bail!(Error { + span: f.name.span, + msg: format!("duplicate constructors"), + }) + } + } + } + } + + TypeDefKind::Resource + } + ast::Type::Record(record) => { + let fields = record + .fields + .iter() + .map(|field| { + Ok(Field { + docs: self.docs(&field.docs), + name: field.name.name.to_string(), + ty: self.resolve_type(&field.ty)?, + }) + }) + .collect::>>()?; + TypeDefKind::Record(Record { fields }) + } + ast::Type::Flags(flags) => { + let flags = flags + .flags + .iter() + .map(|flag| Flag { + docs: self.docs(&flag.docs), + name: flag.name.name.to_string(), + }) + .collect::>(); + TypeDefKind::Flags(Flags { flags }) + } + ast::Type::Tuple(types) => { + let types = types + .iter() + .map(|ty| self.resolve_type(ty)) + .collect::>>()?; + TypeDefKind::Tuple(Tuple { types }) + } + ast::Type::Variant(variant) => { + if variant.cases.is_empty() { + return Err(Error { + span: variant.span, + msg: "empty variant".to_string(), + } + .into()); + } + let cases = variant + .cases + .iter() + .map(|case| { + Ok(Case { + docs: self.docs(&case.docs), + name: case.name.name.to_string(), + ty: self.resolve_optional_type(case.ty.as_ref())?, + }) + }) + .collect::>>()?; + TypeDefKind::Variant(Variant { cases }) + } + ast::Type::Enum(e) => { + if e.cases.is_empty() { + return Err(Error { + span: e.span, + msg: "empty enum".to_string(), + } + .into()); + } + let cases = e + .cases + .iter() + .map(|case| { + Ok(EnumCase { + docs: self.docs(&case.docs), + name: case.name.name.to_string(), + }) + }) + .collect::>>()?; + TypeDefKind::Enum(Enum { cases }) + } + ast::Type::Option(ty) => TypeDefKind::Option(self.resolve_type(ty)?), + ast::Type::Result(r) => TypeDefKind::Result(Result_ { + ok: self.resolve_optional_type(r.ok.as_deref())?, + err: self.resolve_optional_type(r.err.as_deref())?, + }), + ast::Type::Future(t) => TypeDefKind::Future(self.resolve_optional_type(t.as_deref())?), + ast::Type::Stream(s) => TypeDefKind::Stream(Stream { + element: self.resolve_optional_type(s.element.as_deref())?, + end: self.resolve_optional_type(s.end.as_deref())?, + }), + }) + } + + fn resolve_type_name(&mut self, name: &ast::Id<'_>) -> Result { + match self.type_lookup.get(name.name) { + Some((TypeOrItem::Type(id), _)) => Ok(*id), + Some((TypeOrItem::Item(s), _)) => bail!(Error { + span: name.span, + msg: format!("cannot use {s} `{name}` as a type", name = name.name), + }), + None => bail!(Error { + span: name.span, + msg: format!("name `{name}` is not defined", name = name.name), + }), + } + } + + fn validate_resource(&mut self, name: &ast::Id<'_>) -> Result { + let id = self.resolve_type_name(name)?; + let mut cur = id; + loop { + match self.types[cur].kind { + TypeDefKind::Resource => break Ok(id), + TypeDefKind::Type(Type::Id(ty)) => cur = ty, + TypeDefKind::Unknown => { + self.required_resource_types.push((cur, name.span)); + break Ok(id); + } + _ => bail!(Error { + span: name.span, + msg: format!("type `{}` used in a handle must be a resource", name.name), + }), + } + } + } + + fn resolve_type(&mut self, ty: &super::Type<'_>) -> Result { + // Resources must be declared at the top level to have their methods + // processed appropriately, but resources also shouldn't show up + // recursively so assert that's not happening here. + match ty { + ast::Type::Resource(_) => unreachable!(), + _ => {} + } + let kind = self.resolve_type_def(ty)?; + Ok(self.anon_type_def(TypeDef { + kind, + name: None, + docs: Docs::default(), + owner: TypeOwner::None, + })) + } + + fn resolve_optional_type(&mut self, ty: Option<&super::Type<'_>>) -> Result> { + match ty { + Some(ty) => Ok(Some(self.resolve_type(ty)?)), + None => Ok(None), + } + } + + fn anon_type_def(&mut self, ty: TypeDef) -> Type { + let key = match &ty.kind { + TypeDefKind::Type(t) => return *t, + TypeDefKind::Variant(v) => Key::Variant( + v.cases + .iter() + .map(|case| (case.name.clone(), case.ty)) + .collect::>(), + ), + TypeDefKind::Handle(Handle::Borrow(h)) => Key::BorrowHandle(*h), + // An anonymous `own` type is the same as a reference to the type + // `T`, so avoid creating anonymous type and return that here + // directly. Note that this additionally avoids creating distinct + // anonymous types for `list` and `list>` for example. + TypeDefKind::Handle(Handle::Own(id)) => return Type::Id(*id), + TypeDefKind::Resource => unreachable!("anonymous resources aren't supported"), + TypeDefKind::Record(r) => Key::Record( + r.fields + .iter() + .map(|case| (case.name.clone(), case.ty)) + .collect::>(), + ), + TypeDefKind::Flags(r) => { + Key::Flags(r.flags.iter().map(|f| f.name.clone()).collect::>()) + } + TypeDefKind::Tuple(t) => Key::Tuple(t.types.clone()), + TypeDefKind::Enum(r) => { + Key::Enum(r.cases.iter().map(|f| f.name.clone()).collect::>()) + } + TypeDefKind::List(ty) => Key::List(*ty), + TypeDefKind::Option(t) => Key::Option(*t), + TypeDefKind::Result(r) => Key::Result(r.ok, r.err), + TypeDefKind::Future(ty) => Key::Future(*ty), + TypeDefKind::Stream(s) => Key::Stream(s.element, s.end), + TypeDefKind::Unknown => unreachable!(), + }; + let types = &mut self.types; + let id = self + .anon_types + .entry(key) + .or_insert_with(|| types.alloc(ty)); + Type::Id(*id) + } + + fn docs(&mut self, doc: &super::Docs<'_>) -> Docs { + let mut lines = vec![]; + for doc in doc.docs.iter() { + if let Some(doc) = doc.strip_prefix("/**") { + lines.push(doc.strip_suffix("*/").unwrap().trim()); + } else { + lines.push(doc.trim_start_matches('/').trim()); + } + } + let contents = if lines.is_empty() { + None + } else { + Some(lines.join("\n")) + }; + Docs { contents } + } + + fn resolve_params(&mut self, params: &ParamList<'_>, kind: &FunctionKind) -> Result { + let mut ret = IndexMap::new(); + match *kind { + // These kinds of methods don't have any adjustments to the + // parameters, so do nothing here. + FunctionKind::Freestanding | FunctionKind::Constructor(_) | FunctionKind::Static(_) => { + } + + // Methods automatically get a `self` initial argument so insert + // that here before processing the normal parameters. + FunctionKind::Method(id) => { + let shared = self.anon_type_def(TypeDef { + docs: Docs::default(), + kind: TypeDefKind::Handle(Handle::Borrow(id)), + name: None, + owner: TypeOwner::None, + }); + ret.insert("self".to_string(), shared); + } + } + for (name, ty) in params { + let prev = ret.insert(name.name.to_string(), self.resolve_type(ty)?); + if prev.is_some() { + return Err(Error { + span: name.span, + msg: format!("param `{}` is defined more than once", name.name), + } + .into()); + } + } + Ok(ret.into_iter().collect()) + } + + fn resolve_results( + &mut self, + results: &ResultList<'_>, + kind: &FunctionKind, + ) -> Result { + match *kind { + // These kinds of methods don't have any adjustments to the return + // values, so plumb them through as-is. + FunctionKind::Freestanding | FunctionKind::Method(_) | FunctionKind::Static(_) => { + match results { + ResultList::Named(rs) => Ok(Results::Named( + self.resolve_params(rs, &FunctionKind::Freestanding)?, + )), + ResultList::Anon(ty) => Ok(Results::Anon(self.resolve_type(ty)?)), + } + } + + // Constructors are alwys parsed as 0 returned types but they're + // automatically translated as a single return type of the type that + // it's a constructor for. + FunctionKind::Constructor(id) => { + match results { + ResultList::Named(rs) => assert!(rs.is_empty()), + ResultList::Anon(_) => unreachable!(), + } + Ok(Results::Anon(Type::Id(id))) + } + } + } +} + +fn collect_deps<'a>(ty: &ast::Type<'a>, deps: &mut Vec>) { + match ty { + ast::Type::Bool + | ast::Type::U8 + | ast::Type::U16 + | ast::Type::U32 + | ast::Type::U64 + | ast::Type::S8 + | ast::Type::S16 + | ast::Type::S32 + | ast::Type::S64 + | ast::Type::Float32 + | ast::Type::Float64 + | ast::Type::Char + | ast::Type::String + | ast::Type::Flags(_) + | ast::Type::Enum(_) => {} + ast::Type::Name(name) => deps.push(name.clone()), + ast::Type::List(list) => collect_deps(list, deps), + ast::Type::Handle(handle) => match handle { + ast::Handle::Own { resource } => deps.push(resource.clone()), + ast::Handle::Borrow { resource } => deps.push(resource.clone()), + }, + ast::Type::Resource(_) => {} + ast::Type::Record(record) => { + for field in record.fields.iter() { + collect_deps(&field.ty, deps); + } + } + ast::Type::Tuple(types) => { + for ty in types { + collect_deps(ty, deps); + } + } + ast::Type::Variant(variant) => { + for case in variant.cases.iter() { + if let Some(ty) = &case.ty { + collect_deps(ty, deps); + } + } + } + ast::Type::Option(ty) => collect_deps(ty, deps), + ast::Type::Result(r) => { + if let Some(ty) = &r.ok { + collect_deps(ty, deps); + } + if let Some(ty) = &r.err { + collect_deps(ty, deps); + } + } + ast::Type::Future(t) => { + if let Some(t) = t { + collect_deps(t, deps) + } + } + ast::Type::Stream(s) => { + if let Some(t) = &s.element { + collect_deps(t, deps); + } + if let Some(t) = &s.end { + collect_deps(t, deps); + } + } + } +} diff --git a/crates/wit-parser/src/ast/toposort.rs b/crates/wit-parser/src/ast/toposort.rs new file mode 100644 index 0000000000..0a43dc0325 --- /dev/null +++ b/crates/wit-parser/src/ast/toposort.rs @@ -0,0 +1,225 @@ +use crate::ast::{Id, Span}; +use anyhow::Result; +use indexmap::IndexMap; +use std::collections::BinaryHeap; +use std::fmt; +use std::mem; + +#[derive(Default, Clone)] +struct State { + /// Number of outbound edges from this node which have still not been + /// processed into the topological ordering. + outbound_remaining: usize, + + /// Indices of nodes that depend on this one, used when this node is added + /// to the binary heap to decrement `outbound_remaining`. + reverse_deps: Vec, +} + +/// Performs a topological sort of the `deps` provided, returning the order in +/// which to visit the nodes in reverse-dep order. +/// +/// This sort goes one level further as well to produce a stable ordering +/// regardless of the input edges so long as the structure of the graph has +/// changed. Notably the nodes are sorted, by name, in the output in addition to +/// being sorted in dependency order. This is done to assist with round-tripping +/// documents where new edges are discovered during world elaboration that +/// doesn't change the dependency graph but can change the dependency listings +/// between serializations. +/// +/// The algorithm chosen here to do this is: +/// +/// * Build some metadata about all nodes including their count of outbound +/// edges remaining to be added to the order and a reverse dependency list. +/// * Collect all nodes with 0 outbound edges into a binary heap. +/// * Pop from the binary heap and decrement outbound edges that depend on +/// this node. +/// * Iterate until the dependency ordering is the same size as the dependency +/// array. +/// +/// This sort will also detect when dependencies are missing or when cycles are +/// present and return an error. +pub fn toposort<'a>( + kind: &str, + deps: &IndexMap<&'a str, Vec>>, +) -> Result, Error> { + // Initialize a `State` per-node with the number of outbound edges and + // additionally filling out the `reverse_deps` array. + let mut states = vec![State::default(); deps.len()]; + for (i, (_, edges)) in deps.iter().enumerate() { + states[i].outbound_remaining = edges.len(); + for edge in edges { + let (j, _, _) = deps + .get_full(edge.name) + .ok_or_else(|| Error::NonexistentDep { + span: edge.span, + name: edge.name.to_string(), + kind: kind.to_string(), + })?; + states[j].reverse_deps.push(i); + } + } + + let mut order = Vec::new(); + let mut heap = BinaryHeap::new(); + + // Seed the `heap` with edges that have no outbound edges + // + // The heap here is keyed by `(usize, &str, usize)` where the first `usize` + // is unique which is what determines the order of the heap. The other two + // fields are metadata used when pulling from the heap. The first `usize` is + // the index of the item within the original dependency map which should + // reflect the original source order of the item. Note that this is stored + // in reverse order to ensure that when there are multiple items in the heap + // the first item in the original order is popped first. + for (i, dep) in deps.keys().enumerate() { + if states[i].outbound_remaining == 0 { + heap.push((deps.len() - i, *dep, i)); + } + } + + // Drain the binary heap which represents all nodes that have had all their + // dependencies processed. Iteratively add to the heap as well as nodes are + // removed. + while let Some((_order, node, i)) = heap.pop() { + order.push(node); + for i in mem::take(&mut states[i].reverse_deps) { + states[i].outbound_remaining -= 1; + if states[i].outbound_remaining == 0 { + let (dep, _) = deps.get_index(i).unwrap(); + heap.push((deps.len() - i, *dep, i)); + } + } + } + + // If all nodes are present in order then a topological ordering was + // achieved and it can be returned. + if order.len() == deps.len() { + return Ok(order); + } + + // ... otherwise there are still dependencies with remaining edges which + // means that a cycle must be present, so find the cycle and report the + // error. + for (i, state) in states.iter().enumerate() { + if state.outbound_remaining == 0 { + continue; + } + let (_, edges) = deps.get_index(i).unwrap(); + for dep in edges { + let (j, _, _) = deps.get_full(dep.name).unwrap(); + if states[j].outbound_remaining == 0 { + continue; + } + return Err(Error::Cycle { + span: dep.span, + name: dep.name.to_string(), + kind: kind.to_string(), + }); + } + } + + unreachable!() +} + +#[derive(Debug)] +pub enum Error { + NonexistentDep { + span: Span, + name: String, + kind: String, + }, + Cycle { + span: Span, + name: String, + kind: String, + }, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::NonexistentDep { kind, name, .. } => { + write!(f, "{kind} `{name}` does not exist") + } + Error::Cycle { kind, name, .. } => { + write!(f, "{kind} `{name}` depends on itself") + } + } + } +} + +impl std::error::Error for Error {} + +#[cfg(test)] +mod tests { + use super::*; + + fn id(name: &str) -> Id<'_> { + Id { + name, + span: Span { start: 0, end: 0 }, + } + } + + #[test] + fn smoke() { + let empty: Vec<&str> = Vec::new(); + assert_eq!(toposort("", &IndexMap::new()).unwrap(), empty); + + let mut nonexistent = IndexMap::new(); + nonexistent.insert("a", vec![id("b")]); + assert!(matches!( + toposort("", &nonexistent), + Err(Error::NonexistentDep { .. }) + )); + + let mut one = IndexMap::new(); + one.insert("a", vec![]); + assert_eq!(toposort("", &one).unwrap(), ["a"]); + + let mut two = IndexMap::new(); + two.insert("a", vec![]); + two.insert("b", vec![id("a")]); + assert_eq!(toposort("", &two).unwrap(), ["a", "b"]); + + let mut two = IndexMap::new(); + two.insert("a", vec![id("b")]); + two.insert("b", vec![]); + assert_eq!(toposort("", &two).unwrap(), ["b", "a"]); + } + + #[test] + fn cycles() { + let mut cycle = IndexMap::new(); + cycle.insert("a", vec![id("a")]); + assert!(matches!(toposort("", &cycle), Err(Error::Cycle { .. }))); + + let mut cycle = IndexMap::new(); + cycle.insert("a", vec![id("b")]); + cycle.insert("b", vec![id("c")]); + cycle.insert("c", vec![id("a")]); + assert!(matches!(toposort("", &cycle), Err(Error::Cycle { .. }))); + } + + #[test] + fn depend_twice() { + let mut two = IndexMap::new(); + two.insert("b", vec![id("a"), id("a")]); + two.insert("a", vec![]); + assert_eq!(toposort("", &two).unwrap(), ["a", "b"]); + } + + #[test] + fn preserve_order() { + let mut order = IndexMap::new(); + order.insert("a", vec![]); + order.insert("b", vec![]); + assert_eq!(toposort("", &order).unwrap(), ["a", "b"]); + + let mut order = IndexMap::new(); + order.insert("b", vec![]); + order.insert("a", vec![]); + assert_eq!(toposort("", &order).unwrap(), ["b", "a"]); + } +} diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs new file mode 100644 index 0000000000..100b8e4976 --- /dev/null +++ b/crates/wit-parser/src/lib.rs @@ -0,0 +1,711 @@ +use anyhow::{Context, Result}; +use id_arena::{Arena, Id}; +use indexmap::IndexMap; +use semver::Version; +use serde_derive::Serialize; +use std::borrow::Cow; +use std::fmt; +use std::path::Path; + +pub mod abi; +mod ast; +use ast::lex::Span; +pub use ast::SourceMap; +mod sizealign; +pub use sizealign::*; +mod resolve; +pub use resolve::{Package, PackageId, Remap, Resolve}; +mod live; +pub use live::LiveTypes; +mod serde_; +use serde_::{ + serialize_anon_result, serialize_id, serialize_id_map, serialize_none, serialize_optional_id, + serialize_params, +}; + +/// Checks if the given string is a legal identifier in wit. +pub fn validate_id(s: &str) -> Result<()> { + ast::validate_id(0, s)?; + Ok(()) +} + +pub type WorldId = Id; +pub type InterfaceId = Id; +pub type TypeId = Id; + +/// Representation of a parsed WIT package which has not resolved external +/// dependencies yet. +/// +/// This representation has performed internal resolution of the WIT package +/// itself, ensuring that all references internally are valid and the WIT was +/// syntactically valid and such. +/// +/// The fields of this structure represent a flat list of arrays unioned from +/// all documents within the WIT package. This means, for example, that all +/// types from all documents are located in `self.types`. The fields of each +/// item can help splitting back out into packages/interfaces/etc as necessary. +/// +/// Note that an `UnresolvedPackage` cannot be queried in general about +/// information such as size or alignment as that would require resolution of +/// foreign dependencies. Translations such as to-binary additionally are not +/// supported on an `UnresolvedPackage` due to the lack of knowledge about the +/// foreign types. This is intended to be an intermediate state which can be +/// inspected by embedders, if necessary, before quickly transforming to a +/// [`Resolve`] to fully work with a WIT package. +/// +/// After an [`UnresolvedPackage`] is parsed it can be fully resolved with +/// [`Resolve::push`]. During this operation a dependency map is specified which +/// will connect the `foreign_deps` field of this structure to packages +/// previously inserted within the [`Resolve`]. Embedders are responsible for +/// performing this resolution themselves. +#[derive(Clone)] +pub struct UnresolvedPackage { + /// The namespace, name, and version information for this package. + pub name: PackageName, + + /// All worlds from all documents within this package. + /// + /// Each world lists the document that it is from. + pub worlds: Arena, + + /// All interfaces from all documents within this package. + /// + /// Each interface lists the document that it is from. Interfaces are listed + /// in topological order as well so iteration through this arena will only + /// reference prior elements already visited when working with recursive + /// references. + pub interfaces: Arena, + + /// All types from all documents within this package. + /// + /// Each type lists the interface or world that defined it, or nothing if + /// it's an anonymous type. Types are listed in this arena in topological + /// order to ensure that iteration through this arena will only reference + /// other types transitively that are already iterated over. + pub types: Arena, + + /// All foreign dependencies that this package depends on. + /// + /// These foreign dependencies must be resolved to convert this unresolved + /// package into a `Resolve`. The map here is keyed by the name of the + /// foreign package that this depends on, and the sub-map is keyed by an + /// interface name followed by the identifier within `self.interfaces`. The + /// fields of `self.interfaces` describes the required types that are from + /// each foreign interface. + pub foreign_deps: IndexMap>, + + /// Doc comments for this package. + pub docs: Docs, + + unknown_type_spans: Vec, + world_item_spans: Vec<(Vec, Vec)>, + interface_spans: Vec, + world_spans: Vec, + foreign_dep_spans: Vec, + source_map: SourceMap, + include_world_spans: Vec, + required_resource_types: Vec<(TypeId, Span)>, +} + +#[derive(Debug, Copy, Clone, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum AstItem { + #[serde(serialize_with = "serialize_id")] + Interface(InterfaceId), + #[serde(serialize_with = "serialize_id")] + World(WorldId), +} + +/// A structure used to keep track of the name of a package, containing optional +/// information such as a namespace and version information. +/// +/// This is directly encoded as an "ID" in the binary component representation +/// with an interfaced tacked on as well. +#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize)] +#[serde(into = "String")] +pub struct PackageName { + /// A namespace such as `wasi` in `wasi:foo/bar` + pub namespace: String, + /// The kebab-name of this package, which is always specified. + pub name: String, + /// Optional major/minor version information. + pub version: Option, +} + +impl From for String { + fn from(name: PackageName) -> String { + name.to_string() + } +} + +impl PackageName { + /// Returns the ID that this package name would assign the `interface` name + /// specified. + pub fn interface_id(&self, interface: &str) -> String { + let mut s = String::new(); + s.push_str(&format!("{}:{}/{interface}", self.namespace, self.name)); + if let Some(version) = &self.version { + s.push_str(&format!("@{version}")); + } + s + } +} + +impl fmt::Display for PackageName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{}", self.namespace, self.name)?; + if let Some(version) = &self.version { + write!(f, "@{version}")?; + } + Ok(()) + } +} + +#[derive(Debug)] +struct Error { + span: Span, + msg: String, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.msg.fmt(f) + } +} + +impl std::error::Error for Error {} + +impl UnresolvedPackage { + /// Parses the given string as a wit document. + /// + /// The `path` argument is used for error reporting. The `contents` provided + /// will not be able to use `pkg` use paths to other documents. + pub fn parse(path: &Path, contents: &str) -> Result { + let mut map = SourceMap::default(); + map.push(path, contents); + map.parse() + } + + /// Parse a WIT package at the provided path. + /// + /// The path provided is inferred whether it's a file or a directory. A file + /// is parsed with [`UnresolvedPackage::parse_file`] and a directory is + /// parsed with [`UnresolvedPackage::parse_dir`]. + pub fn parse_path(path: &Path) -> Result { + if path.is_dir() { + UnresolvedPackage::parse_dir(path) + } else { + UnresolvedPackage::parse_file(path) + } + } + + /// Parses a WIT package from the file provided. + /// + /// The WIT package returned will be a single-document package and will not + /// be able to use `pkg` paths to other documents. + pub fn parse_file(path: &Path) -> Result { + let contents = std::fs::read_to_string(path) + .with_context(|| format!("failed to read file {path:?}"))?; + Self::parse(path, &contents) + } + + /// Parses a WIT package from the directory provided. + /// + /// All files with the extension `*.wit` or `*.wit.md` will be loaded from + /// `path` into the returned package. + pub fn parse_dir(path: &Path) -> Result { + let mut map = SourceMap::default(); + let cx = || format!("failed to read directory {path:?}"); + for entry in path.read_dir().with_context(&cx)? { + let entry = entry.with_context(&cx)?; + let path = entry.path(); + let ty = entry.file_type().with_context(&cx)?; + if ty.is_dir() { + continue; + } + if ty.is_symlink() { + if path.is_dir() { + continue; + } + } + let filename = match path.file_name().and_then(|s| s.to_str()) { + Some(name) => name, + None => continue, + }; + if !filename.ends_with(".wit") && !filename.ends_with(".wit.md") { + continue; + } + map.push_file(&path)?; + } + map.parse() + } + + /// Returns an iterator over the list of source files that were read when + /// parsing this package. + pub fn source_files(&self) -> impl Iterator { + self.source_map.source_files() + } +} + +#[derive(Debug, Clone, Serialize)] +pub struct World { + /// The WIT identifier name of this world. + pub name: String, + + /// All imported items into this interface, both worlds and functions. + pub imports: IndexMap, + + /// All exported items from this interface, both worlds and functions. + pub exports: IndexMap, + + /// The package that owns this world. + #[serde(serialize_with = "serialize_optional_id")] + pub package: Option, + + /// Documentation associated with this world declaration. + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, + + /// All the included worlds from this world. Empty if this is fully resolved + #[serde(skip)] + pub includes: Vec, + + /// All the included worlds names. Empty if this is fully resolved + #[serde(skip)] + pub include_names: Vec>, +} + +#[derive(Debug, Clone)] +pub struct IncludeName { + /// The name of the item + pub name: String, + + /// The name to be replaced with + pub as_: String, +} + +/// The key to the import/export maps of a world. Either a kebab-name or a +/// unique interface. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] +#[serde(into = "String")] +pub enum WorldKey { + /// A kebab-name. + Name(String), + /// An interface which is assigned no kebab-name. + Interface(InterfaceId), +} + +impl From for String { + fn from(key: WorldKey) -> String { + match key { + WorldKey::Name(name) => name, + WorldKey::Interface(id) => format!("interface-{}", id.index()), + } + } +} + +impl WorldKey { + /// Asserts that this is `WorldKey::Name` and returns the name. + #[track_caller] + pub fn unwrap_name(self) -> String { + match self { + WorldKey::Name(name) => name, + WorldKey::Interface(_) => panic!("expected a name, found interface"), + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum WorldItem { + /// An interface is being imported or exported from a world, indicating that + /// it's a namespace of functions. + #[serde(serialize_with = "serialize_id")] + Interface(InterfaceId), + + /// A function is being directly imported or exported from this world. + Function(Function), + + /// A type is being exported from this world. + /// + /// Note that types are never imported into worlds at this time. + #[serde(serialize_with = "serialize_id")] + Type(TypeId), +} + +#[derive(Debug, Clone, Serialize)] +pub struct Interface { + /// Optionally listed name of this interface. + /// + /// This is `None` for inline interfaces in worlds. + pub name: Option, + + /// Exported types from this interface. + /// + /// Export names are listed within the types themselves. Note that the + /// export name here matches the name listed in the `TypeDef`. + #[serde(serialize_with = "serialize_id_map")] + pub types: IndexMap, + + /// Exported functions from this interface. + pub functions: IndexMap, + + /// Documentation associated with this interface. + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, + + /// The package that owns this interface. + #[serde(serialize_with = "serialize_optional_id")] + pub package: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct TypeDef { + pub name: Option, + pub kind: TypeDefKind, + pub owner: TypeOwner, + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum TypeDefKind { + Record(Record), + Resource, + Handle(Handle), + Flags(Flags), + Tuple(Tuple), + Variant(Variant), + Enum(Enum), + Option(Type), + Result(Result_), + List(Type), + Future(Option), + Stream(Stream), + Type(Type), + + /// This represents a type of unknown structure imported from a foreign + /// interface. + /// + /// This variant is only used during the creation of `UnresolvedPackage` but + /// by the time a `Resolve` is created then this will not exist. + Unknown, +} + +impl TypeDefKind { + pub fn as_str(&self) -> &'static str { + match self { + TypeDefKind::Record(_) => "record", + TypeDefKind::Resource => "resource", + TypeDefKind::Handle(handle) => match handle { + Handle::Own(_) => "own", + Handle::Borrow(_) => "borrow", + }, + TypeDefKind::Flags(_) => "flags", + TypeDefKind::Tuple(_) => "tuple", + TypeDefKind::Variant(_) => "variant", + TypeDefKind::Enum(_) => "enum", + TypeDefKind::Option(_) => "option", + TypeDefKind::Result(_) => "result", + TypeDefKind::List(_) => "list", + TypeDefKind::Future(_) => "future", + TypeDefKind::Stream(_) => "stream", + TypeDefKind::Type(_) => "type", + TypeDefKind::Unknown => "unknown", + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum TypeOwner { + /// This type was defined within a `world` block. + #[serde(serialize_with = "serialize_id")] + World(WorldId), + /// This type was defined within an `interface` block. + #[serde(serialize_with = "serialize_id")] + Interface(InterfaceId), + /// This type wasn't inherently defined anywhere, such as a `list`, which + /// doesn't need an owner. + #[serde(untagged, serialize_with = "serialize_none")] + None, +} + +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum Handle { + #[serde(serialize_with = "serialize_id")] + Own(TypeId), + #[serde(serialize_with = "serialize_id")] + Borrow(TypeId), +} + +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +pub enum Type { + Bool, + U8, + U16, + U32, + U64, + S8, + S16, + S32, + S64, + Float32, + Float64, + Char, + String, + Id(TypeId), +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Int { + U8, + U16, + U32, + U64, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Record { + pub fields: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Field { + pub name: String, + #[serde(rename = "type")] + pub ty: Type, + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Flags { + pub flags: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Flag { + pub name: String, + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum FlagsRepr { + U8, + U16, + U32(usize), +} + +impl Flags { + pub fn repr(&self) -> FlagsRepr { + match self.flags.len() { + 0 => FlagsRepr::U32(0), + n if n <= 8 => FlagsRepr::U8, + n if n <= 16 => FlagsRepr::U16, + n => FlagsRepr::U32(sizealign::align_to(n, 32) / 32), + } + } +} + +impl FlagsRepr { + pub fn count(&self) -> usize { + match self { + FlagsRepr::U8 => 1, + FlagsRepr::U16 => 1, + FlagsRepr::U32(n) => *n, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Tuple { + pub types: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Variant { + pub cases: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Case { + pub name: String, + #[serde(rename = "type")] + pub ty: Option, + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, +} + +impl Variant { + pub fn tag(&self) -> Int { + match self.cases.len() { + n if n <= u8::max_value() as usize => Int::U8, + n if n <= u16::max_value() as usize => Int::U16, + n if n <= u32::max_value() as usize => Int::U32, + _ => panic!("too many cases to fit in a repr"), + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Enum { + pub cases: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct EnumCase { + pub name: String, + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, +} + +impl Enum { + pub fn tag(&self) -> Int { + match self.cases.len() { + n if n <= u8::max_value() as usize => Int::U8, + n if n <= u16::max_value() as usize => Int::U16, + n if n <= u32::max_value() as usize => Int::U32, + _ => panic!("too many cases to fit in a repr"), + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Result_ { + pub ok: Option, + pub err: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Stream { + pub element: Option, + pub end: Option, +} + +#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize)] +pub struct Docs { + pub contents: Option, +} + +impl Docs { + pub fn is_empty(&self) -> bool { + self.contents.is_none() + } +} + +pub type Params = Vec<(String, Type)>; + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] +#[serde(untagged)] +pub enum Results { + #[serde(serialize_with = "serialize_params")] + Named(Params), + #[serde(serialize_with = "serialize_anon_result")] + Anon(Type), +} + +pub enum ResultsTypeIter<'a> { + Named(std::slice::Iter<'a, (String, Type)>), + Anon(std::iter::Once<&'a Type>), +} + +impl<'a> Iterator for ResultsTypeIter<'a> { + type Item = &'a Type; + + fn next(&mut self) -> Option<&'a Type> { + match self { + ResultsTypeIter::Named(ps) => ps.next().map(|p| &p.1), + ResultsTypeIter::Anon(ty) => ty.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + ResultsTypeIter::Named(ps) => ps.size_hint(), + ResultsTypeIter::Anon(ty) => ty.size_hint(), + } + } +} + +impl<'a> ExactSizeIterator for ResultsTypeIter<'a> {} + +impl Results { + // For the common case of an empty results list. + pub fn empty() -> Results { + Results::Named(Vec::new()) + } + + pub fn len(&self) -> usize { + match self { + Results::Named(params) => params.len(), + Results::Anon(_) => 1, + } + } + + pub fn throws<'a>(&self, resolve: &'a Resolve) -> Option<(Option<&'a Type>, Option<&'a Type>)> { + if self.len() != 1 { + return None; + } + match self.iter_types().next().unwrap() { + Type::Id(id) => match &resolve.types[*id].kind { + TypeDefKind::Result(r) => Some((r.ok.as_ref(), r.err.as_ref())), + _ => None, + }, + _ => None, + } + } + + pub fn iter_types(&self) -> ResultsTypeIter { + match self { + Results::Named(ps) => ResultsTypeIter::Named(ps.iter()), + Results::Anon(ty) => ResultsTypeIter::Anon(std::iter::once(ty)), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct Function { + pub name: String, + pub kind: FunctionKind, + #[serde(serialize_with = "serialize_params")] + pub params: Params, + pub results: Results, + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum FunctionKind { + Freestanding, + #[serde(serialize_with = "serialize_id")] + Method(TypeId), + #[serde(serialize_with = "serialize_id")] + Static(TypeId), + #[serde(serialize_with = "serialize_id")] + Constructor(TypeId), +} + +impl Function { + pub fn item_name(&self) -> &str { + match &self.kind { + FunctionKind::Freestanding => &self.name, + FunctionKind::Method(_) | FunctionKind::Static(_) => { + &self.name[self.name.find('.').unwrap() + 1..] + } + FunctionKind::Constructor(_) => "constructor", + } + } + + /// Gets the core export name for this function. + pub fn core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> { + match interface { + Some(interface) => Cow::Owned(format!("{interface}#{}", self.name)), + None => Cow::Borrowed(&self.name), + } + } +} diff --git a/crates/wit-parser/src/live.rs b/crates/wit-parser/src/live.rs new file mode 100644 index 0000000000..19ded9153f --- /dev/null +++ b/crates/wit-parser/src/live.rs @@ -0,0 +1,111 @@ +use crate::{Function, InterfaceId, Resolve, Type, TypeDefKind, TypeId, WorldId, WorldItem}; +use indexmap::IndexSet; + +#[derive(Default)] +pub struct LiveTypes { + set: IndexSet, +} + +impl LiveTypes { + pub fn iter(&self) -> impl Iterator + '_ { + self.set.iter().copied() + } + + pub fn len(&self) -> usize { + self.set.len() + } + + pub fn add_interface(&mut self, resolve: &Resolve, iface: InterfaceId) { + let iface = &resolve.interfaces[iface]; + for (_, id) in iface.types.iter() { + self.add_type_id(resolve, *id); + } + for (_, func) in iface.functions.iter() { + self.add_func(resolve, func); + } + } + + pub fn add_world(&mut self, resolve: &Resolve, world: WorldId) { + let world = &resolve.worlds[world]; + for (_, item) in world.imports.iter().chain(world.exports.iter()) { + self.add_world_item(resolve, item); + } + } + + pub fn add_world_item(&mut self, resolve: &Resolve, item: &WorldItem) { + match item { + WorldItem::Interface(id) => self.add_interface(resolve, *id), + WorldItem::Function(f) => self.add_func(resolve, f), + WorldItem::Type(t) => self.add_type_id(resolve, *t), + } + } + + pub fn add_func(&mut self, resolve: &Resolve, func: &Function) { + for (_, ty) in func.params.iter() { + self.add_type(resolve, ty); + } + for ty in func.results.iter_types() { + self.add_type(resolve, ty); + } + } + + pub fn add_type_id(&mut self, resolve: &Resolve, ty: TypeId) { + if self.set.contains(&ty) { + return; + } + match &resolve.types[ty].kind { + TypeDefKind::Type(t) + | TypeDefKind::List(t) + | TypeDefKind::Option(t) + | TypeDefKind::Future(Some(t)) => self.add_type(resolve, t), + TypeDefKind::Handle(handle) => match handle { + crate::Handle::Own(ty) => self.add_type_id(resolve, *ty), + crate::Handle::Borrow(ty) => self.add_type_id(resolve, *ty), + }, + TypeDefKind::Resource => {} + TypeDefKind::Record(r) => { + for field in r.fields.iter() { + self.add_type(resolve, &field.ty); + } + } + TypeDefKind::Tuple(r) => { + for ty in r.types.iter() { + self.add_type(resolve, ty); + } + } + TypeDefKind::Variant(v) => { + for case in v.cases.iter() { + if let Some(ty) = &case.ty { + self.add_type(resolve, ty); + } + } + } + TypeDefKind::Result(r) => { + if let Some(ty) = &r.ok { + self.add_type(resolve, ty); + } + if let Some(ty) = &r.err { + self.add_type(resolve, ty); + } + } + TypeDefKind::Stream(s) => { + if let Some(ty) = &s.element { + self.add_type(resolve, ty); + } + if let Some(ty) = &s.end { + self.add_type(resolve, ty); + } + } + TypeDefKind::Flags(_) | TypeDefKind::Enum(_) | TypeDefKind::Future(None) => {} + TypeDefKind::Unknown => unreachable!(), + } + assert!(self.set.insert(ty)); + } + + pub fn add_type(&mut self, resolve: &Resolve, ty: &Type) { + match ty { + Type::Id(id) => self.add_type_id(resolve, *id), + _ => {} + } + } +} diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs new file mode 100644 index 0000000000..f98fa4d665 --- /dev/null +++ b/crates/wit-parser/src/resolve.rs @@ -0,0 +1,1783 @@ +use crate::ast::lex::Span; +use crate::ast::{parse_use_path, AstUsePath}; +use crate::serde_::{serialize_arena, serialize_id_map}; +use crate::{ + AstItem, Docs, Error, Function, FunctionKind, Handle, IncludeName, Interface, InterfaceId, + PackageName, Results, Type, TypeDef, TypeDefKind, TypeId, TypeOwner, UnresolvedPackage, World, + WorldId, WorldItem, WorldKey, +}; +use anyhow::{anyhow, bail, Context, Result}; +use id_arena::{Arena, Id}; +use indexmap::{IndexMap, IndexSet}; +use serde_derive::Serialize; +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::mem; +use std::path::{Path, PathBuf}; + +/// Representation of a fully resolved set of WIT packages. +/// +/// This structure contains a graph of WIT packages and all of their contents +/// merged together into the contained arenas. All items are sorted +/// topologically and everything here is fully resolved, so with a `Resolve` no +/// name lookups are necessary and instead everything is index-based. +/// +/// Working with a WIT package requires inserting it into a `Resolve` to ensure +/// that all of its dependencies are satisfied. This will give the full picture +/// of that package's types and such. +/// +/// Each item in a `Resolve` has a parent link to trace it back to the original +/// package as necessary. +#[derive(Default, Clone, Serialize)] +pub struct Resolve { + #[serde(serialize_with = "serialize_arena")] + pub worlds: Arena, + #[serde(serialize_with = "serialize_arena")] + pub interfaces: Arena, + #[serde(serialize_with = "serialize_arena")] + pub types: Arena, + #[serde(serialize_with = "serialize_arena")] + pub packages: Arena, + #[serde(skip)] + pub package_names: IndexMap, +} + +/// A WIT package within a `Resolve`. +/// +/// A package is a collection of interfaces and worlds. Packages additionally +/// have a unique identifier that affects generated components and uniquely +/// identifiers this particular package. +#[derive(Clone, Serialize)] +pub struct Package { + /// A unique name corresponding to this package. + pub name: PackageName, + + /// Documentation associated with this package. + #[serde(skip_serializing_if = "Docs::is_empty")] + pub docs: Docs, + + /// All interfaces contained in this packaged, keyed by the interface's + /// name. + #[serde(serialize_with = "serialize_id_map")] + pub interfaces: IndexMap, + + /// All worlds contained in this package, keyed by the world's name. + #[serde(serialize_with = "serialize_id_map")] + pub worlds: IndexMap, +} + +pub type PackageId = Id; + +impl Resolve { + /// Creates a new [`Resolve`] with no packages/items inside of it. + pub fn new() -> Resolve { + Resolve::default() + } + + /// Parses the filesystem directory at `path` as a WIT package and returns + /// the fully resolved [`PackageId`] as a result. + /// + /// Dependencies referenced by the WIT package at `path` will be loaded from + /// a `deps/..` directory under `path`. All directories under `deps/` will + /// be parsed as a WIT package. The directory name containing each package + /// is not used as each package is otherwise self-identifying. + /// + /// This function returns the [`PackageId`] of the root parsed package at + /// `path`, along with a list of all paths that were consumed during parsing + /// for the root package and all dependency packages. + pub fn push_dir(&mut self, path: &Path) -> Result<(PackageId, Vec)> { + let pkg = UnresolvedPackage::parse_dir(path) + .with_context(|| format!("failed to parse package: {}", path.display()))?; + + let deps = path.join("deps"); + let mut deps = parse_deps_dir(&deps) + .with_context(|| format!("failed to parse dependency directory: {}", deps.display()))?; + + // Perform a simple topological sort which will bail out on cycles + // and otherwise determine the order that packages must be added to + // this `Resolve`. + let mut order = IndexSet::new(); + let mut visiting = HashSet::new(); + for pkg in deps.values().chain([&pkg]) { + visit(&pkg, &deps, &mut order, &mut visiting)?; + } + + // Using the topological ordering insert each package incrementally. + // Additionally note that the last item visited here is the root + // package, which is the one returned here. + let mut last = None; + let mut files = Vec::new(); + let mut pkg = Some(pkg); + for name in order { + let pkg = deps.remove(&name).unwrap_or_else(|| pkg.take().unwrap()); + files.extend(pkg.source_files().map(|p| p.to_path_buf())); + let pkgid = self.push(pkg)?; + last = Some(pkgid); + } + + return Ok((last.unwrap(), files)); + + fn parse_deps_dir(path: &Path) -> Result> { + let mut ret = BTreeMap::new(); + // If there's no `deps` dir, then there's no deps, so return the + // empty set. + if !path.exists() { + return Ok(ret); + } + for dep in path.read_dir().context("failed to read directory")? { + let dep = dep.context("failed to read directory iterator")?; + let path = dep.path(); + + // Files in deps dir are ignored for now to avoid accidentally + // including things like `.DS_Store` files in the call below to + // `parse_dir`. + if path.is_file() { + continue; + } + + let pkg = UnresolvedPackage::parse_dir(&path) + .with_context(|| format!("failed to parse package: {}", path.display()))?; + let prev = ret.insert(pkg.name.clone(), pkg); + if let Some(prev) = prev { + bail!("duplicate definitions of package `{}` found", prev.name); + } + } + Ok(ret) + } + + fn visit<'a>( + pkg: &'a UnresolvedPackage, + deps: &'a BTreeMap, + order: &mut IndexSet, + visiting: &mut HashSet<&'a PackageName>, + ) -> Result<()> { + if order.contains(&pkg.name) { + return Ok(()); + } + pkg.source_map.rewrite_error(|| { + for (i, (dep, _)) in pkg.foreign_deps.iter().enumerate() { + let span = pkg.foreign_dep_spans[i]; + if !visiting.insert(dep) { + bail!(Error { + span, + msg: format!("package depends on itself"), + }); + } + let dep = deps.get(dep).ok_or_else(|| Error { + span, + msg: format!("failed to find package `{dep}` in `deps` directory"), + })?; + visit(dep, deps, order, visiting)?; + assert!(visiting.remove(&dep.name)); + } + assert!(order.insert(pkg.name.clone())); + Ok(()) + }) + } + } + + /// Appends a new [`UnresolvedPackage`] to this [`Resolve`], creating a + /// fully resolved package with no dangling references. + /// + /// The `deps` argument indicates that the named dependencies in + /// `unresolved` to packages are resolved by the mapping specified. + /// + /// Any dependency resolution error or otherwise world-elaboration error + /// will be returned here. If successful a package identifier is returned. + pub fn push(&mut self, mut unresolved: UnresolvedPackage) -> Result { + let source_map = mem::take(&mut unresolved.source_map); + source_map.rewrite_error(|| Remap::default().append(self, unresolved)) + } + + pub fn all_bits_valid(&self, ty: &Type) -> bool { + match ty { + Type::U8 + | Type::S8 + | Type::U16 + | Type::S16 + | Type::U32 + | Type::S32 + | Type::U64 + | Type::S64 + | Type::Float32 + | Type::Float64 => true, + + Type::Bool | Type::Char | Type::String => false, + + Type::Id(id) => match &self.types[*id].kind { + TypeDefKind::List(_) + | TypeDefKind::Variant(_) + | TypeDefKind::Enum(_) + | TypeDefKind::Option(_) + | TypeDefKind::Result(_) + | TypeDefKind::Future(_) + | TypeDefKind::Stream(_) => false, + TypeDefKind::Type(t) => self.all_bits_valid(t), + + TypeDefKind::Handle(h) => match h { + crate::Handle::Own(_) => true, + crate::Handle::Borrow(_) => true, + }, + + TypeDefKind::Resource => false, + TypeDefKind::Record(r) => r.fields.iter().all(|f| self.all_bits_valid(&f.ty)), + TypeDefKind::Tuple(t) => t.types.iter().all(|t| self.all_bits_valid(t)), + + // FIXME: this could perhaps be `true` for multiples-of-32 but + // seems better to probably leave this as unconditionally + // `false` for now, may want to reconsider later? + TypeDefKind::Flags(_) => false, + + TypeDefKind::Unknown => unreachable!(), + }, + } + } + + /// Merges all the contents of a different `Resolve` into this one. The + /// `Remap` structure returned provides a mapping from all old indices to + /// new indices + /// + /// This operation can fail if `resolve` disagrees with `self` about the + /// packages being inserted. Otherwise though this will additionally attempt + /// to "union" packages found in `resolve` with those found in `self`. + /// Unioning packages is keyed on the name/url of packages for those with + /// URLs present. If found then it's assumed that both `Resolve` instances + /// were originally created from the same contents and are two views + /// of the same package. + pub fn merge(&mut self, resolve: Resolve) -> Result { + log::trace!( + "merging {} packages into {} packages", + resolve.packages.len(), + self.packages.len() + ); + + let mut map = MergeMap::new(&resolve, &self)?; + map.build()?; + let MergeMap { + package_map, + interface_map, + type_map, + world_map, + interfaces_to_add, + worlds_to_add, + .. + } = map; + + // With a set of maps from ids in `resolve` to ids in `self` the next + // operation is to start moving over items and building a `Remap` to + // update ids. + // + // Each component field of `resolve` is moved into `self` so long as + // its ID is not within one of the maps above. If it's present in a map + // above then that means the item is already present in `self` so a new + // one need not be added. If it's not present in a map that means it's + // not present in `self` so it must be added to an arena. + // + // When adding an item to an arena one of the `remap.update_*` methods + // is additionally called to update all identifiers from pointers within + // `resolve` to becoming pointers within `self`. + // + // Altogether this should weave all the missing items in `self` from + // `resolve` into one structure while updating all identifiers to + // be local within `self`. + + let mut remap = Remap::default(); + let Resolve { + types, + worlds, + interfaces, + packages, + package_names, + } = resolve; + + let mut moved_types = Vec::new(); + for (id, mut ty) in types { + let new_id = type_map.get(&id).copied().unwrap_or_else(|| { + moved_types.push(id); + remap.update_typedef(self, &mut ty); + self.types.alloc(ty) + }); + assert_eq!(remap.types.len(), id.index()); + remap.types.push(new_id); + } + + let mut moved_interfaces = Vec::new(); + for (id, mut iface) in interfaces { + let new_id = interface_map.get(&id).copied().unwrap_or_else(|| { + moved_interfaces.push(id); + remap.update_interface(self, &mut iface); + self.interfaces.alloc(iface) + }); + assert_eq!(remap.interfaces.len(), id.index()); + remap.interfaces.push(new_id); + } + + let mut moved_worlds = Vec::new(); + for (id, mut world) in worlds { + let new_id = world_map.get(&id).copied().unwrap_or_else(|| { + moved_worlds.push(id); + let mut update = |map: &mut IndexMap| { + for (mut name, mut item) in mem::take(map) { + remap.update_world_key(&mut name); + match &mut item { + WorldItem::Function(f) => remap.update_function(self, f), + WorldItem::Interface(i) => *i = remap.interfaces[i.index()], + WorldItem::Type(i) => *i = remap.types[i.index()], + } + map.insert(name, item); + } + }; + update(&mut world.imports); + update(&mut world.exports); + self.worlds.alloc(world) + }); + assert_eq!(remap.worlds.len(), id.index()); + remap.worlds.push(new_id); + } + + for (id, mut pkg) in packages { + let new_id = package_map.get(&id).copied().unwrap_or_else(|| { + for (_, id) in pkg.interfaces.iter_mut() { + *id = remap.interfaces[id.index()]; + } + for (_, id) in pkg.worlds.iter_mut() { + *id = remap.worlds[id.index()]; + } + self.packages.alloc(pkg) + }); + assert_eq!(remap.packages.len(), id.index()); + remap.packages.push(new_id); + } + + for (name, id) in package_names { + let id = remap.packages[id.index()]; + if let Some(prev) = self.package_names.insert(name, id) { + assert_eq!(prev, id); + } + } + + // Fixup all "parent" links now. + // + // Note that this is only done for items that are actually moved from + // `resolve` into `self`, which is tracked by the various `moved_*` + // lists built incrementally above. The ids in the `moved_*` lists + // are ids within `resolve`, so they're translated through `remap` to + // ids within `self`. + for id in moved_worlds { + let id = remap.worlds[id.index()]; + let pkg = self.worlds[id].package.as_mut().unwrap(); + *pkg = remap.packages[pkg.index()]; + } + for id in moved_interfaces { + let id = remap.interfaces[id.index()]; + let pkg = self.interfaces[id].package.as_mut().unwrap(); + *pkg = remap.packages[pkg.index()]; + } + for id in moved_types { + let id = remap.types[id.index()]; + match &mut self.types[id].owner { + TypeOwner::Interface(id) => *id = remap.interfaces[id.index()], + TypeOwner::World(id) => *id = remap.worlds[id.index()], + TypeOwner::None => {} + } + } + + // And finally process items that were present in `resolve` but were + // not present in `self`. This is only done for merged packages as + // documents may be added to `self.documents` but wouldn't otherwise be + // present in the `documents` field of the corresponding package. + for (name, pkg, iface) in interfaces_to_add { + let prev = self.packages[pkg] + .interfaces + .insert(name, remap.interfaces[iface.index()]); + assert!(prev.is_none()); + } + for (name, pkg, world) in worlds_to_add { + let prev = self.packages[pkg] + .worlds + .insert(name, remap.worlds[world.index()]); + assert!(prev.is_none()); + } + + log::trace!("now have {} packages", self.packages.len()); + Ok(remap) + } + + /// Merges the world `from` into the world `into`. + /// + /// This will attempt to merge one world into another, unioning all of its + /// imports and exports together. This is an operation performed by + /// `wit-component`, for example where two different worlds from two + /// different libraries were linked into the same core wasm file and are + /// producing a singular world that will be the final component's + /// interface. + /// + /// This operation can fail if the imports/exports overlap. + pub fn merge_worlds(&mut self, from: WorldId, into: WorldId) -> Result<()> { + let mut new_imports = Vec::new(); + let mut new_exports = Vec::new(); + + let from_world = &self.worlds[from]; + let into_world = &self.worlds[into]; + + // Build a map of the imports/exports in `into` going the reverse + // direction from what's listed. This is then consulted below to ensure + // that the same item isn't exported or imported under two different + // names which isn't allowed in the component model. + let mut into_imports_by_id = HashMap::new(); + let mut into_exports_by_id = HashMap::new(); + for (name, import) in into_world.imports.iter() { + if let WorldItem::Interface(id) = *import { + let prev = into_imports_by_id.insert(id, name); + assert!(prev.is_none()); + } + } + for (name, export) in into_world.exports.iter() { + if let WorldItem::Interface(id) = *export { + let prev = into_exports_by_id.insert(id, name); + assert!(prev.is_none()); + } + } + for (name, import) in from_world.imports.iter() { + // If the "from" world imports an interface which is already + // imported by the "into" world then this is allowed if the names + // are the same. Importing the same interface under different names + // isn't allowed, but otherwise merging imports of + // same-named-interfaces is allowed to merge them together. + if let WorldItem::Interface(id) = import { + if let Some(prev) = into_imports_by_id.get(id) { + if *prev != name { + let name = self.name_world_key(name); + let prev = self.name_world_key(prev); + bail!("import `{name}` conflicts with previous name of `{prev}`"); + } + } + } + } + for (name, export) in from_world.exports.iter() { + // Note that unlike imports same-named exports are not handled here + // since if something is exported twice there's no way to "unify" it + // so it's left as an error. + if let WorldItem::Interface(id) = export { + if let Some(prev) = into_exports_by_id.get(id) { + let name = self.name_world_key(name); + let prev = self.name_world_key(prev); + bail!("export `{name}` conflicts with previous name of `{prev}`"); + } + } + } + + // Next walk over the interfaces imported into `from_world` and queue up + // imports to get inserted into `into_world`. + for (name, from_import) in from_world.imports.iter() { + match into_world.imports.get(name) { + Some(into_import) => match (from_import, into_import) { + // If these imports, which have the same name, are of the + // same interface then union them together at this point. + (WorldItem::Interface(from), WorldItem::Interface(into)) if from == into => { + continue + } + _ => { + let name = self.name_world_key(name); + bail!("duplicate import found for interface `{name}`"); + } + }, + None => new_imports.push((name.clone(), from_import.clone())), + } + } + + // All exports at this time must be unique. For example the same + // interface exported from two locations can't really be resolved to one + // canonical definition, so make sure that merging worlds only succeeds + // if the worlds have disjoint sets of exports. + for (name, export) in from_world.exports.iter() { + match into_world.exports.get(name) { + Some(_) => { + let name = self.name_world_key(name); + bail!("duplicate export found for interface `{name}`"); + } + None => new_exports.push((name.clone(), export.clone())), + } + } + + // Insert any new imports and new exports found first. + let into = &mut self.worlds[into]; + for (name, import) in new_imports { + let prev = into.imports.insert(name, import); + assert!(prev.is_none()); + } + for (name, export) in new_exports { + let prev = into.exports.insert(name, export); + assert!(prev.is_none()); + } + + Ok(()) + } + + /// Returns the ID of the specified `interface`. + /// + /// Returns `None` for unnamed interfaces. + pub fn id_of(&self, interface: InterfaceId) -> Option { + let interface = &self.interfaces[interface]; + let package = &self.packages[interface.package.unwrap()]; + let mut base = String::new(); + base.push_str(&package.name.namespace); + base.push_str(":"); + base.push_str(&package.name.name); + base.push_str("/"); + base.push_str(interface.name.as_ref()?); + if let Some(version) = &package.name.version { + base.push_str(&format!("@{version}")); + } + Some(base) + } + + /// Attempts to locate a world given the "default" package `pkg` and the + /// optional string specifier `world`. + /// + /// This method is intended to be used by bindings generation tools to + /// select a world from either `pkg` or a package in this `Resolve`. + /// + /// If `world` is `None` then `pkg` must have precisely one world which will + /// be returned. + /// + /// If `world` is `Some` then it can either be: + /// + /// * A kebab-name of a world contained within `pkg` which is being + /// selected, such as `"the-world"`. + /// + /// * An ID-based form of a world which is selected within this `Resolve`, + /// ignoring `pkg`. For example `"wasi:http/proxy"`. + /// + /// If successful the corresponding `WorldId` is returned, otherwise an + /// error is returned. + pub fn select_world(&self, pkg: PackageId, world: Option<&str>) -> Result { + let world = match world { + Some(world) => world, + None => { + let pkg = &self.packages[pkg]; + match pkg.worlds.len() { + 0 => bail!("no worlds found in package `{}`", pkg.name), + 1 => return Ok(*pkg.worlds.values().next().unwrap()), + _ => bail!( + "multiple worlds found in package `{}`: one must be explicitly chosen", + pkg.name + ), + } + } + }; + + let path = parse_use_path(world) + .with_context(|| format!("failed to parse world specifier `{world}`"))?; + let (pkg, world) = match path { + AstUsePath::Name(name) => (pkg, name), + AstUsePath::Package(pkg, interface) => ( + *self + .package_names + .get(&pkg) + .ok_or_else(|| anyhow!("unknown package `{pkg}`"))?, + interface, + ), + }; + let pkg = &self.packages[pkg]; + pkg.worlds + .get(&world) + .copied() + .ok_or_else(|| anyhow!("no world named `{world}` in package")) + } + + /// Assigns a human readable name to the `WorldKey` specified. + pub fn name_world_key(&self, key: &WorldKey) -> String { + match key { + WorldKey::Name(s) => s.to_string(), + WorldKey::Interface(i) => self.id_of(*i).expect("unexpected anonymous interface"), + } + } + + /// Returns an iterator of all interfaces that the interface `id` depends + /// on. + /// + /// Interfaces may depend on others for type information to resolve type + /// imports. + /// + /// Note that the returned iterate may yield the same interface as a + /// dependency multiple times. Additionally only direct dependencies of `id` + /// are yielded, not transitive dependencies. + pub fn interface_direct_deps(&self, id: InterfaceId) -> impl Iterator + '_ { + self.interfaces[id] + .types + .iter() + .filter_map(move |(_name, ty)| { + // Find `other` which `ty` is defined within to determine which + // interfaces this interface depends on. + let dep = match self.types[*ty].kind { + TypeDefKind::Type(Type::Id(id)) => id, + _ => return None, + }; + let other = match self.types[dep].owner { + TypeOwner::Interface(id) => id, + _ => return None, + }; + if other == id { + None + } else { + Some(other) + } + }) + } +} + +/// Structure returned by [`Resolve::merge`] which contains mappings from +/// old-ids to new-ids after the merge. +#[derive(Default)] +pub struct Remap { + pub types: Vec, + pub interfaces: Vec, + pub worlds: Vec, + pub packages: Vec, + + /// A cache of anonymous `own` handles for resource types. + /// + /// The appending operation of `Remap` is the one responsible for + /// translating references to `T` where `T` is a resource into `own` + /// instead. This map is used to deduplicate the `own` types generated + /// to generate as few as possible. + /// + /// The key of this map is the resource id `T` in the new resolve, and + /// the value is the `own` type pointing to `T`. + own_handles: HashMap, +} + +impl Remap { + fn append( + &mut self, + resolve: &mut Resolve, + unresolved: UnresolvedPackage, + ) -> Result { + self.process_foreign_deps(resolve, &unresolved)?; + + let foreign_types = self.types.len(); + let foreign_interfaces = self.interfaces.len(); + let foreign_worlds = self.worlds.len(); + + // Copy over all types first, updating any intra-type references. Note + // that types are sorted topologically which means this iteration + // order should be sufficient. Also note though that the interface + // owner of a type isn't updated here due to interfaces not being known + // yet. + for (id, mut ty) in unresolved.types.into_iter().skip(foreign_types) { + self.update_typedef(resolve, &mut ty); + let new_id = resolve.types.alloc(ty); + assert_eq!(self.types.len(), id.index()); + + let new_id = match resolve.types[new_id] { + // If this is an `own` handle then either replace it with a + // preexisting `own` handle which may have been generated in + // `update_ty`. If that doesn't exist though then insert it into + // the `own_handles` cache. + TypeDef { + name: None, + owner: TypeOwner::None, + kind: TypeDefKind::Handle(Handle::Own(id)), + docs: _, + } => *self.own_handles.entry(id).or_insert(new_id), + + // Everything not-related to `own` doesn't get its ID + // modified. + _ => new_id, + }; + self.types.push(new_id); + } + + // Next transfer all interfaces into `Resolve`, updating type ids + // referenced along the way. + for (id, mut iface) in unresolved.interfaces.into_iter().skip(foreign_interfaces) { + self.update_interface(resolve, &mut iface); + let new_id = resolve.interfaces.alloc(iface); + assert_eq!(self.interfaces.len(), id.index()); + self.interfaces.push(new_id); + } + + // Now that interfaces are identified go back through the types and + // update their interface owners. + for id in self.types.iter().skip(foreign_types) { + match &mut resolve.types[*id].owner { + TypeOwner::Interface(id) => *id = self.interfaces[id.index()], + TypeOwner::World(_) | TypeOwner::None => {} + } + } + + // Perform a weighty step of full resolution of worlds. This will fully + // expand imports/exports for a world and create the topological + // ordering necessary for this. + // + // This is done after types/interfaces are fully settled so the + // transitive relation between interfaces, through types, is understood + // here. + assert_eq!(unresolved.worlds.len(), unresolved.world_item_spans.len()); + let include_world_spans = unresolved.include_world_spans; + for ((id, mut world), (import_spans, export_spans)) in unresolved + .worlds + .into_iter() + .zip(unresolved.world_item_spans) + .skip(foreign_worlds) + { + self.update_world( + &mut world, + resolve, + &import_spans, + &export_spans, + &include_world_spans, + )?; + + let new_id = resolve.worlds.alloc(world); + assert_eq!(self.worlds.len(), id.index()); + self.worlds.push(new_id); + } + + // As with interfaces, now update the ids of world-owned types. + for id in self.types.iter().skip(foreign_types) { + match &mut resolve.types[*id].owner { + TypeOwner::World(id) => *id = self.worlds[id.index()], + TypeOwner::Interface(_) | TypeOwner::None => {} + } + } + + // Fixup "parent" ids now that everything has been identified + let pkgid = resolve.packages.alloc(Package { + name: unresolved.name.clone(), + docs: unresolved.docs.clone(), + interfaces: Default::default(), + worlds: Default::default(), + }); + let prev = resolve.package_names.insert(unresolved.name.clone(), pkgid); + assert!(prev.is_none()); + for id in self.interfaces.iter().skip(foreign_interfaces) { + let iface = &mut resolve.interfaces[*id]; + iface.package = Some(pkgid); + if let Some(name) = &iface.name { + let prev = resolve.packages[pkgid].interfaces.insert(name.clone(), *id); + assert!(prev.is_none()); + } + } + for id in self.worlds.iter().skip(foreign_worlds) { + let world = &mut resolve.worlds[*id]; + world.package = Some(pkgid); + let prev = resolve.packages[pkgid] + .worlds + .insert(world.name.clone(), *id); + assert!(prev.is_none()); + } + Ok(pkgid) + } + + fn process_foreign_deps( + &mut self, + resolve: &mut Resolve, + unresolved: &UnresolvedPackage, + ) -> Result<()> { + // Invert the `foreign_deps` map to be keyed by world id to get + // used in the loops below. + let mut world_to_package = HashMap::new(); + let mut interface_to_package = HashMap::new(); + for (i, (pkg_name, worlds_or_ifaces)) in unresolved.foreign_deps.iter().enumerate() { + for (name, item) in worlds_or_ifaces { + match item { + AstItem::Interface(unresolved_interface_id) => { + let prev = interface_to_package.insert( + *unresolved_interface_id, + (pkg_name, name, unresolved.foreign_dep_spans[i]), + ); + assert!(prev.is_none()); + } + AstItem::World(unresolved_world_id) => { + let prev = world_to_package.insert( + *unresolved_world_id, + (pkg_name, name, unresolved.foreign_dep_spans[i]), + ); + assert!(prev.is_none()); + } + } + } + } + + // Connect all interfaces referred to in `interface_to_package`, which + // are at the front of `unresolved.interfaces`, to interfaces already + // contained within `resolve`. + self.process_foreign_interfaces(unresolved, &interface_to_package, resolve)?; + + // Connect all worlds referred to in `world_to_package`, which + // are at the front of `unresolved.worlds`, to worlds already + // contained within `resolve`. + self.process_foreign_worlds(unresolved, &world_to_package, resolve)?; + + // Finally, iterate over all foreign-defined types and determine + // what they map to. + self.process_foreign_types(unresolved, resolve)?; + + for (id, span) in unresolved.required_resource_types.iter() { + let mut id = self.types[id.index()]; + loop { + match resolve.types[id].kind { + TypeDefKind::Type(Type::Id(i)) => id = i, + TypeDefKind::Resource => break, + _ => bail!(Error { + span: *span, + msg: format!("type used in a handle must be a resource"), + }), + } + } + } + + Ok(()) + } + + fn process_foreign_interfaces( + &mut self, + unresolved: &UnresolvedPackage, + interface_to_package: &HashMap, + resolve: &mut Resolve, + ) -> Result<(), anyhow::Error> { + for (unresolved_iface_id, unresolved_iface) in unresolved.interfaces.iter() { + let (pkg_name, interface, span) = match interface_to_package.get(&unresolved_iface_id) { + Some(items) => *items, + // All foreign interfaces are defined first, so the first one + // which is defined in a non-foreign document means that all + // further interfaces will be non-foreign as well. + None => break, + }; + let pkgid = resolve + .package_names + .get(pkg_name) + .copied() + .ok_or_else(|| Error { + span, + msg: format!("package not found"), + })?; + + // Functions can't be imported so this should be empty. + assert!(unresolved_iface.functions.is_empty()); + + let pkg = &resolve.packages[pkgid]; + let span = unresolved.interface_spans[unresolved_iface_id.index()]; + let iface_id = pkg + .interfaces + .get(interface) + .copied() + .ok_or_else(|| Error { + span, + msg: format!("interface not found in package"), + })?; + assert_eq!(self.interfaces.len(), unresolved_iface_id.index()); + self.interfaces.push(iface_id); + } + for (id, _) in unresolved.interfaces.iter().skip(self.interfaces.len()) { + assert!( + interface_to_package.get(&id).is_none(), + "found foreign interface after local interface" + ); + } + Ok(()) + } + + fn process_foreign_worlds( + &mut self, + unresolved: &UnresolvedPackage, + world_to_package: &HashMap, + resolve: &mut Resolve, + ) -> Result<(), anyhow::Error> { + for (unresolved_world_id, _) in unresolved.worlds.iter() { + let (pkg_name, world, span) = match world_to_package.get(&unresolved_world_id) { + Some(items) => *items, + // Same as above, all worlds are foreign until we find a + // non-foreign one. + None => break, + }; + + let pkgid = resolve + .package_names + .get(pkg_name) + .copied() + .ok_or_else(|| Error { + span, + msg: format!("package not found"), + })?; + let pkg = &resolve.packages[pkgid]; + let span = unresolved.world_spans[unresolved_world_id.index()]; + let world_id = pkg.worlds.get(world).copied().ok_or_else(|| Error { + span, + msg: format!("world not found in package"), + })?; + assert_eq!(self.worlds.len(), unresolved_world_id.index()); + self.worlds.push(world_id); + } + for (id, _) in unresolved.worlds.iter().skip(self.worlds.len()) { + assert!( + world_to_package.get(&id).is_none(), + "found foreign world after local world" + ); + } + Ok(()) + } + + fn process_foreign_types( + &mut self, + unresolved: &UnresolvedPackage, + resolve: &mut Resolve, + ) -> Result<(), anyhow::Error> { + for (unresolved_type_id, unresolved_ty) in unresolved.types.iter() { + // All "Unknown" types should appear first so once we're no longer + // in unknown territory it's package-defined types so break out of + // this loop. + match unresolved_ty.kind { + TypeDefKind::Unknown => {} + _ => break, + } + let unresolved_iface_id = match unresolved_ty.owner { + TypeOwner::Interface(id) => id, + _ => unreachable!(), + }; + let iface_id = self.interfaces[unresolved_iface_id.index()]; + let name = unresolved_ty.name.as_ref().unwrap(); + let span = unresolved.unknown_type_spans[unresolved_type_id.index()]; + let type_id = *resolve.interfaces[iface_id] + .types + .get(name) + .ok_or_else(|| Error { + span, + msg: format!("type `{name}` not defined in interface"), + })?; + assert_eq!(self.types.len(), unresolved_type_id.index()); + self.types.push(type_id); + } + for (_, ty) in unresolved.types.iter().skip(self.types.len()) { + if let TypeDefKind::Unknown = ty.kind { + panic!("unknown type after defined type"); + } + } + Ok(()) + } + + fn update_typedef(&mut self, resolve: &mut Resolve, ty: &mut TypeDef) { + // NB: note that `ty.owner` is not updated here since interfaces + // haven't been mapped yet and that's done in a separate step. + use crate::TypeDefKind::*; + match &mut ty.kind { + Handle(handle) => match handle { + crate::Handle::Own(ty) | crate::Handle::Borrow(ty) => self.update_type_id(ty), + }, + Resource => {} + Record(r) => { + for field in r.fields.iter_mut() { + self.update_ty(resolve, &mut field.ty); + } + } + Tuple(t) => { + for ty in t.types.iter_mut() { + self.update_ty(resolve, ty); + } + } + Variant(v) => { + for case in v.cases.iter_mut() { + if let Some(t) = &mut case.ty { + self.update_ty(resolve, t); + } + } + } + Option(t) => self.update_ty(resolve, t), + Result(r) => { + if let Some(ty) = &mut r.ok { + self.update_ty(resolve, ty); + } + if let Some(ty) = &mut r.err { + self.update_ty(resolve, ty); + } + } + List(t) => self.update_ty(resolve, t), + Future(Some(t)) => self.update_ty(resolve, t), + Stream(t) => { + if let Some(ty) = &mut t.element { + self.update_ty(resolve, ty); + } + if let Some(ty) = &mut t.end { + self.update_ty(resolve, ty); + } + } + + // Note that `update_ty` is specifically not used here as typedefs + // because for the `type a = b` form that doesn't force `a` to be a + // handle type if `b` is a resource type, instead `a` is + // simultaneously usable as a resource and a handle type + Type(crate::Type::Id(id)) => self.update_type_id(id), + Type(_) => {} + + // nothing to do for these as they're just names or empty + Flags(_) | Enum(_) | Future(None) => {} + + Unknown => unreachable!(), + } + } + + fn update_ty(&mut self, resolve: &mut Resolve, ty: &mut Type) { + let id = match ty { + Type::Id(id) => id, + _ => return, + }; + self.update_type_id(id); + + // If `id` points to a `Resource` type then this means that what was + // just discovered was a reference to what will implicitly become an + // `own` handle. This `own` handle is implicitly allocated here + // and handled during the merging process. + let mut cur = *id; + let points_to_resource = loop { + match resolve.types[cur].kind { + TypeDefKind::Type(Type::Id(id)) => cur = id, + TypeDefKind::Resource => break true, + _ => break false, + } + }; + + if points_to_resource { + *id = *self.own_handles.entry(*id).or_insert_with(|| { + resolve.types.alloc(TypeDef { + name: None, + owner: TypeOwner::None, + kind: TypeDefKind::Handle(Handle::Own(*id)), + docs: Default::default(), + }) + }); + } + } + + fn update_type_id(&self, id: &mut TypeId) { + *id = self.types[id.index()]; + } + + fn update_interface(&mut self, resolve: &mut Resolve, iface: &mut Interface) { + // NB: note that `iface.doc` is not updated here since interfaces + // haven't been mapped yet and that's done in a separate step. + for (_name, ty) in iface.types.iter_mut() { + self.update_type_id(ty); + } + for (_, func) in iface.functions.iter_mut() { + self.update_function(resolve, func); + } + } + + fn update_function(&mut self, resolve: &mut Resolve, func: &mut Function) { + match &mut func.kind { + FunctionKind::Freestanding => {} + FunctionKind::Method(id) | FunctionKind::Constructor(id) | FunctionKind::Static(id) => { + self.update_type_id(id); + } + } + for (_, ty) in func.params.iter_mut() { + self.update_ty(resolve, ty); + } + match &mut func.results { + Results::Named(named) => { + for (_, ty) in named.iter_mut() { + self.update_ty(resolve, ty); + } + } + Results::Anon(ty) => self.update_ty(resolve, ty), + } + } + + fn update_world( + &mut self, + world: &mut World, + resolve: &mut Resolve, + import_spans: &[Span], + export_spans: &[Span], + include_world_spans: &[Span], + ) -> Result<()> { + // NB: this function is more more complicated than the prior versions + // of merging an item because this is the location that elaboration of + // imports/exports of a world are fully resolved. With full transitive + // knowledge of all interfaces a worlds imports, for example, are + // expanded fully to ensure that all transitive items are necessarily + // imported. + assert_eq!(world.imports.len(), import_spans.len()); + assert_eq!(world.exports.len(), export_spans.len()); + + // First up, process all the `imports` of the world. Note that this + // starts by gutting the list of imports stored in `world` to get + // rebuilt iteratively below. + // + // Here each import of an interface is recorded and then additionally + // explicitly named imports of interfaces are recorded as well for + // determining names later on. + let mut import_funcs = Vec::new(); + let mut import_types = Vec::new(); + for ((mut name, item), span) in mem::take(&mut world.imports).into_iter().zip(import_spans) + { + self.update_world_key(&mut name); + match item { + WorldItem::Interface(id) => { + let id = self.interfaces[id.index()]; + self.add_world_import(resolve, world, name, id); + } + WorldItem::Function(mut f) => { + self.update_function(resolve, &mut f); + import_funcs.push((name.unwrap_name(), f, *span)); + } + WorldItem::Type(id) => { + let id = self.types[id.index()]; + import_types.push((name.unwrap_name(), id, *span)); + } + } + } + + for (_name, id, _span) in import_types.iter() { + if let TypeDefKind::Type(Type::Id(other)) = resolve.types[*id].kind { + if let TypeOwner::Interface(owner) = resolve.types[other].owner { + let name = WorldKey::Interface(owner); + self.add_world_import(resolve, world, name, owner); + } + } + } + + let mut export_funcs = Vec::new(); + let mut export_interfaces = IndexMap::new(); + for ((mut name, item), span) in mem::take(&mut world.exports).into_iter().zip(export_spans) + { + self.update_world_key(&mut name); + match item { + WorldItem::Interface(id) => { + let id = self.interfaces[id.index()]; + let prev = export_interfaces.insert(id, (name, *span)); + assert!(prev.is_none()); + } + WorldItem::Function(mut f) => { + self.update_function(resolve, &mut f); + let name = match name { + WorldKey::Name(name) => name, + WorldKey::Interface(_) => unreachable!(), + }; + export_funcs.push((name, f, *span)); + } + WorldItem::Type(_) => unreachable!(), + } + } + + self.add_world_exports(resolve, world, &export_interfaces)?; + + // Resolve all includes of the world + let includes = mem::take(&mut world.includes); + let include_names = mem::take(&mut world.include_names); + for (index, include_world) in includes.into_iter().enumerate() { + let span = include_world_spans[index]; + let names = &include_names[index]; + self.resolve_include(world, include_world, names, span, resolve)?; + } + + for (name, id, span) in import_types { + let prev = world + .imports + .insert(WorldKey::Name(name.clone()), WorldItem::Type(id)); + if prev.is_some() { + bail!(Error { + msg: format!("export of type `{name}` shadows previously imported interface"), + span, + }) + } + + // check if this type has name conflict with any of the exported item. + if world.exports.contains_key(&WorldKey::Name(name.clone())) { + bail!(Error { + msg: format!("import type `{name}` conflicts with prior export of interface",), + span, + }) + } + } + + for (name, func, span) in import_funcs { + let prev = world + .imports + .insert(WorldKey::Name(name.clone()), WorldItem::Function(func)); + if prev.is_some() { + bail!(Error { + msg: format!( + "import of function `{name}` shadows previously imported interface" + ), + span, + }) + } + + // check if this function has name conflict with any of the exported item. + if world.exports.contains_key(&WorldKey::Name(name.clone())) { + bail!(Error { + msg: format!( + "import of function `{name}` conflicts with prior export of interface", + ), + span, + }) + } + } + + for (name, func, span) in export_funcs { + let prev = world + .exports + .insert(WorldKey::Name(name.clone()), WorldItem::Function(func)); + if prev.is_some() || world.imports.contains_key(&WorldKey::Name(name.clone())) { + bail!(Error { + msg: format!( + "export of function `{name}` shadows previously exported interface" + ), + span, + }) + } + + // check if this function has name conflict with any of the import item. + if world.imports.contains_key(&WorldKey::Name(name.clone())) { + bail!(Error { + msg: format!( + "export of function `{name}` conflicts with prior import of interface", + ), + span, + }) + } + } + + // After all that sort functions in exports to come before interfaces in + // exports. This is not strictly required for correctness but make + // iterating over a world much easier for consumers. Exported functions + // are guaranteed to use types from either imported interfaces or + // imported types into the world itself. Currently there is no means by + // which an export function, at the root, can use types from any other + // exported interfaces (can't be modeled syntactically in WIT). This + // means that by placing all functions first it guarantees that visitors + // which visit imports first then exports will walk over types and + // references in the order of what they're actually using. + // + // For example if an interface is both imported and exported and an + // exported function uses a type from that interface, then a visitor + // should visit the imported interface, then the exported function, then + // the exported interface. That way tables about "where was this type + // defined" will be correct as the last-inserted item will be used and + // correctly account for this. + world.exports.sort_by(|_, a, _, b| { + let rank = |item: &WorldItem| match item { + WorldItem::Type(_) => unreachable!(), + WorldItem::Function(_) => 0, + WorldItem::Interface(_) => 1, + }; + rank(a).cmp(&rank(b)) + }); + + log::trace!("imports = {:?}", world.imports); + log::trace!("exports = {:?}", world.exports); + + Ok(()) + } + + fn update_world_key(&self, key: &mut WorldKey) { + match key { + WorldKey::Name(_) => {} + WorldKey::Interface(id) => { + *id = self.interfaces[id.index()]; + } + } + } + + fn add_world_import( + &self, + resolve: &Resolve, + world: &mut World, + key: WorldKey, + id: InterfaceId, + ) { + if world.imports.contains_key(&key) { + return; + } + for dep in resolve.interface_direct_deps(id) { + self.add_world_import(resolve, world, WorldKey::Interface(dep), dep); + } + let prev = world.imports.insert(key, WorldItem::Interface(id)); + assert!(prev.is_none()); + } + + /// This function adds all of the interfaces in `export_interfaces` to the + /// list of exports of the `world` specified. + /// + /// This method is more involved than adding imports because it is fallible. + /// Chiefly what can happen is that the dependencies of all exports must be + /// satisfied by other exports or imports, but not both. For example given a + /// situation such as: + /// + /// ```wit + /// interface a { + /// type t = u32 + /// } + /// interface b { + /// use a.{t} + /// } + /// interface c { + /// use a.{t} + /// use b.{t as t2} + /// } + /// ``` + /// + /// where `c` depends on `b` and `a` where `b` depends on `a`, then the + /// purpose of this method is to reject this world: + /// + /// ```wit + /// world foo { + /// export a + /// export c + /// } + /// ``` + /// + /// The reasoning here is unfortunately subtle and is additionally the + /// subject of WebAssembly/component-model#208. Effectively the `c` + /// interface depends on `b`, but it's not listed explicitly as an import, + /// so it's then implicitly added as an import. This then transitively + /// depends on `a` so it's also added as an import. At this point though `c` + /// also depends on `a`, and it's also exported, so naively it should depend + /// on the export and not implicitly add an import. This means though that + /// `c` has access to two copies of `a`, one imported and one exported. This + /// is not valid, especially in the face of resource types. + /// + /// Overall this method is tasked with rejecting the above world by walking + /// over all the exports and adding their dependencies. Each dependency is + /// recorded with whether it's required to be imported, and then if an + /// export is added for something that's required to be an error then the + /// operation fails. + fn add_world_exports( + &self, + resolve: &Resolve, + world: &mut World, + export_interfaces: &IndexMap, + ) -> Result<()> { + let mut required_imports = HashSet::new(); + for (id, (key, span)) in export_interfaces.iter() { + let ok = add_world_export( + resolve, + world, + export_interfaces, + &mut required_imports, + *id, + key, + true, + ); + if !ok { + bail!(Error { + // FIXME: this is not a great error message and basically no + // one will know what to do when it gets printed. Improving + // this error message, however, is a chunk of work that may + // not be best spent doing this at this time, so I'm writing + // this comment instead. + // + // More-or-less what should happen here is that a "path" + // from this interface to the conflicting interface should + // be printed. It should be explained why an import is being + // injected, why that's conflicting with an export, and + // ideally with a suggestion of "add this interface to the + // export list to fix this error". + // + // That's a lot of info that's not easy to get at without + // more refactoring, so it's left to a future date in the + // hopes that most folks won't actually run into this for + // the time being. + msg: format!( + "interface transitively depends on an interface in \ + incompatible ways", + ), + span: *span, + }); + } + } + return Ok(()); + + fn add_world_export( + resolve: &Resolve, + world: &mut World, + export_interfaces: &IndexMap, + required_imports: &mut HashSet, + id: InterfaceId, + key: &WorldKey, + add_export: bool, + ) -> bool { + if world.exports.contains_key(key) { + if add_export { + return true; + } else { + return false; + } + } + // If this is an import and it's already in the `required_imports` + // set then we can skip it as we've already visited this interface. + if !add_export && required_imports.contains(&id) { + return true; + } + let ok = resolve.interface_direct_deps(id).all(|dep| { + let key = WorldKey::Interface(dep); + let add_export = add_export && export_interfaces.contains_key(&dep); + add_world_export( + resolve, + world, + export_interfaces, + required_imports, + dep, + &key, + add_export, + ) + }); + if !ok { + return false; + } + if add_export { + if required_imports.contains(&id) { + return false; + } + world.exports.insert(key.clone(), WorldItem::Interface(id)); + } else { + required_imports.insert(id); + world.imports.insert(key.clone(), WorldItem::Interface(id)); + } + true + } + } + + fn resolve_include( + &self, + world: &mut World, + include_world: WorldId, + names: &[IncludeName], + span: Span, + resolve: &Resolve, + ) -> Result<()> { + let include_world_id = self.worlds[include_world.index()]; + let include_world = &resolve.worlds[include_world_id]; + let mut names_ = names.to_owned(); + + // remove all imports and exports that match the names we're including + for import in include_world.imports.iter() { + self.remove_matching_name(import, &mut names_); + } + for export in include_world.exports.iter() { + self.remove_matching_name(export, &mut names_); + } + if !names_.is_empty() { + bail!(Error { + msg: format!("no import or export kebab-name `{}`. Note that an ID does not support renaming", names_[0].name), + span: span, + }); + } + + // copy the imports and exports from the included world into the current world + for import in include_world.imports.iter() { + self.resolve_include_item(names, &mut world.imports, import, span, "import")?; + } + + for export in include_world.exports.iter() { + self.resolve_include_item(names, &mut world.exports, export, span, "export")?; + } + Ok(()) + } + + fn resolve_include_item( + &self, + names: &[IncludeName], + items: &mut IndexMap, + item: (&WorldKey, &WorldItem), + span: Span, + item_type: &str, + ) -> Result<()> { + match item.0 { + WorldKey::Name(n) => { + let n = if let Some(found) = names + .into_iter() + .find(|include_name| include_name.name == n.clone()) + { + found.as_.clone() + } else { + n.clone() + }; + + let prev = items.insert(WorldKey::Name(n.clone()), item.1.clone()); + if prev.is_some() { + bail!(Error { + msg: format!("{item_type} of `{n}` shadows previously {item_type}ed items"), + span, + }) + } + } + key => { + let prev = items.insert(key.clone(), item.1.clone()); + if let Some(prev) = prev { + assert_eq!(prev, item.1.clone()); + } + } + }; + Ok(()) + } + + fn remove_matching_name(&self, item: (&WorldKey, &WorldItem), names: &mut Vec) { + match item.0 { + WorldKey::Name(n) => { + names.retain(|name| name.name != n.clone()); + } + _ => {} + } + } +} + +struct MergeMap<'a> { + /// A map of package ids in `from` to those in `into` for those that are + /// found to be equivalent. + package_map: HashMap, + + /// A map of interface ids in `from` to those in `into` for those that are + /// found to be equivalent. + interface_map: HashMap, + + /// A map of type ids in `from` to those in `into` for those that are + /// found to be equivalent. + type_map: HashMap, + + /// A map of world ids in `from` to those in `into` for those that are + /// found to be equivalent. + world_map: HashMap, + + /// A list of documents that need to be added to packages in `into`. + /// + /// The elements here are: + /// + /// * The name of the interface/world + /// * The ID within `into` of the package being added to + /// * The ID within `from` of the item being added. + interfaces_to_add: Vec<(String, PackageId, InterfaceId)>, + worlds_to_add: Vec<(String, PackageId, WorldId)>, + + /// Which `Resolve` is being merged from. + from: &'a Resolve, + + /// Which `Resolve` is being merged into. + into: &'a Resolve, +} + +impl<'a> MergeMap<'a> { + fn new(from: &'a Resolve, into: &'a Resolve) -> Result> { + Ok(MergeMap { + package_map: Default::default(), + interface_map: Default::default(), + type_map: Default::default(), + world_map: Default::default(), + interfaces_to_add: Default::default(), + worlds_to_add: Default::default(), + from, + into, + }) + } + + fn build(&mut self) -> Result<()> { + for (from_id, from) in self.from.packages.iter() { + let into_id = match self.into.package_names.get(&from.name) { + Some(id) => *id, + + // This package, according to its name and url, is not present + // in `self` so it needs to get added below. + None => { + log::trace!("adding unique package {}", from.name); + continue; + } + }; + log::trace!("merging duplicate package {}", from.name); + + self.build_package(from_id, into_id).with_context(|| { + format!("failed to merge package `{}` into existing copy", from.name) + })?; + } + + Ok(()) + } + + fn build_package(&mut self, from_id: PackageId, into_id: PackageId) -> Result<()> { + let prev = self.package_map.insert(from_id, into_id); + assert!(prev.is_none()); + + let from = &self.from.packages[from_id]; + let into = &self.into.packages[into_id]; + + // If an interface is present in `from_id` but not present in `into_id` + // then it can be copied over wholesale. That copy is scheduled to + // happen within the `self.interfaces_to_add` list. + for (name, from_interface_id) in from.interfaces.iter() { + let into_interface_id = match into.interfaces.get(name) { + Some(id) => *id, + None => { + self.interfaces_to_add + .push((name.clone(), into_id, *from_interface_id)); + continue; + } + }; + + self.build_interface(*from_interface_id, into_interface_id) + .with_context(|| format!("failed to merge interface `{name}`"))?; + } + + for (name, from_world_id) in from.worlds.iter() { + let into_world_id = match into.worlds.get(name) { + Some(id) => *id, + None => { + self.worlds_to_add + .push((name.clone(), into_id, *from_world_id)); + continue; + } + }; + + self.build_world(*from_world_id, into_world_id) + .with_context(|| format!("failed to merge world `{name}`"))?; + } + + Ok(()) + } + + fn build_interface(&mut self, from_id: InterfaceId, into_id: InterfaceId) -> Result<()> { + let prev = self.interface_map.insert(from_id, into_id); + assert!(prev.is_none()); + + let from_interface = &self.from.interfaces[from_id]; + let into_interface = &self.into.interfaces[into_id]; + + // Unlike documents/interfaces above if an interface in `from` + // differs from the interface in `into` then that's considered an + // error. Changing interfaces can reflect changes in imports/exports + // which may not be expected so it's currently required that all + // interfaces, when merged, exactly match. + // + // One case to consider here, for example, is that if a world in + // `into` exports the interface `into_id` then if `from_id` were to + // add more items into `into` then it would unexpectedly require more + // items to be exported which may not work. In an import context this + // might work since it's "just more items available for import", but + // for now a conservative route of "interfaces must match" is taken. + + for (name, from_type_id) in from_interface.types.iter() { + let into_type_id = *into_interface + .types + .get(name) + .ok_or_else(|| anyhow!("expected type `{name}` to be present"))?; + let prev = self.type_map.insert(*from_type_id, into_type_id); + assert!(prev.is_none()); + + // FIXME: ideally the types should be "structurally + // equal" but that's not trivial to do in the face of + // resources. + } + + for (name, _) in from_interface.functions.iter() { + if !into_interface.functions.contains_key(name) { + bail!("expected function `{name}` to be present"); + } + + // FIXME: ideally the functions should be "structurally + // equal" but that's not trivial to do in the face of + // resources. + } + + Ok(()) + } + + fn build_world(&mut self, from_id: WorldId, into_id: WorldId) -> Result<()> { + let prev = self.world_map.insert(from_id, into_id); + assert!(prev.is_none()); + + let from_world = &self.from.worlds[from_id]; + let into_world = &self.into.worlds[into_id]; + + // Same as interfaces worlds are expected to exactly match to avoid + // unexpectedly changing a particular component's view of imports and + // exports. + // + // FIXME: this should probably share functionality with + // `Resolve::merge_worlds` to support adding imports but not changing + // exports. + + if from_world.imports.len() != into_world.imports.len() { + bail!("world contains different number of imports than expected"); + } + if from_world.exports.len() != into_world.exports.len() { + bail!("world contains different number of exports than expected"); + } + + for (from_name, from) in from_world.imports.iter() { + let into_name = self.map_name(from_name); + let name_str = self.from.name_world_key(from_name); + let into = into_world + .imports + .get(&into_name) + .ok_or_else(|| anyhow!("import `{name_str}` not found in target world"))?; + self.match_world_item(from, into) + .with_context(|| format!("import `{name_str}` didn't match target world"))?; + } + + for (from_name, from) in from_world.exports.iter() { + let into_name = self.map_name(from_name); + let name_str = self.from.name_world_key(from_name); + let into = into_world + .exports + .get(&into_name) + .ok_or_else(|| anyhow!("export `{name_str}` not found in target world"))?; + self.match_world_item(from, into) + .with_context(|| format!("export `{name_str}` didn't match target world"))?; + } + + Ok(()) + } + + fn map_name(&self, from_name: &WorldKey) -> WorldKey { + match from_name { + WorldKey::Name(s) => WorldKey::Name(s.clone()), + WorldKey::Interface(id) => { + WorldKey::Interface(self.interface_map.get(id).copied().unwrap_or(*id)) + } + } + } + + fn match_world_item(&mut self, from: &WorldItem, into: &WorldItem) -> Result<()> { + match (from, into) { + (WorldItem::Interface(from), WorldItem::Interface(into)) => { + match ( + &self.from.interfaces[*from].name, + &self.into.interfaces[*into].name, + ) { + // If one interface is unnamed then they must both be + // unnamed and they must both have the same structure for + // now. + (None, None) => self.build_interface(*from, *into)?, + + // Otherwise both interfaces must be named and they must + // have been previously found to be equivalent. Note that + // if either is unnamed it won't be present in + // `interface_map` so this'll return an error. + _ => { + if self.interface_map.get(&from) != Some(&into) { + bail!("interfaces are not the same"); + } + } + } + } + (WorldItem::Function(from), WorldItem::Function(into)) => { + let _ = (from, into); + // FIXME: should assert an check that `from` structurally + // matches `into` + } + (WorldItem::Type(from), WorldItem::Type(into)) => { + // FIXME: should assert an check that `from` structurally + // matches `into` + let prev = self.type_map.insert(*from, *into); + assert!(prev.is_none()); + } + + (WorldItem::Interface(_), _) + | (WorldItem::Function(_), _) + | (WorldItem::Type(_), _) => { + bail!("world items do not have the same type") + } + } + Ok(()) + } +} diff --git a/crates/wit-parser/src/serde_.rs b/crates/wit-parser/src/serde_.rs new file mode 100644 index 0000000000..f7af879947 --- /dev/null +++ b/crates/wit-parser/src/serde_.rs @@ -0,0 +1,108 @@ +use crate::{Params, Type}; +use id_arena::{Arena, Id}; +use indexmap::IndexMap; +use serde::ser::{SerializeMap, SerializeSeq, Serializer}; +use serde::Serialize; + +pub fn serialize_none(serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_none() +} + +pub fn serialize_arena(arena: &Arena, serializer: S) -> Result +where + T: Serialize, + S: Serializer, +{ + let mut seq = serializer.serialize_seq(Some(arena.len()))?; + for (_, item) in arena.iter() { + seq.serialize_element(&item)?; + } + seq.end() +} + +pub fn serialize_id(id: &Id, serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_u64(id.index() as u64) +} + +pub fn serialize_optional_id(id: &Option>, serializer: S) -> Result +where + S: Serializer, +{ + match id { + Some(id) => serialize_id(&id, serializer), + None => serializer.serialize_none(), + } +} + +pub fn serialize_id_map(map: &IndexMap>, serializer: S) -> Result +where + K: Serialize, + S: Serializer, +{ + let mut s = serializer.serialize_map(Some(map.len()))?; + for (key, id) in map.iter() { + s.serialize_entry(key, &(id.index() as u64))?; + } + s.end() +} + +impl Serialize for Type { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Type::Bool => serializer.serialize_str("bool"), + Type::U8 => serializer.serialize_str("u8"), + Type::U16 => serializer.serialize_str("u16"), + Type::U32 => serializer.serialize_str("u32"), + Type::U64 => serializer.serialize_str("u64"), + Type::S8 => serializer.serialize_str("s8"), + Type::S16 => serializer.serialize_str("s16"), + Type::S32 => serializer.serialize_str("s32"), + Type::S64 => serializer.serialize_str("s64"), + Type::Float32 => serializer.serialize_str("float32"), + Type::Float64 => serializer.serialize_str("float64"), + Type::Char => serializer.serialize_str("char"), + Type::String => serializer.serialize_str("string"), + Type::Id(type_id) => serializer.serialize_u64(type_id.index() as u64), + } + } +} + +pub fn serialize_anon_result(typ: &Type, serializer: S) -> Result +where + S: Serializer, +{ + let params: Params = vec![(String::default(), *typ)]; + serialize_params(¶ms, serializer) +} + +pub fn serialize_params(params: &Params, serializer: S) -> Result +where + S: Serializer, +{ + let mut seq = serializer.serialize_seq(Some(params.len()))?; + for (name, typ) in params.iter() { + let param = Param { + name: name.to_string(), + typ: *typ, + }; + seq.serialize_element(¶m)?; + } + seq.end() +} + +#[derive(Debug, Clone, PartialEq, serde_derive::Serialize)] +struct Param { + #[serde(skip_serializing_if = "String::is_empty")] + pub name: String, + #[serde(rename = "type")] + pub typ: Type, +} diff --git a/crates/wit-parser/src/sizealign.rs b/crates/wit-parser/src/sizealign.rs new file mode 100644 index 0000000000..ae1565973b --- /dev/null +++ b/crates/wit-parser/src/sizealign.rs @@ -0,0 +1,144 @@ +use crate::{FlagsRepr, Int, Resolve, Type, TypeDef, TypeDefKind}; + +#[derive(Default)] +pub struct SizeAlign { + map: Vec<(usize, usize)>, +} + +impl SizeAlign { + pub fn fill(&mut self, resolve: &Resolve) { + self.map = Vec::new(); + for (_, ty) in resolve.types.iter() { + let pair = self.calculate(ty); + self.map.push(pair); + } + } + + fn calculate(&self, ty: &TypeDef) -> (usize, usize) { + match &ty.kind { + TypeDefKind::Type(t) => (self.size(t), self.align(t)), + TypeDefKind::List(_) => (8, 4), + TypeDefKind::Record(r) => self.record(r.fields.iter().map(|f| &f.ty)), + TypeDefKind::Tuple(t) => self.record(t.types.iter()), + TypeDefKind::Flags(f) => match f.repr() { + FlagsRepr::U8 => (1, 1), + FlagsRepr::U16 => (2, 2), + FlagsRepr::U32(n) => (n * 4, 4), + }, + TypeDefKind::Variant(v) => self.variant(v.tag(), v.cases.iter().map(|c| c.ty.as_ref())), + TypeDefKind::Enum(e) => self.variant(e.tag(), []), + TypeDefKind::Option(t) => self.variant(Int::U8, [Some(t)]), + TypeDefKind::Result(r) => self.variant(Int::U8, [r.ok.as_ref(), r.err.as_ref()]), + // A resource is represented as an index. + TypeDefKind::Handle(_) => (4, 4), + // A future is represented as an index. + TypeDefKind::Future(_) => (4, 4), + // A stream is represented as an index. + TypeDefKind::Stream(_) => (4, 4), + // This shouldn't be used for anything since raw resources aren't part of the ABI -- just handles to + // them. + TypeDefKind::Resource => (usize::MAX, usize::MAX), + TypeDefKind::Unknown => unreachable!(), + } + } + + pub fn size(&self, ty: &Type) -> usize { + match ty { + Type::Bool | Type::U8 | Type::S8 => 1, + Type::U16 | Type::S16 => 2, + Type::U32 | Type::S32 | Type::Float32 | Type::Char => 4, + Type::U64 | Type::S64 | Type::Float64 | Type::String => 8, + Type::Id(id) => self.map[id.index()].0, + } + } + + pub fn align(&self, ty: &Type) -> usize { + match ty { + Type::Bool | Type::U8 | Type::S8 => 1, + Type::U16 | Type::S16 => 2, + Type::U32 | Type::S32 | Type::Float32 | Type::Char | Type::String => 4, + Type::U64 | Type::S64 | Type::Float64 => 8, + Type::Id(id) => self.map[id.index()].1, + } + } + + pub fn field_offsets<'a>( + &self, + types: impl IntoIterator, + ) -> Vec<(usize, &'a Type)> { + let mut cur = 0; + types + .into_iter() + .map(|ty| { + let ret = align_to(cur, self.align(ty)); + cur = ret + self.size(ty); + (ret, ty) + }) + .collect() + } + + pub fn payload_offset<'a>( + &self, + tag: Int, + cases: impl IntoIterator>, + ) -> usize { + let mut max_align = 1; + for ty in cases { + if let Some(ty) = ty { + max_align = max_align.max(self.align(ty)); + } + } + let tag_size = int_size_align(tag).0; + align_to(tag_size, max_align) + } + + pub fn record<'a>(&self, types: impl Iterator) -> (usize, usize) { + let mut size = 0; + let mut align = 1; + for ty in types { + let field_size = self.size(ty); + let field_align = self.align(ty); + size = align_to(size, field_align) + field_size; + align = align.max(field_align); + } + (align_to(size, align), align) + } + + pub fn params<'a>(&self, types: impl IntoIterator) -> (usize, usize) { + self.record(types.into_iter()) + } + + fn variant<'a>( + &self, + tag: Int, + types: impl IntoIterator>, + ) -> (usize, usize) { + let (discrim_size, discrim_align) = int_size_align(tag); + let mut case_size = 0; + let mut case_align = 1; + for ty in types { + if let Some(ty) = ty { + case_size = case_size.max(self.size(ty)); + case_align = case_align.max(self.align(ty)); + } + } + let align = discrim_align.max(case_align); + ( + align_to(align_to(discrim_size, case_align) + case_size, align), + align, + ) + } +} + +fn int_size_align(i: Int) -> (usize, usize) { + match i { + Int::U8 => (1, 1), + Int::U16 => (2, 2), + Int::U32 => (4, 4), + Int::U64 => (8, 8), + } +} + +pub(crate) fn align_to(val: usize, align: usize) -> usize { + (val + align - 1) & !(align - 1) +} diff --git a/crates/wit-parser/tests/all.rs b/crates/wit-parser/tests/all.rs new file mode 100644 index 0000000000..dfd294f6ac --- /dev/null +++ b/crates/wit-parser/tests/all.rs @@ -0,0 +1,195 @@ +//! You can run this test suite with: +//! +//! cargo test --test all +//! +//! An argument can be passed as well to filter, based on filename, which test +//! to run +//! +//! cargo test --test all foo.wit + +use anyhow::{bail, Context, Result}; +use pretty_assertions::StrComparison; +use rayon::prelude::*; +use std::env; +use std::ffi::OsStr; +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; +use std::str; +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +use wit_parser::*; + +fn main() { + env_logger::init(); + let tests = find_tests(); + let filter = std::env::args().nth(1); + + let tests = tests + .par_iter() + .filter_map(|test| { + if let Some(filter) = &filter { + if let Some(s) = test.to_str() { + if !s.contains(filter) { + return None; + } + } + } + Some(test) + }) + .collect::>(); + + println!("running {} test files\n", tests.len()); + + let ntests = AtomicUsize::new(0); + let errors = tests + .par_iter() + .filter_map(|test| { + Runner { ntests: &ntests } + .run(test) + .context(format!("test {:?} failed", test)) + .err() + }) + .collect::>(); + + if !errors.is_empty() { + for msg in errors.iter() { + eprintln!("{:?}", msg); + } + + panic!("{} tests failed", errors.len()) + } + + println!( + "test result: ok. {} directives passed\n", + ntests.load(SeqCst) + ); +} + +/// Recursively finds all tests in a whitelisted set of directories which we +/// then load up and test in parallel. +fn find_tests() -> Vec { + let mut tests = Vec::new(); + find_tests("tests/ui".as_ref(), &mut tests); + find_tests("tests/ui/parse-fail".as_ref(), &mut tests); + tests.sort(); + return tests; + + fn find_tests(path: &Path, tests: &mut Vec) { + for f in path.read_dir().unwrap() { + let f = f.unwrap(); + let path = f.path(); + if path.file_name().unwrap().to_str().unwrap() == "parse-fail" { + continue; + } + if f.file_type().unwrap().is_dir() { + tests.push(path); + continue; + } + + match path.extension().and_then(|s| s.to_str()) { + Some("md") => {} + Some("wit") => {} + _ => continue, + } + tests.push(path); + } + } +} + +struct Runner<'a> { + ntests: &'a AtomicUsize, +} + +impl Runner<'_> { + fn run(&mut self, test: &Path) -> Result<()> { + let mut resolve = Resolve::new(); + let result = if test.is_dir() { + resolve.push_dir(test).map(|(id, _)| id) + } else { + let mut map = SourceMap::new(); + map.set_require_semicolons(true); + map.push_file(test) + .and_then(|()| map.parse()) + .and_then(|p| resolve.push(p)) + }; + + let result = if test.iter().any(|s| s == "parse-fail") { + match result { + Ok(_) => bail!("expected test to not parse but it did"), + Err(mut e) => { + if let Some(err) = e.downcast_mut::() { + *err = io::Error::new( + io::ErrorKind::Other, + "some generic platform-agnostic error message", + ); + } + format!("{:?}", e) + } + } + } else { + result?; + // format json string to human readable + let json_result = serde_json::to_string_pretty(&resolve)?; + // "foo.wit" => "foo.wit.json" + self.read_or_write_to_file(test, &json_result, "json")?; + return Ok(()); + }; + + // "foo.wit" => "foo.wit.result" + // "foo.wit.md" => "foo.wit.md.result" + self.read_or_write_to_file(test, &result, "result")?; + return Ok(()); + } + + fn read_or_write_to_file( + &mut self, + test: &Path, + result: &str, + extension: &str, + ) -> Result<(), anyhow::Error> { + let result_file = if test.extension() == Some(OsStr::new("md")) + && test + .file_stem() + .and_then(|path| Path::new(path).extension()) + == Some(OsStr::new("wit")) + { + test.with_extension(format!("md.{extension}")) + } else { + test.with_extension(format!("wit.{extension}")) + }; + if env::var_os("BLESS").is_some() { + let normalized = normalize(&result, extension); + fs::write(&result_file, normalized)?; + } else { + let expected = fs::read_to_string(&result_file).context(format!( + "failed to read test expectation file {:?}\nthis can be fixed with BLESS=1", + result_file + ))?; + let expected = normalize(&expected, extension); + let result = normalize(&result, extension); + if expected != result { + bail!( + "failed test: result is not as expected:{}", + StrComparison::new(&expected, &result), + ); + } + } + self.bump_ntests(); + Ok(()) + } + + fn bump_ntests(&self) { + self.ntests.fetch_add(1, SeqCst); + } +} + +fn normalize(s: &str, extension: &str) -> String { + let s = s.trim(); + match extension { + // .result files have error messages with paths, so normalize Windows \ separators to / + "result" => s.replace("\\", "/").replace("\r\n", "\n"), + + // .json files escape strings with \, so leave them alone + _ => s.replace("\r\n", "\n"), + } +} diff --git a/crates/wit-parser/tests/ui/comments.wit b/crates/wit-parser/tests/ui/comments.wit new file mode 100644 index 0000000000..46545453de --- /dev/null +++ b/crates/wit-parser/tests/ui/comments.wit @@ -0,0 +1,25 @@ +package foo:comments; + +// hello +// world +// why, yes +// this is a comment +/* this too */ /* is a comment */ +/* this /* is /* a */ nested */ comment */ + +interface foo { + type x = u32; + + type /* foo */ bar /* baz */ = // + stream < // + // + // + + + + + x + + >; + +} diff --git a/crates/wit-parser/tests/ui/comments.wit.json b/crates/wit-parser/tests/ui/comments.wit.json new file mode 100644 index 0000000000..fd763de818 --- /dev/null +++ b/crates/wit-parser/tests/ui/comments.wit.json @@ -0,0 +1,46 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "foo", + "types": { + "x": 0, + "bar": 1 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "x", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "bar", + "kind": { + "stream": { + "element": 0, + "end": null + } + }, + "owner": { + "interface": 0 + } + } + ], + "packages": [ + { + "name": "foo:comments", + "interfaces": { + "foo": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/complex-include.wit.json b/crates/wit-parser/tests/ui/complex-include.wit.json new file mode 100644 index 0000000000..2c657bea8b --- /dev/null +++ b/crates/wit-parser/tests/ui/complex-include.wit.json @@ -0,0 +1,168 @@ +{ + "worlds": [ + { + "name": "bar-a", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-1": { + "interface": 1 + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "baz-a", + "imports": { + "interface-2": { + "interface": 2 + }, + "interface-3": { + "interface": 3 + } + }, + "exports": {}, + "package": 1 + }, + { + "name": "a", + "imports": { + "interface-4": { + "interface": 4 + }, + "interface-5": { + "interface": 5 + } + }, + "exports": {}, + "package": 2 + }, + { + "name": "b", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-1": { + "interface": 1 + } + }, + "exports": {}, + "package": 2 + }, + { + "name": "c", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-1": { + "interface": 1 + } + }, + "exports": {}, + "package": 2 + }, + { + "name": "union-world", + "imports": { + "interface-4": { + "interface": 4 + }, + "interface-5": { + "interface": 5 + }, + "interface-0": { + "interface": 0 + }, + "interface-1": { + "interface": 1 + }, + "interface-2": { + "interface": 2 + }, + "interface-3": { + "interface": 3 + } + }, + "exports": {}, + "package": 2 + } + ], + "interfaces": [ + { + "name": "a", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "b", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "a", + "types": {}, + "functions": {}, + "package": 1 + }, + { + "name": "b", + "types": {}, + "functions": {}, + "package": 1 + }, + { + "name": "ai", + "types": {}, + "functions": {}, + "package": 2 + }, + { + "name": "bi", + "types": {}, + "functions": {}, + "package": 2 + } + ], + "types": [], + "packages": [ + { + "name": "foo:bar", + "interfaces": { + "a": 0, + "b": 1 + }, + "worlds": { + "bar-a": 0 + } + }, + { + "name": "foo:baz", + "interfaces": { + "a": 2, + "b": 3 + }, + "worlds": { + "baz-a": 1 + } + }, + { + "name": "foo:root", + "interfaces": { + "ai": 4, + "bi": 5 + }, + "worlds": { + "a": 2, + "b": 3, + "c": 4, + "union-world": 5 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/complex-include/deps/bar/root.wit b/crates/wit-parser/tests/ui/complex-include/deps/bar/root.wit new file mode 100644 index 0000000000..cbf499369f --- /dev/null +++ b/crates/wit-parser/tests/ui/complex-include/deps/bar/root.wit @@ -0,0 +1,9 @@ +package foo:bar; + +interface a {} +interface b {} + +world bar-a { + import a; + import b; +} diff --git a/crates/wit-parser/tests/ui/complex-include/deps/baz/root.wit b/crates/wit-parser/tests/ui/complex-include/deps/baz/root.wit new file mode 100644 index 0000000000..ac0085ceb3 --- /dev/null +++ b/crates/wit-parser/tests/ui/complex-include/deps/baz/root.wit @@ -0,0 +1,9 @@ +package foo:baz; + +interface a {} +interface b {} + +world baz-a { + import a; + import b; +} diff --git a/crates/wit-parser/tests/ui/complex-include/root.wit b/crates/wit-parser/tests/ui/complex-include/root.wit new file mode 100644 index 0000000000..810202482e --- /dev/null +++ b/crates/wit-parser/tests/ui/complex-include/root.wit @@ -0,0 +1,26 @@ +package foo:root; + +interface ai {} +interface bi {} + +world a { + import ai; + import bi; +} + +world b { + include foo:bar/bar-a; +} + +world c { + include b; + include foo:bar/bar-a; +} + +world union-world { + include a; + include b; + include c; + include foo:bar/bar-a; + include foo:baz/baz-a; +} diff --git a/crates/wit-parser/tests/ui/cross-package-resource.wit.json b/crates/wit-parser/tests/ui/cross-package-resource.wit.json new file mode 100644 index 0000000000..51ab92795d --- /dev/null +++ b/crates/wit-parser/tests/ui/cross-package-resource.wit.json @@ -0,0 +1,67 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "foo", + "types": { + "r": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": "foo", + "types": { + "r": 1, + "t": 2 + }, + "functions": {}, + "package": 1 + } + ], + "types": [ + { + "name": "r", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": "r", + "kind": { + "type": 0 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t", + "kind": { + "handle": { + "own": 1 + } + }, + "owner": { + "interface": 1 + } + } + ], + "packages": [ + { + "name": "some:dep", + "interfaces": { + "foo": 0 + }, + "worlds": {} + }, + { + "name": "foo:bar", + "interfaces": { + "foo": 1 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/cross-package-resource/deps/foo/foo.wit b/crates/wit-parser/tests/ui/cross-package-resource/deps/foo/foo.wit new file mode 100644 index 0000000000..a9c5658d4b --- /dev/null +++ b/crates/wit-parser/tests/ui/cross-package-resource/deps/foo/foo.wit @@ -0,0 +1,5 @@ +package some:dep; + +interface foo { + resource r; +} diff --git a/crates/wit-parser/tests/ui/cross-package-resource/foo.wit b/crates/wit-parser/tests/ui/cross-package-resource/foo.wit new file mode 100644 index 0000000000..030dabab58 --- /dev/null +++ b/crates/wit-parser/tests/ui/cross-package-resource/foo.wit @@ -0,0 +1,7 @@ +package foo:bar; + +interface foo { + use some:dep/foo.{r}; + + type t = own; +} diff --git a/crates/wit-parser/tests/ui/diamond1.wit.json b/crates/wit-parser/tests/ui/diamond1.wit.json new file mode 100644 index 0000000000..8d7ce082ea --- /dev/null +++ b/crates/wit-parser/tests/ui/diamond1.wit.json @@ -0,0 +1,55 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-1": { + "interface": 1 + } + }, + "exports": {}, + "package": 2 + } + ], + "interfaces": [ + { + "name": "types", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "types", + "types": {}, + "functions": {}, + "package": 1 + } + ], + "types": [], + "packages": [ + { + "name": "foo:dep1", + "interfaces": { + "types": 0 + }, + "worlds": {} + }, + { + "name": "foo:dep2", + "interfaces": { + "types": 1 + }, + "worlds": {} + }, + { + "name": "foo:foo", + "interfaces": {}, + "worlds": { + "foo": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/diamond1/deps/dep1/types.wit b/crates/wit-parser/tests/ui/diamond1/deps/dep1/types.wit new file mode 100644 index 0000000000..4c84420d4f --- /dev/null +++ b/crates/wit-parser/tests/ui/diamond1/deps/dep1/types.wit @@ -0,0 +1,2 @@ +package foo:dep1; +interface types {} diff --git a/crates/wit-parser/tests/ui/diamond1/deps/dep2/types.wit b/crates/wit-parser/tests/ui/diamond1/deps/dep2/types.wit new file mode 100644 index 0000000000..b7cf946632 --- /dev/null +++ b/crates/wit-parser/tests/ui/diamond1/deps/dep2/types.wit @@ -0,0 +1,2 @@ +package foo:dep2; +interface types {} diff --git a/crates/wit-parser/tests/ui/diamond1/join.wit b/crates/wit-parser/tests/ui/diamond1/join.wit new file mode 100644 index 0000000000..70d8759ee5 --- /dev/null +++ b/crates/wit-parser/tests/ui/diamond1/join.wit @@ -0,0 +1,6 @@ +package foo:foo; + +world foo { + import foo:dep1/types; + import foo:dep2/types; +} diff --git a/crates/wit-parser/tests/ui/disambiguate-diamond.wit.json b/crates/wit-parser/tests/ui/disambiguate-diamond.wit.json new file mode 100644 index 0000000000..0e3ebea318 --- /dev/null +++ b/crates/wit-parser/tests/ui/disambiguate-diamond.wit.json @@ -0,0 +1,107 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "interface-0": { + "interface": 0 + }, + "foo": { + "interface": 2 + }, + "interface-1": { + "interface": 1 + }, + "bar": { + "interface": 3 + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "shared1", + "types": { + "the-type": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": "shared2", + "types": { + "the-type": 1 + }, + "functions": {}, + "package": 0 + }, + { + "name": null, + "types": { + "the-type": 2 + }, + "functions": {}, + "package": 0 + }, + { + "name": null, + "types": { + "the-type": 3 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "the-type", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "the-type", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 1 + } + }, + { + "name": "the-type", + "kind": { + "type": 0 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "the-type", + "kind": { + "type": 1 + }, + "owner": { + "interface": 3 + } + } + ], + "packages": [ + { + "name": "foo:diamond", + "interfaces": { + "shared1": 0, + "shared2": 1 + }, + "worlds": { + "foo": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/disambiguate-diamond/shared1.wit b/crates/wit-parser/tests/ui/disambiguate-diamond/shared1.wit new file mode 100644 index 0000000000..9cc7bbd902 --- /dev/null +++ b/crates/wit-parser/tests/ui/disambiguate-diamond/shared1.wit @@ -0,0 +1,3 @@ +interface shared1 { + type the-type = u32; +} diff --git a/crates/wit-parser/tests/ui/disambiguate-diamond/shared2.wit b/crates/wit-parser/tests/ui/disambiguate-diamond/shared2.wit new file mode 100644 index 0000000000..07b75f6868 --- /dev/null +++ b/crates/wit-parser/tests/ui/disambiguate-diamond/shared2.wit @@ -0,0 +1,3 @@ +interface shared2 { + type the-type = u32; +} diff --git a/crates/wit-parser/tests/ui/disambiguate-diamond/world.wit b/crates/wit-parser/tests/ui/disambiguate-diamond/world.wit new file mode 100644 index 0000000000..837d08fa67 --- /dev/null +++ b/crates/wit-parser/tests/ui/disambiguate-diamond/world.wit @@ -0,0 +1,13 @@ +package foo:diamond; + +world foo { + import foo: interface { + use shared1.{the-type}; + } + import bar: interface { + use shared2.{the-type}; + } + + import shared1; + import shared2; +} diff --git a/crates/wit-parser/tests/ui/empty.wit b/crates/wit-parser/tests/ui/empty.wit new file mode 100644 index 0000000000..bfb0e9823a --- /dev/null +++ b/crates/wit-parser/tests/ui/empty.wit @@ -0,0 +1 @@ +package foo:empty; diff --git a/crates/wit-parser/tests/ui/empty.wit.json b/crates/wit-parser/tests/ui/empty.wit.json new file mode 100644 index 0000000000..092abe5e1d --- /dev/null +++ b/crates/wit-parser/tests/ui/empty.wit.json @@ -0,0 +1,12 @@ +{ + "worlds": [], + "interfaces": [], + "types": [], + "packages": [ + { + "name": "foo:empty", + "interfaces": {}, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/foreign-deps-union.wit.json b/crates/wit-parser/tests/ui/foreign-deps-union.wit.json new file mode 100644 index 0000000000..3c1e2fb406 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union.wit.json @@ -0,0 +1,380 @@ +{ + "worlds": [ + { + "name": "wasi", + "imports": { + "interface-8": { + "interface": 8 + }, + "interface-7": { + "interface": 7 + } + }, + "exports": {}, + "package": 5 + }, + { + "name": "my-world", + "imports": { + "interface-8": { + "interface": 8 + }, + "interface-7": { + "interface": 7 + } + }, + "exports": { + "interface-1": { + "interface": 1 + } + }, + "package": 6 + }, + { + "name": "my-world2", + "imports": { + "interface-8": { + "interface": 8 + }, + "interface-7": { + "interface": 7 + } + }, + "exports": { + "interface-9": { + "interface": 9 + }, + "interface-1": { + "interface": 1 + } + }, + "package": 6 + }, + { + "name": "bars-world", + "imports": { + "interface-4": { + "interface": 4 + }, + "interface-0": { + "interface": 0 + } + }, + "exports": {}, + "package": 6 + }, + { + "name": "unionw-world", + "imports": { + "interface-8": { + "interface": 8 + }, + "interface-7": { + "interface": 7 + } + }, + "exports": { + "interface-1": { + "interface": 1 + }, + "interface-9": { + "interface": 9 + } + }, + "package": 6 + } + ], + "interfaces": [ + { + "name": "other-interface", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "saas", + "types": {}, + "functions": {}, + "package": 1 + }, + { + "name": "i", + "types": {}, + "functions": {}, + "package": 2 + }, + { + "name": "the-default", + "types": { + "some-type": 0 + }, + "functions": {}, + "package": 3 + }, + { + "name": "the-default", + "types": { + "from-default": 1 + }, + "functions": {}, + "package": 4 + }, + { + "name": "some-interface", + "types": { + "another-type": 2 + }, + "functions": {}, + "package": 4 + }, + { + "name": "another-interface", + "types": { + "yet-another-type": 3 + }, + "functions": {}, + "package": 4 + }, + { + "name": "clocks", + "types": { + "timestamp": 4 + }, + "functions": {}, + "package": 5 + }, + { + "name": "filesystem", + "types": { + "stat": 5 + }, + "functions": {}, + "package": 5 + }, + { + "name": "foo", + "types": { + "timestamp": 6, + "stat": 7 + }, + "functions": {}, + "package": 6 + }, + { + "name": "bar", + "types": { + "from-default": 8, + "another-type": 9, + "yet-another-type": 10 + }, + "functions": {}, + "package": 6 + }, + { + "name": "use1", + "types": { + "some-type": 11 + }, + "functions": {}, + "package": 6 + }, + { + "name": "use2", + "types": { + "some-type": 12 + }, + "functions": {}, + "package": 6 + } + ], + "types": [ + { + "name": "some-type", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 3 + } + }, + { + "name": "from-default", + "kind": { + "type": "string" + }, + "owner": { + "interface": 4 + } + }, + { + "name": "another-type", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 5 + } + }, + { + "name": "yet-another-type", + "kind": { + "type": "u8" + }, + "owner": { + "interface": 6 + } + }, + { + "name": "timestamp", + "kind": { + "type": "u64" + }, + "owner": { + "interface": 7 + } + }, + { + "name": "stat", + "kind": { + "record": { + "fields": [ + { + "name": "ino", + "type": "u64" + } + ] + } + }, + "owner": { + "interface": 8 + } + }, + { + "name": "timestamp", + "kind": { + "type": 4 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "stat", + "kind": { + "type": 5 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "from-default", + "kind": { + "type": 1 + }, + "owner": { + "interface": 10 + } + }, + { + "name": "another-type", + "kind": { + "type": 2 + }, + "owner": { + "interface": 10 + } + }, + { + "name": "yet-another-type", + "kind": { + "type": 3 + }, + "owner": { + "interface": 10 + } + }, + { + "name": "some-type", + "kind": { + "type": 0 + }, + "owner": { + "interface": 11 + } + }, + { + "name": "some-type", + "kind": { + "type": 0 + }, + "owner": { + "interface": 12 + } + } + ], + "packages": [ + { + "name": "foo:another-pkg", + "interfaces": { + "other-interface": 0 + }, + "worlds": {} + }, + { + "name": "foo:corp", + "interfaces": { + "saas": 1 + }, + "worlds": {} + }, + { + "name": "foo:different-pkg", + "interfaces": { + "i": 2 + }, + "worlds": {} + }, + { + "name": "foo:foreign-pkg", + "interfaces": { + "the-default": 3 + }, + "worlds": {} + }, + { + "name": "foo:some-pkg", + "interfaces": { + "the-default": 4, + "some-interface": 5, + "another-interface": 6 + }, + "worlds": {} + }, + { + "name": "foo:wasi", + "interfaces": { + "clocks": 7, + "filesystem": 8 + }, + "worlds": { + "wasi": 0 + } + }, + { + "name": "foo:root", + "interfaces": { + "foo": 9, + "bar": 10, + "use1": 11, + "use2": 12 + }, + "worlds": { + "my-world": 1, + "my-world2": 2, + "bars-world": 3, + "unionw-world": 4 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/deps/another-pkg/other-doc.wit b/crates/wit-parser/tests/ui/foreign-deps-union/deps/another-pkg/other-doc.wit new file mode 100644 index 0000000000..a6fe3bac68 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/deps/another-pkg/other-doc.wit @@ -0,0 +1,3 @@ +package foo:another-pkg; + +interface other-interface {} diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/deps/corp/saas.wit b/crates/wit-parser/tests/ui/foreign-deps-union/deps/corp/saas.wit new file mode 100644 index 0000000000..9e913cd512 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/deps/corp/saas.wit @@ -0,0 +1,4 @@ +package foo:corp; + +interface saas { +} diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/deps/different-pkg/the-doc.wit b/crates/wit-parser/tests/ui/foreign-deps-union/deps/different-pkg/the-doc.wit new file mode 100644 index 0000000000..bfb1ba6caa --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/deps/different-pkg/the-doc.wit @@ -0,0 +1,2 @@ +package foo:different-pkg; +interface i {} diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/deps/foreign-pkg/the-doc.wit b/crates/wit-parser/tests/ui/foreign-deps-union/deps/foreign-pkg/the-doc.wit new file mode 100644 index 0000000000..c33f455165 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/deps/foreign-pkg/the-doc.wit @@ -0,0 +1,5 @@ +package foo:foreign-pkg; + +interface the-default { + type some-type = u32; +} diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/deps/some-pkg/some-doc.wit b/crates/wit-parser/tests/ui/foreign-deps-union/deps/some-pkg/some-doc.wit new file mode 100644 index 0000000000..ba4990fd10 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/deps/some-pkg/some-doc.wit @@ -0,0 +1,13 @@ +package foo:some-pkg; + +interface the-default { + type from-default = string; +} + +interface some-interface { + type another-type = u32; +} + +interface another-interface { + type yet-another-type = u8; +} diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/clocks.wit b/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/clocks.wit new file mode 100644 index 0000000000..0e340852ef --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/clocks.wit @@ -0,0 +1,5 @@ +package foo:wasi; + +interface clocks { + type timestamp = u64; +} diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/filesystem.wit b/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/filesystem.wit new file mode 100644 index 0000000000..97be222b2a --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/filesystem.wit @@ -0,0 +1,7 @@ +package foo:wasi; + +interface filesystem { + record stat { + ino: u64 + } +} diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/wasi.wit b/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/wasi.wit new file mode 100644 index 0000000000..edcf06f136 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/deps/wasi/wasi.wit @@ -0,0 +1,6 @@ +package foo:wasi; + +world wasi { + import filesystem; + import clocks; +} diff --git a/crates/wit-parser/tests/ui/foreign-deps-union/root.wit b/crates/wit-parser/tests/ui/foreign-deps-union/root.wit new file mode 100644 index 0000000000..eac08d7d17 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps-union/root.wit @@ -0,0 +1,50 @@ +package foo:root; + +interface foo { + use foo:wasi/clocks.{timestamp}; + use foo:wasi/filesystem.{stat}; +} + +world my-world { + import foo:wasi/filesystem; + import foo:wasi/clocks; + + export foo:corp/saas; +} + +use foo:wasi/filesystem as filesystem; +use foo:wasi/clocks as clocks; + +world my-world2 { + import filesystem; + import clocks; + export foo; + export foo:corp/saas; +} + +interface bar { + use filesystem.{}; + use foo:some-pkg/the-default.{from-default}; + use foo:some-pkg/some-interface.{another-type}; + use foo:some-pkg/some-interface.{}; + use foo:some-pkg/another-interface.{yet-another-type}; + use foo:different-pkg/i.{}; +} + +world bars-world { + import foo:some-pkg/the-default; + import foo:another-pkg/other-interface; +} + +interface use1 { + use foo:foreign-pkg/the-default.{some-type}; +} +interface use2 { + use foo:foreign-pkg/the-default.{some-type}; +} + +world unionw-world { + include my-world; + include my-world2; + include foo:wasi/wasi; +} diff --git a/crates/wit-parser/tests/ui/foreign-deps.wit.json b/crates/wit-parser/tests/ui/foreign-deps.wit.json new file mode 100644 index 0000000000..da5020f0a9 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps.wit.json @@ -0,0 +1,344 @@ +{ + "worlds": [ + { + "name": "my-world", + "imports": { + "interface-8": { + "interface": 8 + }, + "interface-7": { + "interface": 7 + } + }, + "exports": { + "interface-1": { + "interface": 1 + } + }, + "package": 6 + }, + { + "name": "my-world2", + "imports": { + "interface-8": { + "interface": 8 + }, + "interface-7": { + "interface": 7 + } + }, + "exports": { + "interface-9": { + "interface": 9 + }, + "interface-1": { + "interface": 1 + } + }, + "package": 6 + }, + { + "name": "bars-world", + "imports": { + "interface-4": { + "interface": 4 + }, + "interface-0": { + "interface": 0 + } + }, + "exports": {}, + "package": 6 + } + ], + "interfaces": [ + { + "name": "other-interface", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "saas", + "types": {}, + "functions": {}, + "package": 1 + }, + { + "name": "i", + "types": {}, + "functions": {}, + "package": 2 + }, + { + "name": "the-default", + "types": { + "some-type": 0 + }, + "functions": {}, + "package": 3 + }, + { + "name": "the-default", + "types": { + "from-default": 1 + }, + "functions": {}, + "package": 4 + }, + { + "name": "some-interface", + "types": { + "another-type": 2 + }, + "functions": {}, + "package": 4 + }, + { + "name": "another-interface", + "types": { + "yet-another-type": 3 + }, + "functions": {}, + "package": 4 + }, + { + "name": "clocks", + "types": { + "timestamp": 4 + }, + "functions": {}, + "package": 5 + }, + { + "name": "filesystem", + "types": { + "stat": 5 + }, + "functions": {}, + "package": 5 + }, + { + "name": "foo", + "types": { + "timestamp": 6, + "stat": 7 + }, + "functions": {}, + "package": 6 + }, + { + "name": "bar", + "types": { + "from-default": 8, + "another-type": 9, + "yet-another-type": 10 + }, + "functions": {}, + "package": 6 + }, + { + "name": "use1", + "types": { + "some-type": 11 + }, + "functions": {}, + "package": 6 + }, + { + "name": "use2", + "types": { + "some-type": 12 + }, + "functions": {}, + "package": 6 + } + ], + "types": [ + { + "name": "some-type", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 3 + } + }, + { + "name": "from-default", + "kind": { + "type": "string" + }, + "owner": { + "interface": 4 + } + }, + { + "name": "another-type", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 5 + } + }, + { + "name": "yet-another-type", + "kind": { + "type": "u8" + }, + "owner": { + "interface": 6 + } + }, + { + "name": "timestamp", + "kind": { + "type": "u64" + }, + "owner": { + "interface": 7 + } + }, + { + "name": "stat", + "kind": { + "record": { + "fields": [ + { + "name": "ino", + "type": "u64" + } + ] + } + }, + "owner": { + "interface": 8 + } + }, + { + "name": "timestamp", + "kind": { + "type": 4 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "stat", + "kind": { + "type": 5 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "from-default", + "kind": { + "type": 1 + }, + "owner": { + "interface": 10 + } + }, + { + "name": "another-type", + "kind": { + "type": 2 + }, + "owner": { + "interface": 10 + } + }, + { + "name": "yet-another-type", + "kind": { + "type": 3 + }, + "owner": { + "interface": 10 + } + }, + { + "name": "some-type", + "kind": { + "type": 0 + }, + "owner": { + "interface": 11 + } + }, + { + "name": "some-type", + "kind": { + "type": 0 + }, + "owner": { + "interface": 12 + } + } + ], + "packages": [ + { + "name": "foo:another-pkg", + "interfaces": { + "other-interface": 0 + }, + "worlds": {} + }, + { + "name": "foo:corp", + "interfaces": { + "saas": 1 + }, + "worlds": {} + }, + { + "name": "foo:different-pkg", + "interfaces": { + "i": 2 + }, + "worlds": {} + }, + { + "name": "foo:foreign-pkg", + "interfaces": { + "the-default": 3 + }, + "worlds": {} + }, + { + "name": "foo:some-pkg", + "interfaces": { + "the-default": 4, + "some-interface": 5, + "another-interface": 6 + }, + "worlds": {} + }, + { + "name": "foo:wasi", + "interfaces": { + "clocks": 7, + "filesystem": 8 + }, + "worlds": {} + }, + { + "name": "foo:root", + "interfaces": { + "foo": 9, + "bar": 10, + "use1": 11, + "use2": 12 + }, + "worlds": { + "my-world": 0, + "my-world2": 1, + "bars-world": 2 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/another-pkg/other-doc.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/another-pkg/other-doc.wit new file mode 100644 index 0000000000..a6fe3bac68 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/another-pkg/other-doc.wit @@ -0,0 +1,3 @@ +package foo:another-pkg; + +interface other-interface {} diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/corp/saas.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/corp/saas.wit new file mode 100644 index 0000000000..9e913cd512 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/corp/saas.wit @@ -0,0 +1,4 @@ +package foo:corp; + +interface saas { +} diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/different-pkg/the-doc.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/different-pkg/the-doc.wit new file mode 100644 index 0000000000..bfb1ba6caa --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/different-pkg/the-doc.wit @@ -0,0 +1,2 @@ +package foo:different-pkg; +interface i {} diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/foreign-pkg/the-doc.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/foreign-pkg/the-doc.wit new file mode 100644 index 0000000000..c33f455165 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/foreign-pkg/the-doc.wit @@ -0,0 +1,5 @@ +package foo:foreign-pkg; + +interface the-default { + type some-type = u32; +} diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/some-pkg/some-doc.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/some-pkg/some-doc.wit new file mode 100644 index 0000000000..ba4990fd10 --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/some-pkg/some-doc.wit @@ -0,0 +1,13 @@ +package foo:some-pkg; + +interface the-default { + type from-default = string; +} + +interface some-interface { + type another-type = u32; +} + +interface another-interface { + type yet-another-type = u8; +} diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/clocks.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/clocks.wit new file mode 100644 index 0000000000..0e340852ef --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/clocks.wit @@ -0,0 +1,5 @@ +package foo:wasi; + +interface clocks { + type timestamp = u64; +} diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/filesystem.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/filesystem.wit new file mode 100644 index 0000000000..97be222b2a --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/filesystem.wit @@ -0,0 +1,7 @@ +package foo:wasi; + +interface filesystem { + record stat { + ino: u64 + } +} diff --git a/crates/wit-parser/tests/ui/foreign-deps/root.wit b/crates/wit-parser/tests/ui/foreign-deps/root.wit new file mode 100644 index 0000000000..1880a967cf --- /dev/null +++ b/crates/wit-parser/tests/ui/foreign-deps/root.wit @@ -0,0 +1,44 @@ +package foo:root; + +interface foo { + use foo:wasi/clocks.{timestamp}; + use foo:wasi/filesystem.{stat}; +} + +world my-world { + import foo:wasi/filesystem; + import foo:wasi/clocks; + + export foo:corp/saas; +} + +use foo:wasi/filesystem as filesystem; +use foo:wasi/clocks as clocks; + +world my-world2 { + import filesystem; + import clocks; + export foo; + export foo:corp/saas; +} + +interface bar { + use filesystem.{}; + use foo:some-pkg/the-default.{from-default}; + use foo:some-pkg/some-interface.{another-type}; + use foo:some-pkg/some-interface.{}; + use foo:some-pkg/another-interface.{yet-another-type}; + use foo:different-pkg/i.{}; +} + +world bars-world { + import foo:some-pkg/the-default; + import foo:another-pkg/other-interface; +} + +interface use1 { + use foo:foreign-pkg/the-default.{some-type}; +} +interface use2 { + use foo:foreign-pkg/the-default.{some-type}; +} diff --git a/crates/wit-parser/tests/ui/functions.wit b/crates/wit-parser/tests/ui/functions.wit new file mode 100644 index 0000000000..8c4d8da0c7 --- /dev/null +++ b/crates/wit-parser/tests/ui/functions.wit @@ -0,0 +1,14 @@ +package foo:functions; + +interface functions { + f1: func(); + f2: func(a: u32); + f3: func(a: u32,); + f4: func() -> u32; + f6: func() -> tuple; + f7: func(a: float32, b: float32) -> tuple; + f8: func(a: option) -> result; + f9: func() -> (u: u32, f: float32); + f10: func() -> (u: u32); + f11: func() -> (); +} diff --git a/crates/wit-parser/tests/ui/functions.wit.json b/crates/wit-parser/tests/ui/functions.wit.json new file mode 100644 index 0000000000..bb2867cde4 --- /dev/null +++ b/crates/wit-parser/tests/ui/functions.wit.json @@ -0,0 +1,166 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "functions", + "types": {}, + "functions": { + "f1": { + "name": "f1", + "kind": "freestanding", + "params": [], + "results": [] + }, + "f2": { + "name": "f2", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": "u32" + } + ], + "results": [] + }, + "f3": { + "name": "f3", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": "u32" + } + ], + "results": [] + }, + "f4": { + "name": "f4", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": "u32" + } + ] + }, + "f6": { + "name": "f6", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 0 + } + ] + }, + "f7": { + "name": "f7", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": "float32" + }, + { + "name": "b", + "type": "float32" + } + ], + "results": [ + { + "type": 0 + } + ] + }, + "f8": { + "name": "f8", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 1 + } + ], + "results": [ + { + "type": 2 + } + ] + }, + "f9": { + "name": "f9", + "kind": "freestanding", + "params": [], + "results": [ + { + "name": "u", + "type": "u32" + }, + { + "name": "f", + "type": "float32" + } + ] + }, + "f10": { + "name": "f10", + "kind": "freestanding", + "params": [], + "results": [ + { + "name": "u", + "type": "u32" + } + ] + }, + "f11": { + "name": "f11", + "kind": "freestanding", + "params": [], + "results": [] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": null, + "kind": { + "tuple": { + "types": [ + "u32", + "u32" + ] + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "option": "u32" + }, + "owner": null + }, + { + "name": null, + "kind": { + "result": { + "ok": "u32", + "err": "float32" + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:functions", + "interfaces": { + "functions": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/ignore-files-deps.wit.json b/crates/wit-parser/tests/ui/ignore-files-deps.wit.json new file mode 100644 index 0000000000..1b9d00c360 --- /dev/null +++ b/crates/wit-parser/tests/ui/ignore-files-deps.wit.json @@ -0,0 +1,39 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "interface-0": { + "interface": 0 + } + }, + "exports": {}, + "package": 1 + } + ], + "interfaces": [ + { + "name": "types", + "types": {}, + "functions": {}, + "package": 0 + } + ], + "types": [], + "packages": [ + { + "name": "foo:bar", + "interfaces": { + "types": 0 + }, + "worlds": {} + }, + { + "name": "foo:foo", + "interfaces": {}, + "worlds": { + "foo": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/ignore-files-deps/deps/bar/types.wit b/crates/wit-parser/tests/ui/ignore-files-deps/deps/bar/types.wit new file mode 100644 index 0000000000..ad574e3aa1 --- /dev/null +++ b/crates/wit-parser/tests/ui/ignore-files-deps/deps/bar/types.wit @@ -0,0 +1,2 @@ +package foo:bar; +interface types {} diff --git a/crates/wit-parser/tests/ui/ignore-files-deps/deps/ignore-me.txt b/crates/wit-parser/tests/ui/ignore-files-deps/deps/ignore-me.txt new file mode 100644 index 0000000000..48a897f5f1 --- /dev/null +++ b/crates/wit-parser/tests/ui/ignore-files-deps/deps/ignore-me.txt @@ -0,0 +1 @@ +this file should be ignored by the parser \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/ignore-files-deps/world.wit b/crates/wit-parser/tests/ui/ignore-files-deps/world.wit new file mode 100644 index 0000000000..710e7ebcb3 --- /dev/null +++ b/crates/wit-parser/tests/ui/ignore-files-deps/world.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo { + import foo:bar/types; +} diff --git a/crates/wit-parser/tests/ui/include-reps.wit b/crates/wit-parser/tests/ui/include-reps.wit new file mode 100644 index 0000000000..cca17dbdc8 --- /dev/null +++ b/crates/wit-parser/tests/ui/include-reps.wit @@ -0,0 +1,15 @@ +package foo:foo; + +interface a {} +interface b {} + +world bar { + import a; + export b; +} + +world foo { + include bar; + include bar; + include bar; +} diff --git a/crates/wit-parser/tests/ui/include-reps.wit.json b/crates/wit-parser/tests/ui/include-reps.wit.json new file mode 100644 index 0000000000..8217e2ee33 --- /dev/null +++ b/crates/wit-parser/tests/ui/include-reps.wit.json @@ -0,0 +1,60 @@ +{ + "worlds": [ + { + "name": "bar", + "imports": { + "interface-0": { + "interface": 0 + } + }, + "exports": { + "interface-1": { + "interface": 1 + } + }, + "package": 0 + }, + { + "name": "foo", + "imports": { + "interface-0": { + "interface": 0 + } + }, + "exports": { + "interface-1": { + "interface": 1 + } + }, + "package": 0 + } + ], + "interfaces": [ + { + "name": "a", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "b", + "types": {}, + "functions": {}, + "package": 0 + } + ], + "types": [], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "a": 0, + "b": 1 + }, + "worlds": { + "bar": 0, + "foo": 1 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/kebab-name-include-with.wit b/crates/wit-parser/tests/ui/kebab-name-include-with.wit new file mode 100644 index 0000000000..f218637ef7 --- /dev/null +++ b/crates/wit-parser/tests/ui/kebab-name-include-with.wit @@ -0,0 +1,8 @@ +package foo:foo; + +world foo { import a: func(); } +world bar { import a: func(); } +world baz { + include foo with { a as b } + include bar; +} diff --git a/crates/wit-parser/tests/ui/kebab-name-include-with.wit.json b/crates/wit-parser/tests/ui/kebab-name-include-with.wit.json new file mode 100644 index 0000000000..14c6d0d048 --- /dev/null +++ b/crates/wit-parser/tests/ui/kebab-name-include-with.wit.json @@ -0,0 +1,70 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "a": { + "function": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [] + } + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "bar", + "imports": { + "a": { + "function": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [] + } + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "baz", + "imports": { + "b": { + "function": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [] + } + }, + "a": { + "function": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [] + } + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [], + "types": [], + "packages": [ + { + "name": "foo:foo", + "interfaces": {}, + "worlds": { + "foo": 0, + "bar": 1, + "baz": 2 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/many-names.wit.json b/crates/wit-parser/tests/ui/many-names.wit.json new file mode 100644 index 0000000000..87d111bd1f --- /dev/null +++ b/crates/wit-parser/tests/ui/many-names.wit.json @@ -0,0 +1,40 @@ +{ + "worlds": [ + { + "name": "name", + "imports": { + "name": { + "interface": 1 + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "x", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": null, + "types": {}, + "functions": {}, + "package": 0 + } + ], + "types": [], + "packages": [ + { + "name": "foo:name", + "interfaces": { + "x": 0 + }, + "worlds": { + "name": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/many-names/a.wit b/crates/wit-parser/tests/ui/many-names/a.wit new file mode 100644 index 0000000000..6f7ec5a176 --- /dev/null +++ b/crates/wit-parser/tests/ui/many-names/a.wit @@ -0,0 +1,2 @@ +interface x {} +use x as name; diff --git a/crates/wit-parser/tests/ui/many-names/b.wit b/crates/wit-parser/tests/ui/many-names/b.wit new file mode 100644 index 0000000000..c6d8540618 --- /dev/null +++ b/crates/wit-parser/tests/ui/many-names/b.wit @@ -0,0 +1,5 @@ +package foo:name; + +world name { + import name: interface {} +} diff --git a/crates/wit-parser/tests/ui/multi-file.wit.json b/crates/wit-parser/tests/ui/multi-file.wit.json new file mode 100644 index 0000000000..ef6171bce2 --- /dev/null +++ b/crates/wit-parser/tests/ui/multi-file.wit.json @@ -0,0 +1,298 @@ +{ + "worlds": [ + { + "name": "more-depends-on-later-things", + "imports": { + "interface-3": { + "interface": 3 + } + }, + "exports": { + "interface-3": { + "interface": 3 + } + }, + "package": 0 + }, + { + "name": "the-world", + "imports": { + "interface-1": { + "interface": 1 + }, + "x": { + "type": 15 + }, + "foo": { + "function": { + "name": "foo", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 15 + } + ] + } + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "irrelevant-name", + "types": { + "a-name": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": "depend-on-me", + "types": { + "x": 1 + }, + "functions": {}, + "package": 0 + }, + { + "name": "depends-on-later-item", + "types": { + "x": 2 + }, + "functions": {}, + "package": 0 + }, + { + "name": "later-interface", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "cycle1", + "types": { + "t": 3 + }, + "functions": {}, + "package": 0 + }, + { + "name": "cycle2", + "types": { + "t": 4 + }, + "functions": {}, + "package": 0 + }, + { + "name": "cycle3", + "types": { + "t": 5 + }, + "functions": {}, + "package": 0 + }, + { + "name": "foo", + "types": { + "x": 6 + }, + "functions": {}, + "package": 0 + }, + { + "name": "something-else", + "types": { + "y": 7 + }, + "functions": {}, + "package": 0 + }, + { + "name": "bar", + "types": { + "x": 8, + "x2": 9, + "x3": 10, + "x4": 11, + "y": 12, + "y2": 13, + "a-name": 14 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "a-name", + "kind": { + "record": { + "fields": [] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "x", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 1 + } + }, + { + "name": "x", + "kind": { + "type": 1 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t", + "kind": { + "type": 3 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t", + "kind": { + "type": 4 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "x", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 7 + } + }, + { + "name": "y", + "kind": { + "type": "u64" + }, + "owner": { + "interface": 8 + } + }, + { + "name": "x", + "kind": { + "type": 6 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "x2", + "kind": { + "type": 6 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "x3", + "kind": { + "type": 6 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "x4", + "kind": { + "type": 1 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "y", + "kind": { + "type": 7 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "y2", + "kind": { + "type": 7 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "a-name", + "kind": { + "type": 0 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "x", + "kind": { + "type": 1 + }, + "owner": { + "world": 1 + } + } + ], + "packages": [ + { + "name": "foo:multi-file", + "interfaces": { + "irrelevant-name": 0, + "depend-on-me": 1, + "depends-on-later-item": 2, + "later-interface": 3, + "cycle1": 4, + "cycle2": 5, + "cycle3": 6, + "foo": 7, + "something-else": 8, + "bar": 9 + }, + "worlds": { + "more-depends-on-later-things": 0, + "the-world": 1 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/multi-file/bar.wit b/crates/wit-parser/tests/ui/multi-file/bar.wit new file mode 100644 index 0000000000..0803f26b2d --- /dev/null +++ b/crates/wit-parser/tests/ui/multi-file/bar.wit @@ -0,0 +1,21 @@ +package foo:multi-file; + +interface irrelevant-name { + record a-name {} +} + +interface depends-on-later-item { + use depend-on-me.{x}; +} + +interface depend-on-me { + type x = u32; +} + +world more-depends-on-later-things { + import later-interface; + export later-interface; +} + +interface later-interface { +} diff --git a/crates/wit-parser/tests/ui/multi-file/cycle-a.wit b/crates/wit-parser/tests/ui/multi-file/cycle-a.wit new file mode 100644 index 0000000000..c66ac96f0e --- /dev/null +++ b/crates/wit-parser/tests/ui/multi-file/cycle-a.wit @@ -0,0 +1,7 @@ +interface cycle1 { + type t = u32; +} + +interface cycle3 { + use cycle2.{t}; +} diff --git a/crates/wit-parser/tests/ui/multi-file/cycle-b.wit b/crates/wit-parser/tests/ui/multi-file/cycle-b.wit new file mode 100644 index 0000000000..e5d803f456 --- /dev/null +++ b/crates/wit-parser/tests/ui/multi-file/cycle-b.wit @@ -0,0 +1,3 @@ +interface cycle2 { + use cycle1.{t}; +} diff --git a/crates/wit-parser/tests/ui/multi-file/foo.wit b/crates/wit-parser/tests/ui/multi-file/foo.wit new file mode 100644 index 0000000000..ace17c5576 --- /dev/null +++ b/crates/wit-parser/tests/ui/multi-file/foo.wit @@ -0,0 +1,31 @@ +package foo:multi-file; + +interface foo { + type x = u32; +} + +use foo as foo2; + +interface something-else { + type y = u64; +} + +use depend-on-me as a-different-name; + +interface bar { + use foo.{x}; + use foo.{x as x2}; + use foo2.{x as x3}; + use a-different-name.{x as x4}; + use something-else.{y}; + use something-else.{y as y2}; + use irrelevant-name.{a-name}; +} + +world the-world { + import a-different-name; + + use a-different-name.{x}; + + import foo: func() -> x; +} diff --git a/crates/wit-parser/tests/ui/name-both-resource-and-type.wit.json b/crates/wit-parser/tests/ui/name-both-resource-and-type.wit.json new file mode 100644 index 0000000000..1dad5120b5 --- /dev/null +++ b/crates/wit-parser/tests/ui/name-both-resource-and-type.wit.json @@ -0,0 +1,89 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "foo", + "types": { + "a": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": "foo", + "types": { + "a": 1, + "t1": 2, + "t2": 3, + "t3": 4 + }, + "functions": {}, + "package": 1 + } + ], + "types": [ + { + "name": "a", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": "a", + "kind": { + "type": 0 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t1", + "kind": { + "type": 1 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t2", + "kind": { + "handle": { + "borrow": 1 + } + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t3", + "kind": { + "handle": { + "borrow": 2 + } + }, + "owner": { + "interface": 1 + } + } + ], + "packages": [ + { + "name": "some:dep", + "interfaces": { + "foo": 0 + }, + "worlds": {} + }, + { + "name": "foo:bar", + "interfaces": { + "foo": 1 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/name-both-resource-and-type/deps/dep/foo.wit b/crates/wit-parser/tests/ui/name-both-resource-and-type/deps/dep/foo.wit new file mode 100644 index 0000000000..f31a0d22e8 --- /dev/null +++ b/crates/wit-parser/tests/ui/name-both-resource-and-type/deps/dep/foo.wit @@ -0,0 +1,5 @@ +package some:dep; + +interface foo { + resource a; +} diff --git a/crates/wit-parser/tests/ui/name-both-resource-and-type/foo.wit b/crates/wit-parser/tests/ui/name-both-resource-and-type/foo.wit new file mode 100644 index 0000000000..2fa039c1e0 --- /dev/null +++ b/crates/wit-parser/tests/ui/name-both-resource-and-type/foo.wit @@ -0,0 +1,9 @@ +package foo:bar; + +interface foo { + use some:dep/foo.{a}; + + type t1 = a; + type t2 = borrow; + type t3 = borrow; +} diff --git a/crates/wit-parser/tests/ui/package-syntax1.wit b/crates/wit-parser/tests/ui/package-syntax1.wit new file mode 100644 index 0000000000..70773a71e0 --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax1.wit @@ -0,0 +1 @@ +package foo:foo; diff --git a/crates/wit-parser/tests/ui/package-syntax1.wit.json b/crates/wit-parser/tests/ui/package-syntax1.wit.json new file mode 100644 index 0000000000..80af0cbb3b --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax1.wit.json @@ -0,0 +1,12 @@ +{ + "worlds": [], + "interfaces": [], + "types": [], + "packages": [ + { + "name": "foo:foo", + "interfaces": {}, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/package-syntax3.wit b/crates/wit-parser/tests/ui/package-syntax3.wit new file mode 100644 index 0000000000..23698f668d --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax3.wit @@ -0,0 +1 @@ +package foo:bar; diff --git a/crates/wit-parser/tests/ui/package-syntax3.wit.json b/crates/wit-parser/tests/ui/package-syntax3.wit.json new file mode 100644 index 0000000000..e0323c511b --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax3.wit.json @@ -0,0 +1,12 @@ +{ + "worlds": [], + "interfaces": [], + "types": [], + "packages": [ + { + "name": "foo:bar", + "interfaces": {}, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/package-syntax4.wit b/crates/wit-parser/tests/ui/package-syntax4.wit new file mode 100644 index 0000000000..c950b40d44 --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax4.wit @@ -0,0 +1 @@ +package foo:bar@2.0.0; diff --git a/crates/wit-parser/tests/ui/package-syntax4.wit.json b/crates/wit-parser/tests/ui/package-syntax4.wit.json new file mode 100644 index 0000000000..7bacc86f03 --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax4.wit.json @@ -0,0 +1,12 @@ +{ + "worlds": [], + "interfaces": [], + "types": [], + "packages": [ + { + "name": "foo:bar@2.0.0", + "interfaces": {}, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit b/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit new file mode 100644 index 0000000000..82b6c1c553 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit @@ -0,0 +1,6 @@ +// parse-fail +package foo:bar; + +interface foo { + type foo = bar; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit.result b/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit.result new file mode 100644 index 0000000000..1561247d1f --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit.result @@ -0,0 +1,5 @@ +type `bar` does not exist + --> tests/ui/parse-fail/alias-no-type.wit:5:14 + | + 5 | type foo = bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/async.wit.result b/crates/wit-parser/tests/ui/parse-fail/async.wit.result new file mode 100644 index 0000000000..c206072870 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/async.wit.result @@ -0,0 +1,5 @@ +expected keyword `func`, found eof + --> tests/ui/parse-fail/async.wit:3:1 + | + 3 | + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/async1.wit.result b/crates/wit-parser/tests/ui/parse-fail/async1.wit.result new file mode 100644 index 0000000000..caab404761 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/async1.wit.result @@ -0,0 +1,5 @@ +expected keyword `func`, found '(' + --> tests/ui/parse-fail/async1.wit:2:9 + | + 2 | a: async() + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-function.wit b/crates/wit-parser/tests/ui/parse-fail/bad-function.wit new file mode 100644 index 0000000000..76f0a6db6e --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-function.wit @@ -0,0 +1,7 @@ +// parse-fail + +package foo:foo; + +interface foo { + x: func(param: nonexistent); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-function.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-function.wit.result new file mode 100644 index 0000000000..a2c71f1785 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-function.wit.result @@ -0,0 +1,5 @@ +name `nonexistent` is not defined + --> tests/ui/parse-fail/bad-function.wit:6:18 + | + 6 | x: func(param: nonexistent); + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit b/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit new file mode 100644 index 0000000000..a455c8c916 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit @@ -0,0 +1,7 @@ +// parse-fail + +package foo:foo; + +interface foo { + x: func() -> nonexistent; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit.result new file mode 100644 index 0000000000..5cd183197e --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit.result @@ -0,0 +1,5 @@ +name `nonexistent` is not defined + --> tests/ui/parse-fail/bad-function2.wit:6:16 + | + 6 | x: func() -> nonexistent; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-include1.wit b/crates/wit-parser/tests/ui/parse-fail/bad-include1.wit new file mode 100644 index 0000000000..7d71497ab0 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-include1.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo { + include non-existance; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-include1.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-include1.wit.result new file mode 100644 index 0000000000..d4c634eaf4 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-include1.wit.result @@ -0,0 +1,5 @@ +interface or world `non-existance` not found in package + --> tests/ui/parse-fail/bad-include1.wit:4:11 + | + 4 | include non-existance; + | ^------------ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-include2.wit b/crates/wit-parser/tests/ui/parse-fail/bad-include2.wit new file mode 100644 index 0000000000..acde145093 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-include2.wit @@ -0,0 +1,9 @@ +package foo:foo; + +world bar { + include foo; +} + +world foo { + include bar; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-include2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-include2.wit.result new file mode 100644 index 0000000000..7ccd018090 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-include2.wit.result @@ -0,0 +1,5 @@ +interface or world `foo` depends on itself + --> tests/ui/parse-fail/bad-include2.wit:7:7 + | + 7 | world foo { + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-include3.wit b/crates/wit-parser/tests/ui/parse-fail/bad-include3.wit new file mode 100644 index 0000000000..a714cdd322 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-include3.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo { + include foo; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-include3.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-include3.wit.result new file mode 100644 index 0000000000..2ced2f6788 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-include3.wit.result @@ -0,0 +1,5 @@ +interface or world `foo` depends on itself + --> tests/ui/parse-fail/bad-include3.wit:3:7 + | + 3 | world foo { + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list.wit new file mode 100644 index 0000000000..e3aca6b984 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-list.wit @@ -0,0 +1,7 @@ +// parse-fail + +interface foo { + type x = list', found keyword `type` + --> tests/ui/parse-fail/bad-list.wit:6:3 + | + 6 | type y = u32 + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result new file mode 100644 index 0000000000..85cc50ed99 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/bad-pkg1 + +Caused by: + interface or world `nonexistent` not found in package + --> tests/ui/parse-fail/bad-pkg1/root.wit:4:7 + | + 4 | use nonexistent.{}; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg1/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1/root.wit new file mode 100644 index 0000000000..aca5796435 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1/root.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface foo { + use nonexistent.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result new file mode 100644 index 0000000000..57f45a0779 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result @@ -0,0 +1,5 @@ +interface not found in package + --> tests/ui/parse-fail/bad-pkg2/root.wit:4:15 + | + 4 | use foo:bar/nonexistent.{}; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/deps/bar/empty.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/deps/bar/empty.wit new file mode 100644 index 0000000000..23698f668d --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/deps/bar/empty.wit @@ -0,0 +1 @@ +package foo:bar; diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/root.wit new file mode 100644 index 0000000000..2247dd5031 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/root.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface foo { + use foo:bar/nonexistent.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result new file mode 100644 index 0000000000..edcb594776 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result @@ -0,0 +1,5 @@ +interface not found in package + --> tests/ui/parse-fail/bad-pkg3/root.wit:4:15 + | + 4 | use foo:bar/baz.{}; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/.gitkeep b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/baz.wit new file mode 100644 index 0000000000..45e07c7328 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/baz.wit @@ -0,0 +1,2 @@ +package foo:bar; +world baz {} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/root.wit new file mode 100644 index 0000000000..cb1bb28a34 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/root.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface foo { + use foo:bar/baz.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result new file mode 100644 index 0000000000..11c42ac812 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result @@ -0,0 +1,5 @@ +type `a-name` not defined in interface + --> tests/ui/parse-fail/bad-pkg4/root.wit:3:20 + | + 3 | use foo:bar/baz.{a-name}; + | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/.gitkeep b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/baz.wit new file mode 100644 index 0000000000..bdad212a80 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/baz.wit @@ -0,0 +1,4 @@ +package foo:bar; +interface baz { + a-name: func(); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/root.wit new file mode 100644 index 0000000000..f4ff29fd71 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/root.wit @@ -0,0 +1,4 @@ +package foo:foo; +interface foo { + use foo:bar/baz.{a-name}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result new file mode 100644 index 0000000000..15a04b26e2 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result @@ -0,0 +1,5 @@ +type `nonexistent` not defined in interface + --> tests/ui/parse-fail/bad-pkg5/root.wit:3:20 + | + 3 | use foo:bar/baz.{nonexistent}; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/.gitkeep b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/baz.wit new file mode 100644 index 0000000000..2c27cd343a --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/baz.wit @@ -0,0 +1,3 @@ +package foo:bar; +interface baz { +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/root.wit new file mode 100644 index 0000000000..df36bac599 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/root.wit @@ -0,0 +1,4 @@ +package foo:foo; +interface foo { + use foo:bar/baz.{nonexistent}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result new file mode 100644 index 0000000000..40cf6058f5 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result @@ -0,0 +1,5 @@ +failed to find package `foo:bar` in `deps` directory + --> tests/ui/parse-fail/bad-pkg6/root.wit:3:7 + | + 3 | use foo:bar/baz.{}; + | ^------ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/.gitkeep b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/baz.wit new file mode 100644 index 0000000000..f8364b63ce --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/baz.wit @@ -0,0 +1,4 @@ +package foo:baz; + +interface bar {} + diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/root.wit new file mode 100644 index 0000000000..26e60b95e2 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/root.wit @@ -0,0 +1,4 @@ +package foo:foo; +interface foo { + use foo:bar/baz.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource1.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource1.wit new file mode 100644 index 0000000000..d3a4155fbf --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource1.wit @@ -0,0 +1,5 @@ +package foo:bar; + +interface foo { + type t = borrow; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource1.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource1.wit.result new file mode 100644 index 0000000000..2d47c39d00 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource1.wit.result @@ -0,0 +1,5 @@ +expected an identifier or string, found keyword `u32` + --> tests/ui/parse-fail/bad-resource1.wit:4:19 + | + 4 | type t = borrow; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource10.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource10.wit new file mode 100644 index 0000000000..20b0b36f4c --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource10.wit @@ -0,0 +1,5 @@ +package foo:bar; + +interface foo { + type t = own; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource10.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource10.wit.result new file mode 100644 index 0000000000..88ade63e91 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource10.wit.result @@ -0,0 +1,5 @@ +expected an identifier or string, found keyword `u32` + --> tests/ui/parse-fail/bad-resource10.wit:4:16 + | + 4 | type t = own; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource11.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource11.wit new file mode 100644 index 0000000000..acbdb13822 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource11.wit @@ -0,0 +1,5 @@ +package foo:bar; + +interface foo { + type t = own; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource11.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource11.wit.result new file mode 100644 index 0000000000..0b1eb7ee99 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource11.wit.result @@ -0,0 +1,5 @@ +type `foo` does not exist + --> tests/ui/parse-fail/bad-resource11.wit:4:16 + | + 4 | type t = own; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource12.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource12.wit new file mode 100644 index 0000000000..c06fe307af --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource12.wit @@ -0,0 +1,6 @@ +package foo:bar; + +interface foo { + foo: func(); + type t = own; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource12.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource12.wit.result new file mode 100644 index 0000000000..9b8f59b14b --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource12.wit.result @@ -0,0 +1,5 @@ +type `foo` does not exist + --> tests/ui/parse-fail/bad-resource12.wit:5:16 + | + 5 | type t = own; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource13.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource13.wit new file mode 100644 index 0000000000..28c4fe3344 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource13.wit @@ -0,0 +1,6 @@ +package foo:bar; + +interface foo { + type foo = u32; + type t = own; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource13.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource13.wit.result new file mode 100644 index 0000000000..889697a3be --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource13.wit.result @@ -0,0 +1,5 @@ +type `foo` used in a handle must be a resource + --> tests/ui/parse-fail/bad-resource13.wit:5:16 + | + 5 | type t = own; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource14.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource14.wit new file mode 100644 index 0000000000..2580afecc1 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource14.wit @@ -0,0 +1,7 @@ +package foo:bar; + +interface foo { + resource a {} + type t = own; + type b = own; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource14.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource14.wit.result new file mode 100644 index 0000000000..93fea21a32 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource14.wit.result @@ -0,0 +1,5 @@ +type `t` used in a handle must be a resource + --> tests/ui/parse-fail/bad-resource14.wit:6:16 + | + 6 | type b = own; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource15.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource15.wit.result new file mode 100644 index 0000000000..5e840e31fc --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource15.wit.result @@ -0,0 +1,5 @@ +type used in a handle must be a resource + --> tests/ui/parse-fail/bad-resource15/foo.wit:6:16 + | + 6 | type t = own; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource15/deps/foo/foo.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource15/deps/foo/foo.wit new file mode 100644 index 0000000000..42ef387358 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource15/deps/foo/foo.wit @@ -0,0 +1,5 @@ +package some:dep; + +interface foo { + type r = u32; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource15/foo.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource15/foo.wit new file mode 100644 index 0000000000..030dabab58 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource15/foo.wit @@ -0,0 +1,7 @@ +package foo:bar; + +interface foo { + use some:dep/foo.{r}; + + type t = own; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit new file mode 100644 index 0000000000..4c5e891783 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit @@ -0,0 +1,5 @@ +package foo:bar; + +interface foo { + type t = borrow; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit.result new file mode 100644 index 0000000000..21993b5953 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit.result @@ -0,0 +1,5 @@ +type `foo` does not exist + --> tests/ui/parse-fail/bad-resource2.wit:4:19 + | + 4 | type t = borrow; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource3.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource3.wit new file mode 100644 index 0000000000..ba1083e3ea --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource3.wit @@ -0,0 +1,6 @@ +package foo:bar; + +interface foo { + foo: func(); + type t = borrow; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource3.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource3.wit.result new file mode 100644 index 0000000000..747293aa3f --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource3.wit.result @@ -0,0 +1,5 @@ +type `foo` does not exist + --> tests/ui/parse-fail/bad-resource3.wit:5:19 + | + 5 | type t = borrow; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource4.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource4.wit new file mode 100644 index 0000000000..52bc9ddb56 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource4.wit @@ -0,0 +1,6 @@ +package foo:bar; + +interface foo { + type foo = u32; + type t = borrow; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource4.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource4.wit.result new file mode 100644 index 0000000000..2a47f48b7f --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource4.wit.result @@ -0,0 +1,5 @@ +type `foo` used in a handle must be a resource + --> tests/ui/parse-fail/bad-resource4.wit:5:19 + | + 5 | type t = borrow; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource5.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource5.wit new file mode 100644 index 0000000000..757be29a1b --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource5.wit @@ -0,0 +1,7 @@ +package foo:bar; + +interface foo { + resource a {} + type t = borrow; + type b = borrow; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource5.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource5.wit.result new file mode 100644 index 0000000000..836fd4e2d2 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource5.wit.result @@ -0,0 +1,5 @@ +type `t` used in a handle must be a resource + --> tests/ui/parse-fail/bad-resource5.wit:6:19 + | + 6 | type b = borrow; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource6.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource6.wit new file mode 100644 index 0000000000..8c4c9718a6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource6.wit @@ -0,0 +1,7 @@ +package foo:bar; + +interface foo { + resource a { + constructor() -> u32; + } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource6.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource6.wit.result new file mode 100644 index 0000000000..bd561a41f5 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource6.wit.result @@ -0,0 +1,5 @@ +expected ';', found `->` + --> tests/ui/parse-fail/bad-resource6.wit:5:19 + | + 5 | constructor() -> u32; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource7.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource7.wit new file mode 100644 index 0000000000..86a9ad2abc --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource7.wit @@ -0,0 +1,8 @@ +package foo:bar; + +interface foo { + resource a { + constructor(); + constructor(); + } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource7.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource7.wit.result new file mode 100644 index 0000000000..b201ca8c72 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource7.wit.result @@ -0,0 +1,5 @@ +duplicate constructors + --> tests/ui/parse-fail/bad-resource7.wit:6:5 + | + 6 | constructor(); + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource8.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource8.wit new file mode 100644 index 0000000000..b0752d3386 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource8.wit @@ -0,0 +1,8 @@ +package foo:bar; + +interface foo { + resource a { + a: func(); + a: static func(); + } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource8.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource8.wit.result new file mode 100644 index 0000000000..85179e7963 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource8.wit.result @@ -0,0 +1,5 @@ +duplicate function name `a` + --> tests/ui/parse-fail/bad-resource8.wit:6:5 + | + 6 | a: static func(); + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource9.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource9.wit new file mode 100644 index 0000000000..af1530d325 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource9.wit @@ -0,0 +1,7 @@ +package foo:bar; + +interface foo { + resource a { + interface foo {} + } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource9.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource9.wit.result new file mode 100644 index 0000000000..368808cb07 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource9.wit.result @@ -0,0 +1,5 @@ +expected `constructor` or identifier, found keyword `interface` + --> tests/ui/parse-fail/bad-resource9.wit:5:5 + | + 5 | interface foo {} + | ^-------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit b/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit new file mode 100644 index 0000000000..dac0cbeb21 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit @@ -0,0 +1,5 @@ +package foo:foo; +world a { + type a = u32; + import a: func(); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit.result new file mode 100644 index 0000000000..1c23f517de --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit.result @@ -0,0 +1,5 @@ +import `a` conflicts with prior import of same name + --> tests/ui/parse-fail/bad-world-type1.wit:4:10 + | + 4 | import a: func(); + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result b/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result new file mode 100644 index 0000000000..5a6fe46efb --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/conflicting-package + +Caused by: + package identifier `foo:b` does not match previous package name of `foo:a` + --> tests/ui/parse-fail/conflicting-package/b.wit:1:9 + | + 1 | package foo:b; + | ^---- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/conflicting-package/a.wit b/crates/wit-parser/tests/ui/parse-fail/conflicting-package/a.wit new file mode 100644 index 0000000000..767bedb490 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/conflicting-package/a.wit @@ -0,0 +1 @@ +package foo:a; diff --git a/crates/wit-parser/tests/ui/parse-fail/conflicting-package/b.wit b/crates/wit-parser/tests/ui/parse-fail/conflicting-package/b.wit new file mode 100644 index 0000000000..fefd9481da --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/conflicting-package/b.wit @@ -0,0 +1 @@ +package foo:b; diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle.wit b/crates/wit-parser/tests/ui/parse-fail/cycle.wit new file mode 100644 index 0000000000..993b0a5248 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle.wit @@ -0,0 +1,6 @@ +// parse-fail +package foo:foo; + +interface foo { + type foo = foo; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle.wit.result new file mode 100644 index 0000000000..21132ace1d --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle.wit.result @@ -0,0 +1,5 @@ +type `foo` depends on itself + --> tests/ui/parse-fail/cycle.wit:5:14 + | + 5 | type foo = foo; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle2.wit b/crates/wit-parser/tests/ui/parse-fail/cycle2.wit new file mode 100644 index 0000000000..12ad81a80c --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle2.wit @@ -0,0 +1,7 @@ +// parse-fail +package foo:foo; + +interface foo { + type foo = bar; + type bar = foo; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle2.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle2.wit.result new file mode 100644 index 0000000000..c0f10ceca0 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle2.wit.result @@ -0,0 +1,5 @@ +type `bar` depends on itself + --> tests/ui/parse-fail/cycle2.wit:5:14 + | + 5 | type foo = bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle3.wit b/crates/wit-parser/tests/ui/parse-fail/cycle3.wit new file mode 100644 index 0000000000..4762af123f --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle3.wit @@ -0,0 +1,7 @@ +// parse-fail +package foo:foo; + +interface foo { + type foo = bar; + type bar = option; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle3.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle3.wit.result new file mode 100644 index 0000000000..76027ea984 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle3.wit.result @@ -0,0 +1,5 @@ +type `bar` depends on itself + --> tests/ui/parse-fail/cycle3.wit:5:14 + | + 5 | type foo = bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle4.wit b/crates/wit-parser/tests/ui/parse-fail/cycle4.wit new file mode 100644 index 0000000000..353e96c681 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle4.wit @@ -0,0 +1,7 @@ +// parse-fail +package foo:foo; + +interface foo { + type foo = bar; + record bar { x: foo } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle4.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle4.wit.result new file mode 100644 index 0000000000..8fe9ae39da --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle4.wit.result @@ -0,0 +1,5 @@ +type `bar` depends on itself + --> tests/ui/parse-fail/cycle4.wit:5:14 + | + 5 | type foo = bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle5.wit b/crates/wit-parser/tests/ui/parse-fail/cycle5.wit new file mode 100644 index 0000000000..5a4f615dc8 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle5.wit @@ -0,0 +1,7 @@ +// parse-fail +package foo:foo; + +interface foo { + type foo = bar; + type bar = list; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle5.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle5.wit.result new file mode 100644 index 0000000000..cf66c72fae --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/cycle5.wit.result @@ -0,0 +1,5 @@ +type `bar` depends on itself + --> tests/ui/parse-fail/cycle5.wit:5:14 + | + 5 | type foo = bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/dangling-type.wit b/crates/wit-parser/tests/ui/parse-fail/dangling-type.wit new file mode 100644 index 0000000000..6fb5bb3762 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/dangling-type.wit @@ -0,0 +1,5 @@ +// parse-fail + +interface foo { + type + diff --git a/crates/wit-parser/tests/ui/parse-fail/dangling-type.wit.result b/crates/wit-parser/tests/ui/parse-fail/dangling-type.wit.result new file mode 100644 index 0000000000..437394d856 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/dangling-type.wit.result @@ -0,0 +1,5 @@ +expected an identifier or string, found eof + --> tests/ui/parse-fail/dangling-type.wit:6:1 + | + 6 | + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-function-params.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-function-params.wit new file mode 100644 index 0000000000..ea39d11ddc --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-function-params.wit @@ -0,0 +1,7 @@ +// parse-fail + +package foo:foo; + +interface foo { + foo: func(foo: u32, foo: u64); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-function-params.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-function-params.wit.result new file mode 100644 index 0000000000..2cd3ebab69 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-function-params.wit.result @@ -0,0 +1,5 @@ +param `foo` is defined more than once + --> tests/ui/parse-fail/duplicate-function-params.wit:6:23 + | + 6 | foo: func(foo: u32, foo: u64); + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit new file mode 100644 index 0000000000..7d119c0952 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit @@ -0,0 +1,8 @@ +// parse-fail + +package foo:foo; + +interface foo { + foo: func(); + foo: func(); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit.result new file mode 100644 index 0000000000..7cecd5647b --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit.result @@ -0,0 +1,5 @@ +name `foo` is defined more than once + --> tests/ui/parse-fail/duplicate-functions.wit:7:3 + | + 7 | foo: func(); + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit new file mode 100644 index 0000000000..887d83d682 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit @@ -0,0 +1,6 @@ +// parse-fail + +package foo:foo; + +interface foo {} +interface foo {} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit.result new file mode 100644 index 0000000000..f6351f30e1 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit.result @@ -0,0 +1,5 @@ +duplicate item named `foo` + --> tests/ui/parse-fail/duplicate-interface.wit:6:11 + | + 6 | interface foo {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result new file mode 100644 index 0000000000..7ed7ec2b29 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/duplicate-interface2 + +Caused by: + duplicate item named `foo` + --> tests/ui/parse-fail/duplicate-interface2/foo2.wit:3:11 + | + 3 | interface foo {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo.wit new file mode 100644 index 0000000000..21bf4083a7 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo.wit @@ -0,0 +1,3 @@ +package foo:foo; + +interface foo {} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo2.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo2.wit new file mode 100644 index 0000000000..21bf4083a7 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo2.wit @@ -0,0 +1,3 @@ +package foo:foo; + +interface foo {} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit new file mode 100644 index 0000000000..2ca1b228d9 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit @@ -0,0 +1,7 @@ +// parse-fail +package foo:foo; + +interface foo { + type foo = s32; + type foo = s32; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit.result new file mode 100644 index 0000000000..45731a1719 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit.result @@ -0,0 +1,5 @@ +name `foo` is defined more than once + --> tests/ui/parse-fail/duplicate-type.wit:6:8 + | + 6 | type foo = s32; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit b/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit new file mode 100644 index 0000000000..6e920db0bd --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit @@ -0,0 +1,6 @@ +// parse-fail +package foo:foo; + +interface foo { + enum t {} +} diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit.result b/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit.result new file mode 100644 index 0000000000..894a82a00d --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit.result @@ -0,0 +1,5 @@ +empty enum + --> tests/ui/parse-fail/empty-enum.wit:5:8 + | + 5 | enum t {} + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit b/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit new file mode 100644 index 0000000000..ecd9ba78aa --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit @@ -0,0 +1,6 @@ +// parse-fail +package foo:foo; + +interface foo { + variant t {} +} diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit.result b/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit.result new file mode 100644 index 0000000000..9c42ba4c0f --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit.result @@ -0,0 +1,5 @@ +empty variant + --> tests/ui/parse-fail/empty-variant1.wit:5:11 + | + 5 | variant t {} + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/export-twice.wit b/crates/wit-parser/tests/ui/parse-fail/export-twice.wit new file mode 100644 index 0000000000..45ad06baa2 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/export-twice.wit @@ -0,0 +1,8 @@ +package foo:foo; + +interface foo {} + +world bar { + export foo; + export foo; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/export-twice.wit.result b/crates/wit-parser/tests/ui/parse-fail/export-twice.wit.result new file mode 100644 index 0000000000..ea6d0ecd7c --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/export-twice.wit.result @@ -0,0 +1,5 @@ +interface cannot be exported more than once + --> tests/ui/parse-fail/export-twice.wit:7:10 + | + 7 | export foo; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export1.wit b/crates/wit-parser/tests/ui/parse-fail/import-and-export1.wit new file mode 100644 index 0000000000..c6f6dc78b2 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export1.wit @@ -0,0 +1,17 @@ +package foo:foo; +interface i1 { + type t = u32; +} +interface i2 { + use i1.{t}; +} +interface i3 { + use i2.{t}; +} + +world test { + import i1: interface {} + + export i1; + export i3; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export1.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-and-export1.wit.result new file mode 100644 index 0000000000..0726c2aa20 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export1.wit.result @@ -0,0 +1,5 @@ +interface transitively depends on an interface in incompatible ways + --> tests/ui/parse-fail/import-and-export1.wit:16:10 + | + 16 | export i3; + | ^- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export2.wit b/crates/wit-parser/tests/ui/parse-fail/import-and-export2.wit new file mode 100644 index 0000000000..8a744fc3d9 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export2.wit @@ -0,0 +1,18 @@ +package foo:foo; + +interface foo { + type t = u32; +} + +interface bar { + use foo.{t}; +} + +world baz { + export foo; + import bar; + export anon: interface { + use foo.{t}; + use bar.{t as t2}; + } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export2.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-and-export2.wit.result new file mode 100644 index 0000000000..85777bfc99 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export2.wit.result @@ -0,0 +1,5 @@ +interface transitively depends on an interface in incompatible ways + --> tests/ui/parse-fail/import-and-export2.wit:14:10 + | + 14 | export anon: interface { + | ^--- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export3.wit b/crates/wit-parser/tests/ui/parse-fail/import-and-export3.wit new file mode 100644 index 0000000000..c7c30e6391 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export3.wit @@ -0,0 +1,37 @@ +package foo:foo; + +interface foo {} +interface bar {} + +world the-world { + import foo; + import bar; + import baz: interface { + foo: func(); + } + export foo; + export bar; + export baz2: interface { + foo: func(); + } +} + +world a-different-world { + import foo; +} + +interface i1 { + type t = u32; +} +interface i2 { + use i1.{t}; +} +interface i3 { + use i2.{t}; +} + +world test { + import i3; + export i1; + export i3; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export3.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-and-export3.wit.result new file mode 100644 index 0000000000..7e20ce59fb --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export3.wit.result @@ -0,0 +1,5 @@ +interface transitively depends on an interface in incompatible ways + --> tests/ui/parse-fail/import-and-export3.wit:36:10 + | + 36 | export i3; + | ^- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export4.wit b/crates/wit-parser/tests/ui/parse-fail/import-and-export4.wit new file mode 100644 index 0000000000..cc17c3d03b --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export4.wit @@ -0,0 +1,44 @@ +package foo:foo; + + +world union-world { + include test; + include a-different-world; + include the-world; +} + +interface foo {} +interface bar {} + +world the-world { + import foo; + import bar; + import baz: interface { + foo: func(); + } + export foo; + export bar; + export baz2: interface { + foo: func(); + } +} + +world a-different-world { + import foo; +} + +interface i1 { + type t = u32; +} +interface i2 { + use i1.{t}; +} +interface i3 { + use i2.{t}; +} + +world test { + import i3; + export i1; + export i3; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export4.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-and-export4.wit.result new file mode 100644 index 0000000000..b159027354 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export4.wit.result @@ -0,0 +1,5 @@ +interface transitively depends on an interface in incompatible ways + --> tests/ui/parse-fail/import-and-export4.wit:43:10 + | + 43 | export i3; + | ^- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export5.wit b/crates/wit-parser/tests/ui/parse-fail/import-and-export5.wit new file mode 100644 index 0000000000..2c75355b52 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export5.wit @@ -0,0 +1,18 @@ +package foo:bar; + +interface a { + record x { + } +} + +interface b { + use a.{x}; +} + +world w { + export anon: interface { + use b.{x as x2}; + use a.{x}; + } + export a; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-and-export5.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-and-export5.wit.result new file mode 100644 index 0000000000..6e86b74cc2 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-and-export5.wit.result @@ -0,0 +1,5 @@ +interface transitively depends on an interface in incompatible ways + --> tests/ui/parse-fail/import-and-export5.wit:13:10 + | + 13 | export anon: interface { + | ^--- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit new file mode 100644 index 0000000000..49426de292 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit @@ -0,0 +1,5 @@ +package foo:foo; +world foo { + import a: func(); + export a: func(); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit.result new file mode 100644 index 0000000000..16fae36180 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit.result @@ -0,0 +1,5 @@ +export `a` conflicts with prior import of same name + --> tests/ui/parse-fail/import-export-overlap1.wit:4:10 + | + 4 | export a: func(); + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit new file mode 100644 index 0000000000..f25dda1b9a --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit @@ -0,0 +1,5 @@ +package foo:foo; +world foo { + import a: func(); + export a: interface {} +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit.result new file mode 100644 index 0000000000..88ca1c1997 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit.result @@ -0,0 +1,5 @@ +export `a` conflicts with prior import of same name + --> tests/ui/parse-fail/import-export-overlap2.wit:4:10 + | + 4 | export a: interface {} + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-twice.wit b/crates/wit-parser/tests/ui/parse-fail/import-twice.wit new file mode 100644 index 0000000000..78f380d42b --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-twice.wit @@ -0,0 +1,8 @@ +package foo:foo; + +interface foo {} + +world bar { + import foo; + import foo; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-twice.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-twice.wit.result new file mode 100644 index 0000000000..d369190755 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-twice.wit.result @@ -0,0 +1,5 @@ +interface cannot be imported more than once + --> tests/ui/parse-fail/import-twice.wit:7:10 + | + 7 | import foo; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/include-cycle.wit b/crates/wit-parser/tests/ui/parse-fail/include-cycle.wit new file mode 100644 index 0000000000..6a1bf1cdfe --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-cycle.wit @@ -0,0 +1,9 @@ +package foo:foo; + +world a { + include b; +} + +world b { + include a; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/include-cycle.wit.result b/crates/wit-parser/tests/ui/parse-fail/include-cycle.wit.result new file mode 100644 index 0000000000..a89a1fc99c --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-cycle.wit.result @@ -0,0 +1,5 @@ +interface or world `b` depends on itself + --> tests/ui/parse-fail/include-cycle.wit:7:7 + | + 7 | world b { + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/include-foreign.wit.result b/crates/wit-parser/tests/ui/parse-fail/include-foreign.wit.result new file mode 100644 index 0000000000..990f53a8ad --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-foreign.wit.result @@ -0,0 +1,5 @@ +world not found in package + --> tests/ui/parse-fail/include-foreign/root.wit:4:19 + | + 4 | include foo:bar/bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/include-foreign/deps/bar/empty.wit b/crates/wit-parser/tests/ui/parse-fail/include-foreign/deps/bar/empty.wit new file mode 100644 index 0000000000..e3016a3f8c --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-foreign/deps/bar/empty.wit @@ -0,0 +1,3 @@ +package foo:bar; + +interface bar {} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/include-foreign/root.wit b/crates/wit-parser/tests/ui/parse-fail/include-foreign/root.wit new file mode 100644 index 0000000000..3a26f45626 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-foreign/root.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo { + include foo:bar/bar; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/include-with-id.wit b/crates/wit-parser/tests/ui/parse-fail/include-with-id.wit new file mode 100644 index 0000000000..20f8f75837 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-with-id.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface foo {} + +world a { + import foo; +} + +world b { + include a with { foo:foo/foo as foo2 } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/include-with-id.wit.result b/crates/wit-parser/tests/ui/parse-fail/include-with-id.wit.result new file mode 100644 index 0000000000..587e9a66b3 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-with-id.wit.result @@ -0,0 +1,5 @@ +expected keyword `as`, found ':' + --> tests/ui/parse-fail/include-with-id.wit:10:25 + | + 10 | include a with { foo:foo/foo as foo2 } + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/include-with-on-id.wit b/crates/wit-parser/tests/ui/parse-fail/include-with-on-id.wit new file mode 100644 index 0000000000..fc39f548ad --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-with-on-id.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface foo {} + +world a { + import foo; +} + +world b { + include a with { foo as foo2 } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/include-with-on-id.wit.result b/crates/wit-parser/tests/ui/parse-fail/include-with-on-id.wit.result new file mode 100644 index 0000000000..732f000b22 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/include-with-on-id.wit.result @@ -0,0 +1,5 @@ +no import or export kebab-name `foo`. Note that an ID does not support renaming + --> tests/ui/parse-fail/include-with-on-id.wit:10:13 + | + 10 | include a with { foo as foo2 } + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-toplevel.wit b/crates/wit-parser/tests/ui/parse-fail/invalid-toplevel.wit new file mode 100644 index 0000000000..8b627c0522 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-toplevel.wit @@ -0,0 +1,5 @@ +// parse-fail + +interface foo { + abcd +} diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-toplevel.wit.result b/crates/wit-parser/tests/ui/parse-fail/invalid-toplevel.wit.result new file mode 100644 index 0000000000..8d1d7a11ba --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-toplevel.wit.result @@ -0,0 +1,5 @@ +expected ':', found '}' + --> tests/ui/parse-fail/invalid-toplevel.wit:5:1 + | + 5 | } + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit new file mode 100644 index 0000000000..75dc2c3889 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit @@ -0,0 +1,10 @@ +package foo:foo; + +interface foo { + x: func(); + + record foo { + // TODO: this should have a better error message referring to `x: func()` + a: x + } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit.result b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit.result new file mode 100644 index 0000000000..d7861f14f4 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit.result @@ -0,0 +1,5 @@ +type `x` does not exist + --> tests/ui/parse-fail/invalid-type-reference.wit:8:8 + | + 8 | a: x + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit new file mode 100644 index 0000000000..1ebdcbdbd9 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit @@ -0,0 +1,6 @@ +package foo:foo; + +interface foo { + x: func(); + y: func() -> x; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit.result b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit.result new file mode 100644 index 0000000000..9e8c0592f9 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit.result @@ -0,0 +1,5 @@ +cannot use function `x` as a type + --> tests/ui/parse-fail/invalid-type-reference2.wit:5:16 + | + 5 | y: func() -> x; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/kebab-name-include-not-found.wit b/crates/wit-parser/tests/ui/parse-fail/kebab-name-include-not-found.wit new file mode 100644 index 0000000000..23f093c8bd --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/kebab-name-include-not-found.wit @@ -0,0 +1,8 @@ +package foo:foo; + +world foo { import a: func(); } +world bar { import a: func(); } +world baz { + include foo with { b1 as b2 } + include bar with { a as b } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/kebab-name-include-not-found.wit.result b/crates/wit-parser/tests/ui/parse-fail/kebab-name-include-not-found.wit.result new file mode 100644 index 0000000000..5416037a24 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/kebab-name-include-not-found.wit.result @@ -0,0 +1,5 @@ +no import or export kebab-name `b1`. Note that an ID does not support renaming + --> tests/ui/parse-fail/kebab-name-include-not-found.wit:6:13 + | + 6 | include foo with { b1 as b2 } + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/kebab-name-include.wit b/crates/wit-parser/tests/ui/parse-fail/kebab-name-include.wit new file mode 100644 index 0000000000..abbd073ab3 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/kebab-name-include.wit @@ -0,0 +1,8 @@ +package foo:foo; + +world foo { import a: func(); } +world bar { import a: func(); } +world baz { + include foo; + include bar; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/kebab-name-include.wit.result b/crates/wit-parser/tests/ui/parse-fail/kebab-name-include.wit.result new file mode 100644 index 0000000000..045c4fad26 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/kebab-name-include.wit.result @@ -0,0 +1,5 @@ +import of `a` shadows previously imported items + --> tests/ui/parse-fail/kebab-name-include.wit:7:13 + | + 7 | include bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/keyword.wit b/crates/wit-parser/tests/ui/parse-fail/keyword.wit new file mode 100644 index 0000000000..8b19bf97e5 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/keyword.wit @@ -0,0 +1,5 @@ +// parse-fail + +interface kw { + type option = u32 +} diff --git a/crates/wit-parser/tests/ui/parse-fail/keyword.wit.result b/crates/wit-parser/tests/ui/parse-fail/keyword.wit.result new file mode 100644 index 0000000000..5025394cd3 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/keyword.wit.result @@ -0,0 +1,5 @@ +expected an identifier or string, found keyword `option` + --> tests/ui/parse-fail/keyword.wit:4:8 + | + 4 | type option = u32 + | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/missing-package.wit b/crates/wit-parser/tests/ui/parse-fail/missing-package.wit new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-parser/tests/ui/parse-fail/missing-package.wit.result b/crates/wit-parser/tests/ui/parse-fail/missing-package.wit.result new file mode 100644 index 0000000000..d25b316c26 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/missing-package.wit.result @@ -0,0 +1 @@ +no `package` header was found in any WIT file for this package \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs.wit.result b/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs.wit.result new file mode 100644 index 0000000000..e60c1b492c --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/multiple-package-docs + +Caused by: + found doc comments on multiple 'package' items + --> tests/ui/parse-fail/multiple-package-docs/b.wit:1:1 + | + 1 | /// Multiple package docs, B + | ^--------------------------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs/a.wit b/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs/a.wit new file mode 100644 index 0000000000..0ee174b574 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs/a.wit @@ -0,0 +1,2 @@ +/// Multiple package docs, A; +package foo:foo; \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs/b.wit b/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs/b.wit new file mode 100644 index 0000000000..e3808b0241 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs/b.wit @@ -0,0 +1,2 @@ +/// Multiple package docs, B +package foo:foo; diff --git a/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result new file mode 100644 index 0000000000..9693caa78b --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/no-access-to-sibling-use + +Caused by: + interface or world `bar-renamed` does not exist + --> tests/ui/parse-fail/no-access-to-sibling-use/foo.wit:3:5 + | + 3 | use bar-renamed; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/bar.wit b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/bar.wit new file mode 100644 index 0000000000..1b75e6aac0 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/bar.wit @@ -0,0 +1 @@ +use bar as bar-renamed; diff --git a/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/foo.wit b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/foo.wit new file mode 100644 index 0000000000..7b3cf274dd --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/foo.wit @@ -0,0 +1,5 @@ +package foo:foo; + +use bar-renamed; + +interface bar {} diff --git a/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include.wit.result b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include.wit.result new file mode 100644 index 0000000000..ed8f228b25 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include.wit.result @@ -0,0 +1,5 @@ +world not found in package + --> tests/ui/parse-fail/non-existance-world-include/root.wit:4:19 + | + 4 | include foo:baz/non-existance; + | ^------------ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include/deps/bar/.gitkeep b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include/deps/bar/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include/deps/bar/baz.wit new file mode 100644 index 0000000000..f8364b63ce --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include/deps/bar/baz.wit @@ -0,0 +1,4 @@ +package foo:baz; + +interface bar {} + diff --git a/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include/root.wit b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include/root.wit new file mode 100644 index 0000000000..741318b8c6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include/root.wit @@ -0,0 +1,5 @@ +package foo:foo; + +world foo { + include foo:baz/non-existance; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result new file mode 100644 index 0000000000..d87b514871 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result @@ -0,0 +1,5 @@ +package depends on itself + --> tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit:3:7 + | + 3 | use foo:a1/foo.{}; + | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit new file mode 100644 index 0000000000..0fccfc5d0d --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit @@ -0,0 +1,4 @@ +package foo:a1; +interface foo { + use foo:a1/foo.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/root.wit new file mode 100644 index 0000000000..c66e1766c3 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/root.wit @@ -0,0 +1,4 @@ +package foo:foo; +interface foo { + use foo:a1/foo.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result new file mode 100644 index 0000000000..e45eec8350 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result @@ -0,0 +1,5 @@ +package depends on itself + --> tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit:3:7 + | + 3 | use foo:a2/foo.{}; + | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit new file mode 100644 index 0000000000..4a2b7122b6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit @@ -0,0 +1,4 @@ +package foo:a1; +interface foo { + use foo:a2/foo.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit new file mode 100644 index 0000000000..9e022eae47 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit @@ -0,0 +1,4 @@ +package foo:a2; +interface foo { + use foo:a1/foo.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/root.wit new file mode 100644 index 0000000000..105069dfc6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/root.wit @@ -0,0 +1,4 @@ +package foo:root; +interface foo { + use foo:a1/foo.{}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name.wit.result b/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name.wit.result new file mode 100644 index 0000000000..355be9b297 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name.wit.result @@ -0,0 +1,5 @@ +type used in a handle must be a resource + --> tests/ui/parse-fail/type-and-resource-same-name/foo.wit:7:20 + | + 7 | type t2 = borrow; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name/deps/dep/foo.wit b/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name/deps/dep/foo.wit new file mode 100644 index 0000000000..de2cc53b34 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name/deps/dep/foo.wit @@ -0,0 +1,5 @@ +package some:dep; + +interface foo { + type a = u32; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name/foo.wit b/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name/foo.wit new file mode 100644 index 0000000000..e09956f77d --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name/foo.wit @@ -0,0 +1,8 @@ +package foo:bar; + +interface foo { + use some:dep/foo.{a}; + + type t1 = a; + type t2 = borrow; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit b/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit new file mode 100644 index 0000000000..e0e12f28cd --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit @@ -0,0 +1,6 @@ +// parse-fail +package foo:foo; + +interface foo { + type foo = bar; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit.result b/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit.result new file mode 100644 index 0000000000..d070f9e381 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit.result @@ -0,0 +1,5 @@ +type `bar` does not exist + --> tests/ui/parse-fail/undefined-typed.wit:5:14 + | + 5 | type foo = bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/union-fuzz-2.wit b/crates/wit-parser/tests/ui/parse-fail/union-fuzz-2.wit new file mode 100644 index 0000000000..3d0e55b896 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/union-fuzz-2.wit @@ -0,0 +1,12 @@ +package foo:bar; + +world foo { + export foo: func() -> (%name2: float32); +} + + +world bar { + include foo; + + record foo {} +} diff --git a/crates/wit-parser/tests/ui/parse-fail/union-fuzz-2.wit.result b/crates/wit-parser/tests/ui/parse-fail/union-fuzz-2.wit.result new file mode 100644 index 0000000000..a2d50f62f4 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/union-fuzz-2.wit.result @@ -0,0 +1,5 @@ +import type `foo` conflicts with prior export of interface + --> tests/ui/parse-fail/union-fuzz-2.wit:11:12 + | + 11 | record foo {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit b/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit new file mode 100644 index 0000000000..dcdf4a4716 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit @@ -0,0 +1,7 @@ +// parse-fail + +package foo:foo; + +world foo { + import bar; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit.result b/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit.result new file mode 100644 index 0000000000..f03a3ed112 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit.result @@ -0,0 +1,5 @@ +interface or world `bar` does not exist + --> tests/ui/parse-fail/unknown-interface.wit:6:10 + | + 6 | import bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit new file mode 100644 index 0000000000..6b25224b43 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit @@ -0,0 +1,7 @@ +// parse-fail + +package foo:foo; + +world foo { + import foo; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit.result new file mode 100644 index 0000000000..ab2c851f19 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit.result @@ -0,0 +1,5 @@ +name `foo` is defined as a world, not an interface + --> tests/ui/parse-fail/unresolved-interface1.wit:6:10 + | + 6 | import foo; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit new file mode 100644 index 0000000000..3f74362c8a --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit @@ -0,0 +1,8 @@ +// parse-fail + +package foo:foo; + +world foo { + import bar; +} + diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit.result new file mode 100644 index 0000000000..aceeeaa7ee --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit.result @@ -0,0 +1,5 @@ +interface or world `bar` does not exist + --> tests/ui/parse-fail/unresolved-interface2.wit:6:10 + | + 6 | import bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit new file mode 100644 index 0000000000..98f2f45b01 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit @@ -0,0 +1,5 @@ +// parse-fail + +package foo:foo; + +use bar as foo; diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit.result new file mode 100644 index 0000000000..b8515dd20e --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit.result @@ -0,0 +1,5 @@ +interface or world `bar` does not exist + --> tests/ui/parse-fail/unresolved-interface3.wit:5:5 + | + 5 | use bar as foo; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit new file mode 100644 index 0000000000..35addea0e4 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit @@ -0,0 +1,7 @@ +// parse-fail + +package foo:foo; + +world foo { + import some:dependency/iface; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit.result new file mode 100644 index 0000000000..c93df981a5 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit.result @@ -0,0 +1,5 @@ +package not found + --> tests/ui/parse-fail/unresolved-interface4.wit:6:10 + | + 6 | import some:dependency/iface; + | ^-------------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit new file mode 100644 index 0000000000..cf69305ae1 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit @@ -0,0 +1,7 @@ +// parse-fail + +package foo:foo; + +interface foo { + use bar.{x}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit.result new file mode 100644 index 0000000000..d61301e4a1 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit.result @@ -0,0 +1,5 @@ +interface or world `bar` not found in package + --> tests/ui/parse-fail/unresolved-use1.wit:6:7 + | + 6 | use bar.{x}; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result new file mode 100644 index 0000000000..1ad83de299 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/unresolved-use10 + +Caused by: + name `thing` is not defined + --> tests/ui/parse-fail/unresolved-use10/bar.wit:4:12 + | + 4 | use foo.{thing}; + | ^---- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/bar.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/bar.wit new file mode 100644 index 0000000000..aee52cbf1d --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/bar.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface bar { + use foo.{thing}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/foo.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/foo.wit new file mode 100644 index 0000000000..849a1eb3c9 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/foo.wit @@ -0,0 +1,2 @@ +interface foo { +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit new file mode 100644 index 0000000000..e3e543bead --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit @@ -0,0 +1,10 @@ +// parse-fail + +package foo:foo; + +interface foo { + use bar.{x}; +} + +interface bar { +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit.result new file mode 100644 index 0000000000..51349921de --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit.result @@ -0,0 +1,5 @@ +name `x` is not defined + --> tests/ui/parse-fail/unresolved-use2.wit:6:12 + | + 6 | use bar.{x}; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit new file mode 100644 index 0000000000..38f3c12503 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit @@ -0,0 +1,11 @@ +// parse-fail + +package foo:foo; + +interface foo { + use bar.{x}; +} + +interface bar { + x: func(); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit.result new file mode 100644 index 0000000000..baa8660a3e --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit.result @@ -0,0 +1,5 @@ +cannot import function `x` + --> tests/ui/parse-fail/unresolved-use3.wit:6:12 + | + 6 | use bar.{x}; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit new file mode 100644 index 0000000000..e3e543bead --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit @@ -0,0 +1,10 @@ +// parse-fail + +package foo:foo; + +interface foo { + use bar.{x}; +} + +interface bar { +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit.result new file mode 100644 index 0000000000..917215b7cf --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit.result @@ -0,0 +1,5 @@ +name `x` is not defined + --> tests/ui/parse-fail/unresolved-use7.wit:6:12 + | + 6 | use bar.{x}; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit new file mode 100644 index 0000000000..2eecf153bf --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit @@ -0,0 +1,9 @@ +// parse-fail + +package foo:foo; + +world foo { + import foo: interface { + use foo.{i32}; + } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit.result new file mode 100644 index 0000000000..a2f98fafb6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit.result @@ -0,0 +1,5 @@ +name `foo` is defined as a world, not an interface + --> tests/ui/parse-fail/unresolved-use8.wit:7:9 + | + 7 | use foo.{i32}; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit new file mode 100644 index 0000000000..a16e13415e --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit @@ -0,0 +1,9 @@ +// parse-fail + +package foo:foo; + +world foo { + import foo: interface { + use bar.{i32}; + } +} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit.result new file mode 100644 index 0000000000..30629add5b --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit.result @@ -0,0 +1,5 @@ +interface or world `bar` does not exist + --> tests/ui/parse-fail/unresolved-use9.wit:7:9 + | + 7 | use bar.{i32}; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unterminated-string.wit.result b/crates/wit-parser/tests/ui/parse-fail/unterminated-string.wit.result new file mode 100644 index 0000000000..0d117b2d7a --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/unterminated-string.wit.result @@ -0,0 +1,5 @@ +unterminated string literal + --> tests/ui/parse-fail/unterminated-string.wit:3:1 + | + 3 | " + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-and-include-world.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world.wit.result new file mode 100644 index 0000000000..f278affe72 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/use-and-include-world + +Caused by: + name `bar` is defined as an interface, not a world + --> tests/ui/parse-fail/use-and-include-world/root.wit:6:21 + | + 6 | include foo:baz/bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-and-include-world/deps/bar/.gitkeep b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world/deps/bar/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-parser/tests/ui/parse-fail/use-and-include-world/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world/deps/bar/baz.wit new file mode 100644 index 0000000000..f16ef464d6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world/deps/bar/baz.wit @@ -0,0 +1,4 @@ +package foo:baz; + +world bar {} + diff --git a/crates/wit-parser/tests/ui/parse-fail/use-and-include-world/root.wit b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world/root.wit new file mode 100644 index 0000000000..4362788155 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world/root.wit @@ -0,0 +1,7 @@ +package foo:foo; + +use foo:baz/bar; + +world foo { + include foo:baz/bar; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit b/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit new file mode 100644 index 0000000000..3eedfba256 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit @@ -0,0 +1,11 @@ +// parse-fail + +package foo:foo; + +interface foo { + type x = u32; +} + +interface bar { + use foo.{x, x}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit.result new file mode 100644 index 0000000000..a98efef921 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit.result @@ -0,0 +1,5 @@ +name `x` is defined more than once + --> tests/ui/parse-fail/use-conflict.wit:10:15 + | + 10 | use foo.{x, x}; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit b/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit new file mode 100644 index 0000000000..12b5b62f69 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit @@ -0,0 +1,13 @@ +// parse-fail + +package foo:foo; + +interface foo { + type x = u32; +} + +interface bar { + use foo.{x}; + + type x = s64; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit.result new file mode 100644 index 0000000000..1ad6fd3479 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit.result @@ -0,0 +1,5 @@ +name `x` is defined more than once + --> tests/ui/parse-fail/use-conflict2.wit:12:8 + | + 12 | type x = s64; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit b/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit new file mode 100644 index 0000000000..572cbe97dc --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit @@ -0,0 +1,13 @@ +// parse-fail + +package foo:foo; + +interface foo { + type x = u32; +} + +interface bar { + use foo.{x}; + + x: func(); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit.result new file mode 100644 index 0000000000..6f3b28bd52 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit.result @@ -0,0 +1,5 @@ +name `x` is defined more than once + --> tests/ui/parse-fail/use-conflict3.wit:12:3 + | + 12 | x: func(); + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit b/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit new file mode 100644 index 0000000000..f7fc7ca0f4 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit @@ -0,0 +1,7 @@ +// parse-fail + +package foo:foo; + +interface foo { + use foo.{bar}; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit.result new file mode 100644 index 0000000000..984ecb59d6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit.result @@ -0,0 +1,5 @@ +interface or world `foo` depends on itself + --> tests/ui/parse-fail/use-cycle1.wit:5:11 + | + 5 | interface foo { + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit b/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit new file mode 100644 index 0000000000..b93a96d003 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit @@ -0,0 +1,14 @@ +// parse-fail +package foo:foo; + +interface foo { + use bar.{y}; + + type x = u32; +} + +interface bar { + use foo.{x}; + + type y = u32; +} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit.result new file mode 100644 index 0000000000..11ece35ad4 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit.result @@ -0,0 +1,5 @@ +interface or world `bar` depends on itself + --> tests/ui/parse-fail/use-cycle4.wit:10:11 + | + 10 | interface bar { + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit b/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit new file mode 100644 index 0000000000..3c3c4428bd --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit @@ -0,0 +1,7 @@ +package foo:foo; + +use foo as bar; + +interface foo {} + +interface bar {} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit.result new file mode 100644 index 0000000000..cdce8b4cc4 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit.result @@ -0,0 +1,5 @@ +duplicate name `bar` in this file + --> tests/ui/parse-fail/use-shadow1.wit:7:11 + | + 7 | interface bar {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-world.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-world.wit.result new file mode 100644 index 0000000000..d21d706277 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-world.wit.result @@ -0,0 +1,5 @@ +interface not found in package + --> tests/ui/parse-fail/use-world/root.wit:3:13 + | + 3 | use foo:baz/bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-world/deps/bar/.gitkeep b/crates/wit-parser/tests/ui/parse-fail/use-world/deps/bar/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/wit-parser/tests/ui/parse-fail/use-world/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/use-world/deps/bar/baz.wit new file mode 100644 index 0000000000..f16ef464d6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-world/deps/bar/baz.wit @@ -0,0 +1,4 @@ +package foo:baz; + +world bar {} + diff --git a/crates/wit-parser/tests/ui/parse-fail/use-world/root.wit b/crates/wit-parser/tests/ui/parse-fail/use-world/root.wit new file mode 100644 index 0000000000..bd81949e05 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-world/root.wit @@ -0,0 +1,7 @@ +package foo:foo; + +use foo:baz/bar; + +world foo { + +} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit b/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit new file mode 100644 index 0000000000..32f0bb592a --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit @@ -0,0 +1,3 @@ +package foo:foo; +interface foo {} +world foo {} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit.result new file mode 100644 index 0000000000..53f8004cc7 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit.result @@ -0,0 +1,5 @@ +duplicate item named `foo` + --> tests/ui/parse-fail/world-interface-clash.wit:3:7 + | + 3 | world foo {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit b/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit new file mode 100644 index 0000000000..ca16b1e945 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit @@ -0,0 +1,8 @@ +// parse-fail + +package foo:foo; + +world a { + import foo: interface {} + import foo: interface {} +} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit.result new file mode 100644 index 0000000000..3498be115f --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit.result @@ -0,0 +1,5 @@ +import `foo` conflicts with prior import of same name + --> tests/ui/parse-fail/world-same-fields2.wit:7:10 + | + 7 | import foo: interface {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit b/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit new file mode 100644 index 0000000000..104af9f597 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit @@ -0,0 +1,8 @@ +// parse-fail + +package foo:foo; + +world a { + export foo: interface {} + export foo: interface {} +} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit.result new file mode 100644 index 0000000000..bf4a4bc61b --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit.result @@ -0,0 +1,5 @@ +export `foo` conflicts with prior export of same name + --> tests/ui/parse-fail/world-same-fields3.wit:7:10 + | + 7 | export foo: interface {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit new file mode 100644 index 0000000000..71269da064 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit @@ -0,0 +1,5 @@ +package foo:foo; +world foo { + import foo: func(); + import foo: func(); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit.result new file mode 100644 index 0000000000..9462490376 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit.result @@ -0,0 +1,5 @@ +import `foo` conflicts with prior import of same name + --> tests/ui/parse-fail/world-top-level-func.wit:4:10 + | + 4 | import foo: func(); + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit new file mode 100644 index 0000000000..e0fd270346 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit @@ -0,0 +1,4 @@ +package foo:foo; +world foo { + import foo: func(a: b); +} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit.result new file mode 100644 index 0000000000..9ebb6629b6 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit.result @@ -0,0 +1,5 @@ +name `b` is not defined + --> tests/ui/parse-fail/world-top-level-func2.wit:3:23 + | + 3 | import foo: func(a: b); + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/random.wit b/crates/wit-parser/tests/ui/random.wit new file mode 100644 index 0000000000..999ada6008 --- /dev/null +++ b/crates/wit-parser/tests/ui/random.wit @@ -0,0 +1,27 @@ +package wasi:random; + +/// WASI Random is a random data API. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +interface random { + /// Return `len` cryptographically-secure random or pseudo-random bytes. + /// + /// This function must produce data at least as cryptographically secure and + /// fast as an adequately seeded cryptographically-secure pseudo-random + /// number generator (CSPRNG). It must not block, from the perspective of + /// the calling program, under any circumstances, including on the first + /// request and on requests for numbers of bytes. The returned data must + /// always be unpredictable. + /// + /// This function must always return fresh data. Deterministic environments + /// must omit this function, rather than implementing it with deterministic + /// data. + get-random-bytes: func(len: u64) -> list; + + /// Return a cryptographically-secure random or pseudo-random `u64` value. + /// + /// This function returns the same type of data as `get-random-bytes`, + /// represented as a `u64`. + get-random-u64: func() -> u64; +} diff --git a/crates/wit-parser/tests/ui/random.wit.json b/crates/wit-parser/tests/ui/random.wit.json new file mode 100644 index 0000000000..5d46664671 --- /dev/null +++ b/crates/wit-parser/tests/ui/random.wit.json @@ -0,0 +1,64 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "random", + "types": {}, + "functions": { + "get-random-bytes": { + "name": "get-random-bytes", + "kind": "freestanding", + "params": [ + { + "name": "len", + "type": "u64" + } + ], + "results": [ + { + "type": 0 + } + ], + "docs": { + "contents": "Return `len` cryptographically-secure random or pseudo-random bytes.\n\nThis function must produce data at least as cryptographically secure and\nfast as an adequately seeded cryptographically-secure pseudo-random\nnumber generator (CSPRNG). It must not block, from the perspective of\nthe calling program, under any circumstances, including on the first\nrequest and on requests for numbers of bytes. The returned data must\nalways be unpredictable.\n\nThis function must always return fresh data. Deterministic environments\nmust omit this function, rather than implementing it with deterministic\ndata." + } + }, + "get-random-u64": { + "name": "get-random-u64", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": "u64" + } + ], + "docs": { + "contents": "Return a cryptographically-secure random or pseudo-random `u64` value.\n\nThis function returns the same type of data as `get-random-bytes`,\nrepresented as a `u64`." + } + } + }, + "docs": { + "contents": "WASI Random is a random data API.\n\nIt is intended to be portable at least between Unix-family platforms and\nWindows." + }, + "package": 0 + } + ], + "types": [ + { + "name": null, + "kind": { + "list": "u8" + }, + "owner": null + } + ], + "packages": [ + { + "name": "wasi:random", + "interfaces": { + "random": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resources-empty.wit b/crates/wit-parser/tests/ui/resources-empty.wit new file mode 100644 index 0000000000..62447351df --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-empty.wit @@ -0,0 +1,10 @@ +package foo:resources-empty; + +interface resources-empty { + t1: func(a: own) -> (); + t2: func(a: borrow) -> (); + + resource r1 { + } +} + diff --git a/crates/wit-parser/tests/ui/resources-empty.wit.json b/crates/wit-parser/tests/ui/resources-empty.wit.json new file mode 100644 index 0000000000..6c40c61dfc --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-empty.wit.json @@ -0,0 +1,72 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "resources-empty", + "types": { + "r1": 0 + }, + "functions": { + "t1": { + "name": "t1", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 2 + } + ], + "results": [] + }, + "t2": { + "name": "t2", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 1 + } + ], + "results": [] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "r1", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 0 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 0 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:resources-empty", + "interfaces": { + "resources-empty": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resources-multiple-returns-borrow.wit b/crates/wit-parser/tests/ui/resources-multiple-returns-borrow.wit new file mode 100644 index 0000000000..00b62676f9 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-multiple-returns-borrow.wit @@ -0,0 +1,10 @@ +package foo:resources1; + +interface resources1 { + t1: func(a: borrow) -> (); + + resource r1 { + f1: func() -> (a: s32, handle: borrow); + } +} + diff --git a/crates/wit-parser/tests/ui/resources-multiple-returns-borrow.wit.json b/crates/wit-parser/tests/ui/resources-multiple-returns-borrow.wit.json new file mode 100644 index 0000000000..d5fbf02a2c --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-multiple-returns-borrow.wit.json @@ -0,0 +1,74 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "resources1", + "types": { + "r1": 0 + }, + "functions": { + "t1": { + "name": "t1", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 1 + } + ], + "results": [] + }, + "[method]r1.f1": { + "name": "[method]r1.f1", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [ + { + "name": "a", + "type": "s32" + }, + { + "name": "handle", + "type": 1 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "r1", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 0 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:resources1", + "interfaces": { + "resources1": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit b/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit new file mode 100644 index 0000000000..13e87ffd89 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit @@ -0,0 +1,10 @@ +package foo:resources1; + +interface resources1 { + t1: func(a: own) -> (); + + resource r1 { + f1: func() -> (a: s32, handle: own); + } +} + diff --git a/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit.json b/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit.json new file mode 100644 index 0000000000..e7234f7ed8 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit.json @@ -0,0 +1,83 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "resources1", + "types": { + "r1": 0 + }, + "functions": { + "t1": { + "name": "t1", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 2 + } + ], + "results": [] + }, + "[method]r1.f1": { + "name": "[method]r1.f1", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [ + { + "name": "a", + "type": "s32" + }, + { + "name": "handle", + "type": 2 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "r1", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 0 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 0 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:resources1", + "interfaces": { + "resources1": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resources-multiple.wit b/crates/wit-parser/tests/ui/resources-multiple.wit new file mode 100644 index 0000000000..1e7146b95f --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-multiple.wit @@ -0,0 +1,20 @@ +package foo:resources-multiple; + +interface resources-multiple { + t1: func(a: borrow) -> (); + t2: func(a: own) -> (); + + resource r1 { + f1: func(); + f2: func(a: u32); + f3: func(a: u32,); + f4: func() -> u32; + f6: func() -> tuple; + f7: func(a: float32, b: float32) -> tuple; + f8: func(a: option) -> result; + f9: func() -> (u: u32, f: float32); + f10: func() -> (u: u32); + f11: func() -> (); + } +} + diff --git a/crates/wit-parser/tests/ui/resources-multiple.wit.json b/crates/wit-parser/tests/ui/resources-multiple.wit.json new file mode 100644 index 0000000000..b77d35f867 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-multiple.wit.json @@ -0,0 +1,281 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "resources-multiple", + "types": { + "r1": 0 + }, + "functions": { + "t1": { + "name": "t1", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 1 + } + ], + "results": [] + }, + "t2": { + "name": "t2", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 5 + } + ], + "results": [] + }, + "[method]r1.f1": { + "name": "[method]r1.f1", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [] + }, + "[method]r1.f2": { + "name": "[method]r1.f2", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + }, + { + "name": "a", + "type": "u32" + } + ], + "results": [] + }, + "[method]r1.f3": { + "name": "[method]r1.f3", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + }, + { + "name": "a", + "type": "u32" + } + ], + "results": [] + }, + "[method]r1.f4": { + "name": "[method]r1.f4", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [ + { + "type": "u32" + } + ] + }, + "[method]r1.f6": { + "name": "[method]r1.f6", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [ + { + "type": 2 + } + ] + }, + "[method]r1.f7": { + "name": "[method]r1.f7", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + }, + { + "name": "a", + "type": "float32" + }, + { + "name": "b", + "type": "float32" + } + ], + "results": [ + { + "type": 2 + } + ] + }, + "[method]r1.f8": { + "name": "[method]r1.f8", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + }, + { + "name": "a", + "type": 3 + } + ], + "results": [ + { + "type": 4 + } + ] + }, + "[method]r1.f9": { + "name": "[method]r1.f9", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [ + { + "name": "u", + "type": "u32" + }, + { + "name": "f", + "type": "float32" + } + ] + }, + "[method]r1.f10": { + "name": "[method]r1.f10", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [ + { + "name": "u", + "type": "u32" + } + ] + }, + "[method]r1.f11": { + "name": "[method]r1.f11", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "r1", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 0 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "tuple": { + "types": [ + "u32", + "u32" + ] + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "option": "u32" + }, + "owner": null + }, + { + "name": null, + "kind": { + "result": { + "ok": "u32", + "err": "float32" + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 0 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:resources-multiple", + "interfaces": { + "resources-multiple": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resources-return-borrow.wit b/crates/wit-parser/tests/ui/resources-return-borrow.wit new file mode 100644 index 0000000000..ab60abba59 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-return-borrow.wit @@ -0,0 +1,10 @@ +package foo:resources1; + +interface resources1 { + t1: func(a: borrow) -> (); + + resource r1 { + f1: func() -> borrow; + } +} + diff --git a/crates/wit-parser/tests/ui/resources-return-borrow.wit.json b/crates/wit-parser/tests/ui/resources-return-borrow.wit.json new file mode 100644 index 0000000000..c48dd35167 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-return-borrow.wit.json @@ -0,0 +1,69 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "resources1", + "types": { + "r1": 0 + }, + "functions": { + "t1": { + "name": "t1", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 1 + } + ], + "results": [] + }, + "[method]r1.f1": { + "name": "[method]r1.f1", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [ + { + "type": 1 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "r1", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 0 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:resources1", + "interfaces": { + "resources1": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resources-return-own.wit b/crates/wit-parser/tests/ui/resources-return-own.wit new file mode 100644 index 0000000000..0e36ac4ba3 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-return-own.wit @@ -0,0 +1,10 @@ +package foo:resources1; + +interface resources1 { + t1: func(a: own) -> (); + + resource r1 { + f1: func() -> own; + } +} + diff --git a/crates/wit-parser/tests/ui/resources-return-own.wit.json b/crates/wit-parser/tests/ui/resources-return-own.wit.json new file mode 100644 index 0000000000..3e44fc106c --- /dev/null +++ b/crates/wit-parser/tests/ui/resources-return-own.wit.json @@ -0,0 +1,78 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "resources1", + "types": { + "r1": 0 + }, + "functions": { + "t1": { + "name": "t1", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 2 + } + ], + "results": [] + }, + "[method]r1.f1": { + "name": "[method]r1.f1", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [ + { + "type": 2 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "r1", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 0 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 0 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:resources1", + "interfaces": { + "resources1": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resources.wit b/crates/wit-parser/tests/ui/resources.wit new file mode 100644 index 0000000000..cdb8aefd66 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources.wit @@ -0,0 +1,47 @@ +package foo:bar; + +interface foo { + resource a { + } + + resource b { + constructor(); + } + + resource c { + constructor(x: u32); + } + + resource d { + constructor(x: u32); + + a: func(); + + b: static func(); + } + + resource e { + constructor(other: own, other2: borrow); + + method: func(thing: own, thing2: borrow); + } +} + +world w { + resource a; + + resource b { + } + + resource c { + constructor(); + } +} + +interface i { + resource a; + + type t1 = a; + type t2 = borrow; + type t3 = borrow; +} diff --git a/crates/wit-parser/tests/ui/resources.wit.json b/crates/wit-parser/tests/ui/resources.wit.json new file mode 100644 index 0000000000..169fb02110 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources.wit.json @@ -0,0 +1,340 @@ +{ + "worlds": [ + { + "name": "w", + "imports": { + "a": { + "type": 11 + }, + "b": { + "type": 12 + }, + "c": { + "type": 13 + }, + "[constructor]c": { + "function": { + "name": "[constructor]c", + "kind": { + "constructor": 13 + }, + "params": [], + "results": [ + { + "type": 18 + } + ] + } + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "foo", + "types": { + "a": 0, + "b": 1, + "c": 2, + "d": 3, + "e": 4 + }, + "functions": { + "[constructor]b": { + "name": "[constructor]b", + "kind": { + "constructor": 1 + }, + "params": [], + "results": [ + { + "type": 14 + } + ] + }, + "[constructor]c": { + "name": "[constructor]c", + "kind": { + "constructor": 2 + }, + "params": [ + { + "name": "x", + "type": "u32" + } + ], + "results": [ + { + "type": 15 + } + ] + }, + "[constructor]d": { + "name": "[constructor]d", + "kind": { + "constructor": 3 + }, + "params": [ + { + "name": "x", + "type": "u32" + } + ], + "results": [ + { + "type": 16 + } + ] + }, + "[method]d.a": { + "name": "[method]d.a", + "kind": { + "method": 3 + }, + "params": [ + { + "name": "self", + "type": 5 + } + ], + "results": [] + }, + "[static]d.b": { + "name": "[static]d.b", + "kind": { + "static": 3 + }, + "params": [], + "results": [] + }, + "[constructor]e": { + "name": "[constructor]e", + "kind": { + "constructor": 4 + }, + "params": [ + { + "name": "other", + "type": 17 + }, + { + "name": "other2", + "type": 6 + } + ], + "results": [ + { + "type": 17 + } + ] + }, + "[method]e.method": { + "name": "[method]e.method", + "kind": { + "method": 4 + }, + "params": [ + { + "name": "self", + "type": 6 + }, + { + "name": "thing", + "type": 17 + }, + { + "name": "thing2", + "type": 6 + } + ], + "results": [] + } + }, + "package": 0 + }, + { + "name": "i", + "types": { + "a": 7, + "t1": 8, + "t2": 9, + "t3": 10 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "a", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": "b", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": "c", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": "d", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": "e", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 3 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 4 + } + }, + "owner": null + }, + { + "name": "a", + "kind": "resource", + "owner": { + "interface": 1 + } + }, + { + "name": "t1", + "kind": { + "type": 7 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t2", + "kind": { + "handle": { + "borrow": 7 + } + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t3", + "kind": { + "handle": { + "borrow": 8 + } + }, + "owner": { + "interface": 1 + } + }, + { + "name": "a", + "kind": "resource", + "owner": { + "world": 0 + } + }, + { + "name": "b", + "kind": "resource", + "owner": { + "world": 0 + } + }, + { + "name": "c", + "kind": "resource", + "owner": { + "world": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "own": 1 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 2 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 3 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 4 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 13 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:bar", + "interfaces": { + "foo": 0, + "i": 1 + }, + "worlds": { + "w": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resources1.wit b/crates/wit-parser/tests/ui/resources1.wit new file mode 100644 index 0000000000..77baeffe21 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources1.wit @@ -0,0 +1,12 @@ +package foo:resources1; + +interface resources1 { + t1: func(a: borrow) -> (); + t2: func(a: own) -> (); + t3: func(a: r1) -> (); + + resource r1 { + f1: func(); + } +} + diff --git a/crates/wit-parser/tests/ui/resources1.wit.json b/crates/wit-parser/tests/ui/resources1.wit.json new file mode 100644 index 0000000000..447e5ec2b9 --- /dev/null +++ b/crates/wit-parser/tests/ui/resources1.wit.json @@ -0,0 +1,96 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "resources1", + "types": { + "r1": 0 + }, + "functions": { + "t1": { + "name": "t1", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 1 + } + ], + "results": [] + }, + "t2": { + "name": "t2", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 2 + } + ], + "results": [] + }, + "t3": { + "name": "t3", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 2 + } + ], + "results": [] + }, + "[method]r1.f1": { + "name": "[method]r1.f1", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 1 + } + ], + "results": [] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "r1", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 0 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 0 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:resources1", + "interfaces": { + "resources1": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/shared-types.wit b/crates/wit-parser/tests/ui/shared-types.wit new file mode 100644 index 0000000000..3aafbda86b --- /dev/null +++ b/crates/wit-parser/tests/ui/shared-types.wit @@ -0,0 +1,10 @@ +package foo:shared-items; + +world foo { + import foo: interface { + a: func() -> list; + } + export bar: interface { + a: func() -> tuple>; + } +} diff --git a/crates/wit-parser/tests/ui/shared-types.wit.json b/crates/wit-parser/tests/ui/shared-types.wit.json new file mode 100644 index 0000000000..d0dba6598c --- /dev/null +++ b/crates/wit-parser/tests/ui/shared-types.wit.json @@ -0,0 +1,83 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "foo": { + "interface": 0 + } + }, + "exports": { + "bar": { + "interface": 1 + } + }, + "package": 0 + } + ], + "interfaces": [ + { + "name": null, + "types": {}, + "functions": { + "a": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 0 + } + ] + } + }, + "package": 0 + }, + { + "name": null, + "types": {}, + "functions": { + "a": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 1 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": null, + "kind": { + "list": "u8" + }, + "owner": null + }, + { + "name": null, + "kind": { + "tuple": { + "types": [ + 0 + ] + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:shared-items", + "interfaces": {}, + "worlds": { + "foo": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/stress-export-elaborate.wit b/crates/wit-parser/tests/ui/stress-export-elaborate.wit new file mode 100644 index 0000000000..aba12ee1b7 --- /dev/null +++ b/crates/wit-parser/tests/ui/stress-export-elaborate.wit @@ -0,0 +1,54 @@ +package foo:bar; + +interface i1 { + type t1 = u32; + type t2 = u32; + type t3 = u32; + type t4 = u32; + type t5 = u32; + type t6 = u32; + type t7 = u32; + type t8 = u32; + type t9 = u32; + type t10 = u32; +} + +interface i2 { + use i1.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +interface i3 { + use i2.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +interface i4 { + use i3.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +interface i5 { + use i4.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +interface i6 { + use i5.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +interface i7 { + use i6.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +interface i8 { + use i7.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +interface i9 { + use i8.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +interface i10 { + use i9.{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}; +} + +world foo { + export i10; +} diff --git a/crates/wit-parser/tests/ui/stress-export-elaborate.wit.json b/crates/wit-parser/tests/ui/stress-export-elaborate.wit.json new file mode 100644 index 0000000000..bd8fdfceed --- /dev/null +++ b/crates/wit-parser/tests/ui/stress-export-elaborate.wit.json @@ -0,0 +1,1136 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-1": { + "interface": 1 + }, + "interface-2": { + "interface": 2 + }, + "interface-3": { + "interface": 3 + }, + "interface-4": { + "interface": 4 + }, + "interface-5": { + "interface": 5 + }, + "interface-6": { + "interface": 6 + }, + "interface-7": { + "interface": 7 + }, + "interface-8": { + "interface": 8 + } + }, + "exports": { + "interface-9": { + "interface": 9 + } + }, + "package": 0 + } + ], + "interfaces": [ + { + "name": "i1", + "types": { + "t1": 0, + "t2": 1, + "t3": 2, + "t4": 3, + "t5": 4, + "t6": 5, + "t7": 6, + "t8": 7, + "t9": 8, + "t10": 9 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i2", + "types": { + "t1": 10, + "t2": 11, + "t3": 12, + "t4": 13, + "t5": 14, + "t6": 15, + "t7": 16, + "t8": 17, + "t9": 18, + "t10": 19 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i3", + "types": { + "t1": 20, + "t2": 21, + "t3": 22, + "t4": 23, + "t5": 24, + "t6": 25, + "t7": 26, + "t8": 27, + "t9": 28, + "t10": 29 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i4", + "types": { + "t1": 30, + "t2": 31, + "t3": 32, + "t4": 33, + "t5": 34, + "t6": 35, + "t7": 36, + "t8": 37, + "t9": 38, + "t10": 39 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i5", + "types": { + "t1": 40, + "t2": 41, + "t3": 42, + "t4": 43, + "t5": 44, + "t6": 45, + "t7": 46, + "t8": 47, + "t9": 48, + "t10": 49 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i6", + "types": { + "t1": 50, + "t2": 51, + "t3": 52, + "t4": 53, + "t5": 54, + "t6": 55, + "t7": 56, + "t8": 57, + "t9": 58, + "t10": 59 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i7", + "types": { + "t1": 60, + "t2": 61, + "t3": 62, + "t4": 63, + "t5": 64, + "t6": 65, + "t7": 66, + "t8": 67, + "t9": 68, + "t10": 69 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i8", + "types": { + "t1": 70, + "t2": 71, + "t3": 72, + "t4": 73, + "t5": 74, + "t6": 75, + "t7": 76, + "t8": 77, + "t9": 78, + "t10": 79 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i9", + "types": { + "t1": 80, + "t2": 81, + "t3": 82, + "t4": 83, + "t5": 84, + "t6": 85, + "t7": 86, + "t8": 87, + "t9": 88, + "t10": 89 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i10", + "types": { + "t1": 90, + "t2": 91, + "t3": 92, + "t4": 93, + "t5": 94, + "t6": 95, + "t7": 96, + "t8": 97, + "t9": 98, + "t10": 99 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "t1", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t2", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t3", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t4", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t5", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t6", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t7", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t8", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t9", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t10", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t1", + "kind": { + "type": 0 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t2", + "kind": { + "type": 1 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t3", + "kind": { + "type": 2 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t4", + "kind": { + "type": 3 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t5", + "kind": { + "type": 4 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t6", + "kind": { + "type": 5 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t7", + "kind": { + "type": 6 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t8", + "kind": { + "type": 7 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t9", + "kind": { + "type": 8 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t10", + "kind": { + "type": 9 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t1", + "kind": { + "type": 10 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t2", + "kind": { + "type": 11 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t3", + "kind": { + "type": 12 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t4", + "kind": { + "type": 13 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t5", + "kind": { + "type": 14 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t6", + "kind": { + "type": 15 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t7", + "kind": { + "type": 16 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t8", + "kind": { + "type": 17 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t9", + "kind": { + "type": 18 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t10", + "kind": { + "type": 19 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t1", + "kind": { + "type": 20 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t2", + "kind": { + "type": 21 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t3", + "kind": { + "type": 22 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t4", + "kind": { + "type": 23 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t5", + "kind": { + "type": 24 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t6", + "kind": { + "type": 25 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t7", + "kind": { + "type": 26 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t8", + "kind": { + "type": 27 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t9", + "kind": { + "type": 28 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t10", + "kind": { + "type": 29 + }, + "owner": { + "interface": 3 + } + }, + { + "name": "t1", + "kind": { + "type": 30 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t2", + "kind": { + "type": 31 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t3", + "kind": { + "type": 32 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t4", + "kind": { + "type": 33 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t5", + "kind": { + "type": 34 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t6", + "kind": { + "type": 35 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t7", + "kind": { + "type": 36 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t8", + "kind": { + "type": 37 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t9", + "kind": { + "type": 38 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t10", + "kind": { + "type": 39 + }, + "owner": { + "interface": 4 + } + }, + { + "name": "t1", + "kind": { + "type": 40 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t2", + "kind": { + "type": 41 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t3", + "kind": { + "type": 42 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t4", + "kind": { + "type": 43 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t5", + "kind": { + "type": 44 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t6", + "kind": { + "type": 45 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t7", + "kind": { + "type": 46 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t8", + "kind": { + "type": 47 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t9", + "kind": { + "type": 48 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t10", + "kind": { + "type": 49 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "t1", + "kind": { + "type": 50 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t2", + "kind": { + "type": 51 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t3", + "kind": { + "type": 52 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t4", + "kind": { + "type": 53 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t5", + "kind": { + "type": 54 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t6", + "kind": { + "type": 55 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t7", + "kind": { + "type": 56 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t8", + "kind": { + "type": 57 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t9", + "kind": { + "type": 58 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t10", + "kind": { + "type": 59 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "t1", + "kind": { + "type": 60 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t2", + "kind": { + "type": 61 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t3", + "kind": { + "type": 62 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t4", + "kind": { + "type": 63 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t5", + "kind": { + "type": 64 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t6", + "kind": { + "type": 65 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t7", + "kind": { + "type": 66 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t8", + "kind": { + "type": 67 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t9", + "kind": { + "type": 68 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t10", + "kind": { + "type": 69 + }, + "owner": { + "interface": 7 + } + }, + { + "name": "t1", + "kind": { + "type": 70 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t2", + "kind": { + "type": 71 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t3", + "kind": { + "type": 72 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t4", + "kind": { + "type": 73 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t5", + "kind": { + "type": 74 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t6", + "kind": { + "type": 75 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t7", + "kind": { + "type": 76 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t8", + "kind": { + "type": 77 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t9", + "kind": { + "type": 78 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t10", + "kind": { + "type": 79 + }, + "owner": { + "interface": 8 + } + }, + { + "name": "t1", + "kind": { + "type": 80 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t2", + "kind": { + "type": 81 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t3", + "kind": { + "type": 82 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t4", + "kind": { + "type": 83 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t5", + "kind": { + "type": 84 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t6", + "kind": { + "type": 85 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t7", + "kind": { + "type": 86 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t8", + "kind": { + "type": 87 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t9", + "kind": { + "type": 88 + }, + "owner": { + "interface": 9 + } + }, + { + "name": "t10", + "kind": { + "type": 89 + }, + "owner": { + "interface": 9 + } + } + ], + "packages": [ + { + "name": "foo:bar", + "interfaces": { + "i1": 0, + "i2": 1, + "i3": 2, + "i4": 3, + "i5": 4, + "i6": 5, + "i7": 6, + "i8": 7, + "i9": 8, + "i10": 9 + }, + "worlds": { + "foo": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/type-then-eof.wit b/crates/wit-parser/tests/ui/type-then-eof.wit new file mode 100644 index 0000000000..4c4424b37b --- /dev/null +++ b/crates/wit-parser/tests/ui/type-then-eof.wit @@ -0,0 +1,5 @@ +package foo:foo; + +interface foo { + foo: func() -> string; +} diff --git a/crates/wit-parser/tests/ui/type-then-eof.wit.json b/crates/wit-parser/tests/ui/type-then-eof.wit.json new file mode 100644 index 0000000000..beb0a7adca --- /dev/null +++ b/crates/wit-parser/tests/ui/type-then-eof.wit.json @@ -0,0 +1,32 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "foo", + "types": {}, + "functions": { + "foo": { + "name": "foo", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": "string" + } + ] + } + }, + "package": 0 + } + ], + "types": [], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "foo": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/types.wit b/crates/wit-parser/tests/ui/types.wit new file mode 100644 index 0000000000..99f0f2a26d --- /dev/null +++ b/crates/wit-parser/tests/ui/types.wit @@ -0,0 +1,58 @@ +package foo:types; + +interface types { + type t1 = u8; + type t2 = u16; + type t3 = u32; + type t4 = u64; + type t5 = s8; + type t6 = s16; + type t7 = s32; + type t8 = s64; + type t9 = float32; + type t10 = float64; + type t11 = char; + type t12 = list; + type t13 = string; + type t14 = option; + type t15 = result; + type t16 = result<_, u32>; + type t17 = result; + type t18 = result; + record t20 {} + record t21 { a: u32 } + record t22 { a: u32, } + record t23 { a: u32, b: u64 } + record t24 { a: u32, b: u64, } + record t25 { x: u32 } + record %record {} + type t26 = tuple<>; + type t27 = tuple; + type t28 = tuple; + type t29 = tuple; + flags t30 {} + flags t31 { a, b, c } + flags t32 { a, b, c, } + variant t33 { a } + variant t34 { a, b } + variant t35 { a, b, } + variant t36 { a, b(u32), } + variant t37 { a, b(option), } + enum t41 { a, b, c } + enum t42 { a, b, c, } + type t43 = bool; + type t44 = string; + type t45 = list>>; + type t46 = t44; + type t47 = %t44; + type t48 = stream; + type t49 = stream<_, u32>; + type t50 = stream; + type t51 = stream; + type t52 = future; + type t53 = future; + + // type order doesn't matter + type foo = bar; + type bar = u32; +} diff --git a/crates/wit-parser/tests/ui/types.wit.json b/crates/wit-parser/tests/ui/types.wit.json new file mode 100644 index 0000000000..2839365bc8 --- /dev/null +++ b/crates/wit-parser/tests/ui/types.wit.json @@ -0,0 +1,751 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "types", + "types": { + "t1": 0, + "t2": 1, + "t3": 2, + "t4": 3, + "t5": 4, + "t6": 5, + "t7": 6, + "t8": 7, + "t9": 8, + "t10": 9, + "t11": 10, + "t12": 11, + "t13": 12, + "t14": 13, + "t15": 14, + "t16": 15, + "t17": 16, + "t18": 17, + "t20": 18, + "t21": 19, + "t22": 20, + "t23": 21, + "t24": 22, + "t25": 23, + "record": 24, + "t26": 25, + "t27": 26, + "t28": 27, + "t29": 28, + "t30": 29, + "t31": 30, + "t32": 31, + "t33": 32, + "t34": 33, + "t35": 34, + "t36": 35, + "t37": 37, + "t41": 38, + "t42": 39, + "t43": 40, + "t44": 41, + "t45": 44, + "t46": 45, + "t47": 46, + "t48": 47, + "t49": 48, + "t50": 49, + "t51": 50, + "t52": 51, + "t53": 52, + "bar": 53, + "foo": 54 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "t1", + "kind": { + "type": "u8" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t2", + "kind": { + "type": "u16" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t3", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t4", + "kind": { + "type": "u64" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t5", + "kind": { + "type": "s8" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t6", + "kind": { + "type": "s16" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t7", + "kind": { + "type": "s32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t8", + "kind": { + "type": "s64" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t9", + "kind": { + "type": "float32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t10", + "kind": { + "type": "float64" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t11", + "kind": { + "type": "char" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t12", + "kind": { + "list": "char" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t13", + "kind": { + "type": "string" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t14", + "kind": { + "option": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t15", + "kind": { + "result": { + "ok": "u32", + "err": "u32" + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t16", + "kind": { + "result": { + "ok": null, + "err": "u32" + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t17", + "kind": { + "result": { + "ok": "u32", + "err": null + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t18", + "kind": { + "result": { + "ok": null, + "err": null + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t20", + "kind": { + "record": { + "fields": [] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t21", + "kind": { + "record": { + "fields": [ + { + "name": "a", + "type": "u32" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t22", + "kind": { + "record": { + "fields": [ + { + "name": "a", + "type": "u32" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t23", + "kind": { + "record": { + "fields": [ + { + "name": "a", + "type": "u32" + }, + { + "name": "b", + "type": "u64" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t24", + "kind": { + "record": { + "fields": [ + { + "name": "a", + "type": "u32" + }, + { + "name": "b", + "type": "u64" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t25", + "kind": { + "record": { + "fields": [ + { + "name": "x", + "type": "u32" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "record", + "kind": { + "record": { + "fields": [] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t26", + "kind": { + "tuple": { + "types": [] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t27", + "kind": { + "tuple": { + "types": [ + "u32" + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t28", + "kind": { + "tuple": { + "types": [ + "u32" + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t29", + "kind": { + "tuple": { + "types": [ + "u32", + "u64" + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t30", + "kind": { + "flags": { + "flags": [] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t31", + "kind": { + "flags": { + "flags": [ + { + "name": "a" + }, + { + "name": "b" + }, + { + "name": "c" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t32", + "kind": { + "flags": { + "flags": [ + { + "name": "a" + }, + { + "name": "b" + }, + { + "name": "c" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t33", + "kind": { + "variant": { + "cases": [ + { + "name": "a", + "type": null + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t34", + "kind": { + "variant": { + "cases": [ + { + "name": "a", + "type": null + }, + { + "name": "b", + "type": null + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t35", + "kind": { + "variant": { + "cases": [ + { + "name": "a", + "type": null + }, + { + "name": "b", + "type": null + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t36", + "kind": { + "variant": { + "cases": [ + { + "name": "a", + "type": null + }, + { + "name": "b", + "type": "u32" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "option": "u32" + }, + "owner": null + }, + { + "name": "t37", + "kind": { + "variant": { + "cases": [ + { + "name": "a", + "type": null + }, + { + "name": "b", + "type": 36 + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t41", + "kind": { + "enum": { + "cases": [ + { + "name": "a" + }, + { + "name": "b" + }, + { + "name": "c" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t42", + "kind": { + "enum": { + "cases": [ + { + "name": "a" + }, + { + "name": "b" + }, + { + "name": "c" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t43", + "kind": { + "type": "bool" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t44", + "kind": { + "type": "string" + }, + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "list": 31 + }, + "owner": null + }, + { + "name": null, + "kind": { + "list": 42 + }, + "owner": null + }, + { + "name": "t45", + "kind": { + "list": 43 + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t46", + "kind": { + "type": 41 + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t47", + "kind": { + "type": 41 + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t48", + "kind": { + "stream": { + "element": "u32", + "end": "u32" + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t49", + "kind": { + "stream": { + "element": null, + "end": "u32" + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t50", + "kind": { + "stream": { + "element": "u32", + "end": null + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t51", + "kind": { + "stream": { + "element": null, + "end": null + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t52", + "kind": { + "future": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t53", + "kind": { + "future": null + }, + "owner": { + "interface": 0 + } + }, + { + "name": "bar", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "foo", + "kind": { + "type": 53 + }, + "owner": { + "interface": 0 + } + } + ], + "packages": [ + { + "name": "foo:types", + "interfaces": { + "types": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/union-fuzz-1.wit b/crates/wit-parser/tests/ui/union-fuzz-1.wit new file mode 100644 index 0000000000..6528f7db3a --- /dev/null +++ b/crates/wit-parser/tests/ui/union-fuzz-1.wit @@ -0,0 +1,9 @@ +package foo:bar; + +world xo {} + +world name {} + +world x { + include name; +} diff --git a/crates/wit-parser/tests/ui/union-fuzz-1.wit.json b/crates/wit-parser/tests/ui/union-fuzz-1.wit.json new file mode 100644 index 0000000000..31c7c82687 --- /dev/null +++ b/crates/wit-parser/tests/ui/union-fuzz-1.wit.json @@ -0,0 +1,35 @@ +{ + "worlds": [ + { + "name": "xo", + "imports": {}, + "exports": {}, + "package": 0 + }, + { + "name": "name", + "imports": {}, + "exports": {}, + "package": 0 + }, + { + "name": "x", + "imports": {}, + "exports": {}, + "package": 0 + } + ], + "interfaces": [], + "types": [], + "packages": [ + { + "name": "foo:bar", + "interfaces": {}, + "worlds": { + "xo": 0, + "name": 1, + "x": 2 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/use-chain.wit b/crates/wit-parser/tests/ui/use-chain.wit new file mode 100644 index 0000000000..e40f3e4971 --- /dev/null +++ b/crates/wit-parser/tests/ui/use-chain.wit @@ -0,0 +1,11 @@ +package foo:name; + +interface foo { + record foo {} +} + +use foo as bar; + +interface name { + use bar.{foo}; +} diff --git a/crates/wit-parser/tests/ui/use-chain.wit.json b/crates/wit-parser/tests/ui/use-chain.wit.json new file mode 100644 index 0000000000..bd942bb8cd --- /dev/null +++ b/crates/wit-parser/tests/ui/use-chain.wit.json @@ -0,0 +1,53 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "foo", + "types": { + "foo": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": "name", + "types": { + "foo": 1 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "foo", + "kind": { + "record": { + "fields": [] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "foo", + "kind": { + "type": 0 + }, + "owner": { + "interface": 1 + } + } + ], + "packages": [ + { + "name": "foo:name", + "interfaces": { + "foo": 0, + "name": 1 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/use.wit b/crates/wit-parser/tests/ui/use.wit new file mode 100644 index 0000000000..dce58e6f90 --- /dev/null +++ b/crates/wit-parser/tests/ui/use.wit @@ -0,0 +1,34 @@ +package foo:foo; + +interface foo { + use bar.{the-type}; +} + +interface bar { + type the-type = u32; +} + +interface baz { + use foo.{the-type}; + use bar.{the-type as test}; +} + +interface empty { +} + +interface use-from-empty { + use empty.{}; + use empty.{}; +} + +interface use-multiple { + use baz.{the-type, test}; + + some-function: func(x: the-type) -> test; +} + +interface trailing-comma { + use foo.{the-type,}; + + record the-foo { a: the-type } +} diff --git a/crates/wit-parser/tests/ui/use.wit.json b/crates/wit-parser/tests/ui/use.wit.json new file mode 100644 index 0000000000..43cc16b4a7 --- /dev/null +++ b/crates/wit-parser/tests/ui/use.wit.json @@ -0,0 +1,172 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "bar", + "types": { + "the-type": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": "foo", + "types": { + "the-type": 1 + }, + "functions": {}, + "package": 0 + }, + { + "name": "baz", + "types": { + "the-type": 2, + "test": 3 + }, + "functions": {}, + "package": 0 + }, + { + "name": "empty", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "use-from-empty", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "use-multiple", + "types": { + "the-type": 4, + "test": 5 + }, + "functions": { + "some-function": { + "name": "some-function", + "kind": "freestanding", + "params": [ + { + "name": "x", + "type": 4 + } + ], + "results": [ + { + "type": 5 + } + ] + } + }, + "package": 0 + }, + { + "name": "trailing-comma", + "types": { + "the-type": 6, + "the-foo": 7 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "the-type", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "the-type", + "kind": { + "type": 0 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "the-type", + "kind": { + "type": 1 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "test", + "kind": { + "type": 0 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "the-type", + "kind": { + "type": 2 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "test", + "kind": { + "type": 3 + }, + "owner": { + "interface": 5 + } + }, + { + "name": "the-type", + "kind": { + "type": 1 + }, + "owner": { + "interface": 6 + } + }, + { + "name": "the-foo", + "kind": { + "record": { + "fields": [ + { + "name": "a", + "type": 6 + } + ] + } + }, + "owner": { + "interface": 6 + } + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "bar": 0, + "foo": 1, + "baz": 2, + "empty": 3, + "use-from-empty": 4, + "use-multiple": 5, + "trailing-comma": 6 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/versions.wit.json b/crates/wit-parser/tests/ui/versions.wit.json new file mode 100644 index 0000000000..febd55be51 --- /dev/null +++ b/crates/wit-parser/tests/ui/versions.wit.json @@ -0,0 +1,91 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "foo", + "types": { + "t": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": "foo", + "types": { + "t": 1 + }, + "functions": {}, + "package": 1 + }, + { + "name": "foo", + "types": { + "t": 2, + "t2": 3 + }, + "functions": {}, + "package": 2 + } + ], + "types": [ + { + "name": "t", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 1 + } + }, + { + "name": "t", + "kind": { + "type": 0 + }, + "owner": { + "interface": 2 + } + }, + { + "name": "t2", + "kind": { + "type": 1 + }, + "owner": { + "interface": 2 + } + } + ], + "packages": [ + { + "name": "a:a@1.0.0", + "interfaces": { + "foo": 0 + }, + "worlds": {} + }, + { + "name": "a:a@2.0.0", + "interfaces": { + "foo": 1 + }, + "worlds": {} + }, + { + "name": "foo:versions", + "interfaces": { + "foo": 2 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/versions/deps/a1/foo.wit b/crates/wit-parser/tests/ui/versions/deps/a1/foo.wit new file mode 100644 index 0000000000..c9edd0e7b9 --- /dev/null +++ b/crates/wit-parser/tests/ui/versions/deps/a1/foo.wit @@ -0,0 +1,5 @@ +package a:a@1.0.0; + +interface foo { + type t = u32; +} diff --git a/crates/wit-parser/tests/ui/versions/deps/a2/foo.wit b/crates/wit-parser/tests/ui/versions/deps/a2/foo.wit new file mode 100644 index 0000000000..99b782cc8a --- /dev/null +++ b/crates/wit-parser/tests/ui/versions/deps/a2/foo.wit @@ -0,0 +1,5 @@ +package a:a@2.0.0; + +interface foo { + type t = u32; +} diff --git a/crates/wit-parser/tests/ui/versions/foo.wit b/crates/wit-parser/tests/ui/versions/foo.wit new file mode 100644 index 0000000000..0086bf0d0a --- /dev/null +++ b/crates/wit-parser/tests/ui/versions/foo.wit @@ -0,0 +1,7 @@ +package foo:versions; + +interface foo { + use a:a/foo@1.0.0.{t}; + use a:a/foo@2.0.0.{t as t2}; +} + diff --git a/crates/wit-parser/tests/ui/wasi.wit b/crates/wit-parser/tests/ui/wasi.wit new file mode 100644 index 0000000000..cf084a3fe8 --- /dev/null +++ b/crates/wit-parser/tests/ui/wasi.wit @@ -0,0 +1,178 @@ +package wasi:filesystem; + +interface wasi { + enum clockid { + // The clock measuring real time. Time value zero corresponds with + // 1970-01-01T00:00:00Z. + realtime, + // The store-wide monotonic clock, which is defined as a clock measuring + // real time, whose value cannot be adjusted and which cannot have negative + // clock jumps. The epoch of this clock is undefined. The absolute time + // value of this clock therefore has no meaning. + monotonic, + } + + // Timestamp in nanoseconds. + type timestamp = u64; + + // Error codes returned by functions. + // Not all of these error codes are returned by the functions provided by this + // API/ some are used in higher-level library layers, and others are provided + // merely for alignment with POSIX. + enum errno { + // No error occurred. System call completed successfully. + success, + // Argument list too long. + toobig, + // Permission denied. + access, + // Address in use. + addrinuse, + // Address not available. + addrnotavail, + // Address family not supported. + afnosupport, + // Resource unavailable, or operation would block. + again, + // Connection already in progress. + already, + // Bad file descriptor. + badf, + // Bad message. + badmsg, + // Device or resource busy. + busy, + // Operation canceled. + canceled, + // No child processes. + child, + // Connection aborted. + connaborted, + // Connection refused. + connrefused, + // Connection reset. + connreset, + // Resource deadlock would occur. + deadlk, + // Destination address required. + destaddrreq, + // Mathematics argument out of domain of function. + dom, + // Reserved. + dquot, + // File exists. + exist, + // Bad address. + fault, + // File too large. + fbig, + // Host is unreachable. + hostunreach, + // Identifier removed. + idrm, + // Illegal byte sequence. + ilseq, + // Operation in progress. + inprogress, + // Interrupted function. + intr, + // Invalid argument. + inval, + // I/O error. + io, + // Socket is connected. + isconn, + // Is a directory. + isdir, + // Too many levels of symbolic links. + loop, + // File descriptor value too large. + mfile, + // Too many links. + mlink, + // Message too large. + msgsize, + // Reserved. + multihop, + // Filename too long. + nametoolong, + // Network is down. + netdown, + // Connection aborted by network. + netreset, + // Network unreachable. + netunreach, + // Too many files open in system. + nfile, + // No buffer space available. + nobufs, + // No such device. + nodev, + // No such file or directory. + noent, + // Executable file format error. + noexec, + // No locks available. + nolck, + // Reserved. + nolink, + // Not enough space. + nomem, + // No message of the desired type. + nomsg, + // Protocol not available. + noprotoopt, + // No space left on device. + nospc, + // Function not supported. + nosys, + // The socket is not connected. + notconn, + // Not a directory or a symbolic link to a directory. + notdir, + // Directory not empty. + notempty, + // State not recoverable. + notrecoverable, + // Not a socket. + notsock, + // Not supported, or operation not supported on socket. + notsup, + // Inappropriate I/O control operation. + notty, + // No such device or address. + nxio, + // Value too large to be stored in data type. + overflow, + // Previous owner died. + ownerdead, + // Operation not permitted. + perm, + // Broken pipe. + pipe, + // Protocol error. + proto, + // Protocol not supported. + protonosupport, + // Protocol wrong type for socket. + prototype, + // Result too large. + range, + // Read-only file system. + rofs, + // Invalid seek. + spipe, + // No such process. + srch, + // Reserved. + stale, + // Connection timed out. + timedout, + // Text file busy. + txtbsy, + // Cross-device link. + xdev, + // Extension: Capabilities insufficient. + notcapable, + } +} diff --git a/crates/wit-parser/tests/ui/wasi.wit.json b/crates/wit-parser/tests/ui/wasi.wit.json new file mode 100644 index 0000000000..d568d859c9 --- /dev/null +++ b/crates/wit-parser/tests/ui/wasi.wit.json @@ -0,0 +1,296 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "wasi", + "types": { + "clockid": 0, + "timestamp": 1, + "errno": 2 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "clockid", + "kind": { + "enum": { + "cases": [ + { + "name": "realtime" + }, + { + "name": "monotonic" + } + ] + } + }, + "owner": { + "interface": 0 + } + }, + { + "name": "timestamp", + "kind": { + "type": "u64" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "errno", + "kind": { + "enum": { + "cases": [ + { + "name": "success" + }, + { + "name": "toobig" + }, + { + "name": "access" + }, + { + "name": "addrinuse" + }, + { + "name": "addrnotavail" + }, + { + "name": "afnosupport" + }, + { + "name": "again" + }, + { + "name": "already" + }, + { + "name": "badf" + }, + { + "name": "badmsg" + }, + { + "name": "busy" + }, + { + "name": "canceled" + }, + { + "name": "child" + }, + { + "name": "connaborted" + }, + { + "name": "connrefused" + }, + { + "name": "connreset" + }, + { + "name": "deadlk" + }, + { + "name": "destaddrreq" + }, + { + "name": "dom" + }, + { + "name": "dquot" + }, + { + "name": "exist" + }, + { + "name": "fault" + }, + { + "name": "fbig" + }, + { + "name": "hostunreach" + }, + { + "name": "idrm" + }, + { + "name": "ilseq" + }, + { + "name": "inprogress" + }, + { + "name": "intr" + }, + { + "name": "inval" + }, + { + "name": "io" + }, + { + "name": "isconn" + }, + { + "name": "isdir" + }, + { + "name": "loop" + }, + { + "name": "mfile" + }, + { + "name": "mlink" + }, + { + "name": "msgsize" + }, + { + "name": "multihop" + }, + { + "name": "nametoolong" + }, + { + "name": "netdown" + }, + { + "name": "netreset" + }, + { + "name": "netunreach" + }, + { + "name": "nfile" + }, + { + "name": "nobufs" + }, + { + "name": "nodev" + }, + { + "name": "noent" + }, + { + "name": "noexec" + }, + { + "name": "nolck" + }, + { + "name": "nolink" + }, + { + "name": "nomem" + }, + { + "name": "nomsg" + }, + { + "name": "noprotoopt" + }, + { + "name": "nospc" + }, + { + "name": "nosys" + }, + { + "name": "notconn" + }, + { + "name": "notdir" + }, + { + "name": "notempty" + }, + { + "name": "notrecoverable" + }, + { + "name": "notsock" + }, + { + "name": "notsup" + }, + { + "name": "notty" + }, + { + "name": "nxio" + }, + { + "name": "overflow" + }, + { + "name": "ownerdead" + }, + { + "name": "perm" + }, + { + "name": "pipe" + }, + { + "name": "proto" + }, + { + "name": "protonosupport" + }, + { + "name": "prototype" + }, + { + "name": "range" + }, + { + "name": "rofs" + }, + { + "name": "spipe" + }, + { + "name": "srch" + }, + { + "name": "stale" + }, + { + "name": "timedout" + }, + { + "name": "txtbsy" + }, + { + "name": "xdev" + }, + { + "name": "notcapable" + } + ] + } + }, + "owner": { + "interface": 0 + } + } + ], + "packages": [ + { + "name": "wasi:filesystem", + "interfaces": { + "wasi": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/world-diamond.wit b/crates/wit-parser/tests/ui/world-diamond.wit new file mode 100644 index 0000000000..e20e488eb8 --- /dev/null +++ b/crates/wit-parser/tests/ui/world-diamond.wit @@ -0,0 +1,23 @@ +package foo:foo; + +interface shared-items { + type foo = u32; +} + +interface i1 { + use shared-items.{foo}; + + a: func() -> foo; +} + +interface i2 { + use shared-items.{foo}; + + a: func() -> foo; +} + +world the-world { + import i1; + import i2; + import a: func(); +} diff --git a/crates/wit-parser/tests/ui/world-diamond.wit.json b/crates/wit-parser/tests/ui/world-diamond.wit.json new file mode 100644 index 0000000000..037141c345 --- /dev/null +++ b/crates/wit-parser/tests/ui/world-diamond.wit.json @@ -0,0 +1,118 @@ +{ + "worlds": [ + { + "name": "the-world", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-1": { + "interface": 1 + }, + "interface-2": { + "interface": 2 + }, + "a": { + "function": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [] + } + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "shared-items", + "types": { + "foo": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": "i1", + "types": { + "foo": 1 + }, + "functions": { + "a": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 1 + } + ] + } + }, + "package": 0 + }, + { + "name": "i2", + "types": { + "foo": 2 + }, + "functions": { + "a": { + "name": "a", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 2 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "foo", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "foo", + "kind": { + "type": 0 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "foo", + "kind": { + "type": 0 + }, + "owner": { + "interface": 2 + } + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "shared-items": 0, + "i1": 1, + "i2": 2 + }, + "worlds": { + "the-world": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/world-iface-no-collide.wit b/crates/wit-parser/tests/ui/world-iface-no-collide.wit new file mode 100644 index 0000000000..f68b1c9c8b --- /dev/null +++ b/crates/wit-parser/tests/ui/world-iface-no-collide.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface foo { + type t = u32; +} + +world bar { + use foo.{t}; + + import foo: func(); +} diff --git a/crates/wit-parser/tests/ui/world-iface-no-collide.wit.json b/crates/wit-parser/tests/ui/world-iface-no-collide.wit.json new file mode 100644 index 0000000000..b9ad08466f --- /dev/null +++ b/crates/wit-parser/tests/ui/world-iface-no-collide.wit.json @@ -0,0 +1,66 @@ +{ + "worlds": [ + { + "name": "bar", + "imports": { + "interface-0": { + "interface": 0 + }, + "t": { + "type": 1 + }, + "foo": { + "function": { + "name": "foo", + "kind": "freestanding", + "params": [], + "results": [] + } + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "foo", + "types": { + "t": 0 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "t", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "t", + "kind": { + "type": 0 + }, + "owner": { + "world": 0 + } + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "foo": 0 + }, + "worlds": { + "bar": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/world-implicit-import1.wit b/crates/wit-parser/tests/ui/world-implicit-import1.wit new file mode 100644 index 0000000000..48799813a9 --- /dev/null +++ b/crates/wit-parser/tests/ui/world-implicit-import1.wit @@ -0,0 +1,12 @@ +package foo:foo; + +interface foo { + type a = u32; +} + +world the-world { + import bar: interface { + use foo.{a}; + } + import foo: interface {} +} diff --git a/crates/wit-parser/tests/ui/world-implicit-import1.wit.json b/crates/wit-parser/tests/ui/world-implicit-import1.wit.json new file mode 100644 index 0000000000..f0b550b712 --- /dev/null +++ b/crates/wit-parser/tests/ui/world-implicit-import1.wit.json @@ -0,0 +1,75 @@ +{ + "worlds": [ + { + "name": "the-world", + "imports": { + "interface-0": { + "interface": 0 + }, + "bar": { + "interface": 1 + }, + "foo": { + "interface": 2 + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "foo", + "types": { + "a": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": null, + "types": { + "a": 1 + }, + "functions": {}, + "package": 0 + }, + { + "name": null, + "types": {}, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "a", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "a", + "kind": { + "type": 0 + }, + "owner": { + "interface": 1 + } + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "foo": 0 + }, + "worlds": { + "the-world": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/world-implicit-import2.wit b/crates/wit-parser/tests/ui/world-implicit-import2.wit new file mode 100644 index 0000000000..5e172e98f6 --- /dev/null +++ b/crates/wit-parser/tests/ui/world-implicit-import2.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface foo { + type g = char; +} + +world w { + use foo.{g}; + + import foo: func() -> g; +} diff --git a/crates/wit-parser/tests/ui/world-implicit-import2.wit.json b/crates/wit-parser/tests/ui/world-implicit-import2.wit.json new file mode 100644 index 0000000000..84e150e4db --- /dev/null +++ b/crates/wit-parser/tests/ui/world-implicit-import2.wit.json @@ -0,0 +1,70 @@ +{ + "worlds": [ + { + "name": "w", + "imports": { + "interface-0": { + "interface": 0 + }, + "g": { + "type": 1 + }, + "foo": { + "function": { + "name": "foo", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 1 + } + ] + } + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "foo", + "types": { + "g": 0 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "g", + "kind": { + "type": "char" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "g", + "kind": { + "type": 0 + }, + "owner": { + "world": 0 + } + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "foo": 0 + }, + "worlds": { + "w": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/world-implicit-import3.wit b/crates/wit-parser/tests/ui/world-implicit-import3.wit new file mode 100644 index 0000000000..ac62df255c --- /dev/null +++ b/crates/wit-parser/tests/ui/world-implicit-import3.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface foo { + type g = char; +} + +world w { + use foo.{g}; + + export foo: func() -> g; +} diff --git a/crates/wit-parser/tests/ui/world-implicit-import3.wit.json b/crates/wit-parser/tests/ui/world-implicit-import3.wit.json new file mode 100644 index 0000000000..3e716e41ef --- /dev/null +++ b/crates/wit-parser/tests/ui/world-implicit-import3.wit.json @@ -0,0 +1,71 @@ +{ + "worlds": [ + { + "name": "w", + "imports": { + "interface-0": { + "interface": 0 + }, + "g": { + "type": 1 + } + }, + "exports": { + "foo": { + "function": { + "name": "foo", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 1 + } + ] + } + } + }, + "package": 0 + } + ], + "interfaces": [ + { + "name": "foo", + "types": { + "g": 0 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "g", + "kind": { + "type": "char" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "g", + "kind": { + "type": 0 + }, + "owner": { + "world": 0 + } + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "foo": 0 + }, + "worlds": { + "w": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/world-same-fields4.wit b/crates/wit-parser/tests/ui/world-same-fields4.wit new file mode 100644 index 0000000000..f1fda3af56 --- /dev/null +++ b/crates/wit-parser/tests/ui/world-same-fields4.wit @@ -0,0 +1,13 @@ +package foo:foo; + +interface shared-items { + type a = u32; +} + +world foo { + import shared-items: interface {} + export a-name: interface { + use shared-items.{a}; + } +} + diff --git a/crates/wit-parser/tests/ui/world-same-fields4.wit.json b/crates/wit-parser/tests/ui/world-same-fields4.wit.json new file mode 100644 index 0000000000..c15baf187d --- /dev/null +++ b/crates/wit-parser/tests/ui/world-same-fields4.wit.json @@ -0,0 +1,76 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "shared-items": { + "interface": 1 + }, + "interface-0": { + "interface": 0 + } + }, + "exports": { + "a-name": { + "interface": 2 + } + }, + "package": 0 + } + ], + "interfaces": [ + { + "name": "shared-items", + "types": { + "a": 0 + }, + "functions": {}, + "package": 0 + }, + { + "name": null, + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": null, + "types": { + "a": 1 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "a", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "a", + "kind": { + "type": 0 + }, + "owner": { + "interface": 2 + } + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "shared-items": 0 + }, + "worlds": { + "foo": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/world-top-level-funcs.wit b/crates/wit-parser/tests/ui/world-top-level-funcs.wit new file mode 100644 index 0000000000..2adab9d5d6 --- /dev/null +++ b/crates/wit-parser/tests/ui/world-top-level-funcs.wit @@ -0,0 +1,9 @@ +package foo:foo; + +world foo { + import foo: func(); + export foo2: func(); + + import bar: func(arg: list); + export some-name: func() -> list>; +} diff --git a/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json b/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json new file mode 100644 index 0000000000..b7866aa12d --- /dev/null +++ b/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json @@ -0,0 +1,86 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "foo": { + "function": { + "name": "foo", + "kind": "freestanding", + "params": [], + "results": [] + } + }, + "bar": { + "function": { + "name": "bar", + "kind": "freestanding", + "params": [ + { + "name": "arg", + "type": 0 + } + ], + "results": [] + } + } + }, + "exports": { + "foo2": { + "function": { + "name": "foo2", + "kind": "freestanding", + "params": [], + "results": [] + } + }, + "some-name": { + "function": { + "name": "some-name", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 2 + } + ] + } + } + }, + "package": 0 + } + ], + "interfaces": [], + "types": [ + { + "name": null, + "kind": { + "list": "u32" + }, + "owner": null + }, + { + "name": null, + "kind": { + "option": "u32" + }, + "owner": null + }, + { + "name": null, + "kind": { + "list": 1 + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": {}, + "worlds": { + "foo": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/world-top-level-resources.wit b/crates/wit-parser/tests/ui/world-top-level-resources.wit new file mode 100644 index 0000000000..c236fc7d9e --- /dev/null +++ b/crates/wit-parser/tests/ui/world-top-level-resources.wit @@ -0,0 +1,24 @@ +package foo:foo; + +interface types { + resource request { + foo: func(); + bar: func(arg: list); + } + + resource response { + foo: func(); + bar: func(arg: list); + } +} + +interface handler { + use types.{request, response}; + handle: func(some: borrow) -> borrow; + handle-owned: func(some: own) -> own; +} + +world proxy { + import handler; + export handler; +} diff --git a/crates/wit-parser/tests/ui/world-top-level-resources.wit.json b/crates/wit-parser/tests/ui/world-top-level-resources.wit.json new file mode 100644 index 0000000000..ee1fd2c6f6 --- /dev/null +++ b/crates/wit-parser/tests/ui/world-top-level-resources.wit.json @@ -0,0 +1,240 @@ +{ + "worlds": [ + { + "name": "proxy", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-1": { + "interface": 1 + } + }, + "exports": { + "interface-1": { + "interface": 1 + } + }, + "package": 0 + } + ], + "interfaces": [ + { + "name": "types", + "types": { + "request": 0, + "response": 1 + }, + "functions": { + "[method]request.foo": { + "name": "[method]request.foo", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 2 + } + ], + "results": [] + }, + "[method]request.bar": { + "name": "[method]request.bar", + "kind": { + "method": 0 + }, + "params": [ + { + "name": "self", + "type": 2 + }, + { + "name": "arg", + "type": 3 + } + ], + "results": [] + }, + "[method]response.foo": { + "name": "[method]response.foo", + "kind": { + "method": 1 + }, + "params": [ + { + "name": "self", + "type": 4 + } + ], + "results": [] + }, + "[method]response.bar": { + "name": "[method]response.bar", + "kind": { + "method": 1 + }, + "params": [ + { + "name": "self", + "type": 4 + }, + { + "name": "arg", + "type": 3 + } + ], + "results": [] + } + }, + "package": 0 + }, + { + "name": "handler", + "types": { + "request": 5, + "response": 6 + }, + "functions": { + "handle": { + "name": "handle", + "kind": "freestanding", + "params": [ + { + "name": "some", + "type": 7 + } + ], + "results": [ + { + "type": 8 + } + ] + }, + "handle-owned": { + "name": "handle-owned", + "kind": "freestanding", + "params": [ + { + "name": "some", + "type": 9 + } + ], + "results": [ + { + "type": 10 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "request", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": "response", + "kind": "resource", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 0 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "list": "u32" + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 1 + } + }, + "owner": null + }, + { + "name": "request", + "kind": { + "type": 0 + }, + "owner": { + "interface": 1 + } + }, + { + "name": "response", + "kind": { + "type": 1 + }, + "owner": { + "interface": 1 + } + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 5 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "borrow": 6 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 5 + } + }, + "owner": null + }, + { + "name": null, + "kind": { + "handle": { + "own": 6 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "types": 0, + "handler": 1 + }, + "worlds": { + "proxy": 0 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/worlds-union-dedup.wit b/crates/wit-parser/tests/ui/worlds-union-dedup.wit new file mode 100644 index 0000000000..0e30a0b6cc --- /dev/null +++ b/crates/wit-parser/tests/ui/worlds-union-dedup.wit @@ -0,0 +1,23 @@ +package foo:foo; + +interface a1 { } +interface a2 { } +interface b1 { } +interface b2 { } +interface c { } +interface d { } + +world my-world-a { + import a1; + import b1; +} + +world my-world-b { + import a1; + import b1; +} + +world union-my-world { + include my-world-a; + include my-world-b; +} diff --git a/crates/wit-parser/tests/ui/worlds-union-dedup.wit.json b/crates/wit-parser/tests/ui/worlds-union-dedup.wit.json new file mode 100644 index 0000000000..7fb8ff0ae9 --- /dev/null +++ b/crates/wit-parser/tests/ui/worlds-union-dedup.wit.json @@ -0,0 +1,100 @@ +{ + "worlds": [ + { + "name": "my-world-a", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-2": { + "interface": 2 + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "my-world-b", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-2": { + "interface": 2 + } + }, + "exports": {}, + "package": 0 + }, + { + "name": "union-my-world", + "imports": { + "interface-0": { + "interface": 0 + }, + "interface-2": { + "interface": 2 + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "a1", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "a2", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "b1", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "b2", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "c", + "types": {}, + "functions": {}, + "package": 0 + }, + { + "name": "d", + "types": {}, + "functions": {}, + "package": 0 + } + ], + "types": [], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "a1": 0, + "a2": 1, + "b1": 2, + "b2": 3, + "c": 4, + "d": 5 + }, + "worlds": { + "my-world-a": 0, + "my-world-b": 1, + "union-my-world": 2 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/worlds-with-types.wit b/crates/wit-parser/tests/ui/worlds-with-types.wit new file mode 100644 index 0000000000..b0c015dfbd --- /dev/null +++ b/crates/wit-parser/tests/ui/worlds-with-types.wit @@ -0,0 +1,34 @@ +package foo:foo; + +world foo { + type a = u32; + type b = a; + + export c: func(a: a) -> b; +} + + +interface disambiguate { + type t = u32; +} + +world bar { + import disambiguate; + + use disambiguate.{t}; + + export foo: func() -> t; +} + +world the-test { + record a { + x: u32, + } + + variant b { + c(a), + } + + import foo: func(a: a) -> b; + export bar: func(a: a) -> b; +} diff --git a/crates/wit-parser/tests/ui/worlds-with-types.wit.json b/crates/wit-parser/tests/ui/worlds-with-types.wit.json new file mode 100644 index 0000000000..9ca60c0a3b --- /dev/null +++ b/crates/wit-parser/tests/ui/worlds-with-types.wit.json @@ -0,0 +1,202 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "a": { + "type": 1 + }, + "b": { + "type": 2 + } + }, + "exports": { + "c": { + "function": { + "name": "c", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 1 + } + ], + "results": [ + { + "type": 2 + } + ] + } + } + }, + "package": 0 + }, + { + "name": "bar", + "imports": { + "interface-0": { + "interface": 0 + }, + "t": { + "type": 3 + } + }, + "exports": { + "foo": { + "function": { + "name": "foo", + "kind": "freestanding", + "params": [], + "results": [ + { + "type": 3 + } + ] + } + } + }, + "package": 0 + }, + { + "name": "the-test", + "imports": { + "a": { + "type": 4 + }, + "b": { + "type": 5 + }, + "foo": { + "function": { + "name": "foo", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 4 + } + ], + "results": [ + { + "type": 5 + } + ] + } + } + }, + "exports": { + "bar": { + "function": { + "name": "bar", + "kind": "freestanding", + "params": [ + { + "name": "a", + "type": 4 + } + ], + "results": [ + { + "type": 5 + } + ] + } + } + }, + "package": 0 + } + ], + "interfaces": [ + { + "name": "disambiguate", + "types": { + "t": 0 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": "t", + "kind": { + "type": "u32" + }, + "owner": { + "interface": 0 + } + }, + { + "name": "a", + "kind": { + "type": "u32" + }, + "owner": { + "world": 0 + } + }, + { + "name": "b", + "kind": { + "type": 1 + }, + "owner": { + "world": 0 + } + }, + { + "name": "t", + "kind": { + "type": 0 + }, + "owner": { + "world": 1 + } + }, + { + "name": "a", + "kind": { + "record": { + "fields": [ + { + "name": "x", + "type": "u32" + } + ] + } + }, + "owner": { + "world": 2 + } + }, + { + "name": "b", + "kind": { + "variant": { + "cases": [ + { + "name": "c", + "type": 4 + } + ] + } + }, + "owner": { + "world": 2 + } + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "disambiguate": 0 + }, + "worlds": { + "foo": 0, + "bar": 1, + "the-test": 2 + } + } + ] +} \ No newline at end of file diff --git a/crates/wit-smith/Cargo.toml b/crates/wit-smith/Cargo.toml new file mode 100644 index 0000000000..9e86e922a1 --- /dev/null +++ b/crates/wit-smith/Cargo.toml @@ -0,0 +1,17 @@ +[package] +description = "A WIT test case generator" +documentation = "https://docs.rs/wit-smith" +edition.workspace = true +license = "Apache-2.0 WITH LLVM-exception" +name = "wit-smith" +repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-smith" +version = "0.1.17" + +[dependencies] +arbitrary = { workspace = true, features = ["derive"] } +wit-component = { workspace = true } +wit-parser = { workspace = true } +clap = { workspace = true, optional = true } +indexmap = { workspace = true } +log = { workspace = true } +semver = { workspace = true } diff --git a/crates/wit-smith/src/config.rs b/crates/wit-smith/src/config.rs new file mode 100644 index 0000000000..ea837c5cfd --- /dev/null +++ b/crates/wit-smith/src/config.rs @@ -0,0 +1,52 @@ +use arbitrary::{Arbitrary, Result, Unstructured}; + +#[derive(Debug, Clone)] +#[cfg_attr(feature = "clap", derive(clap::Parser))] +pub struct Config { + #[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().max_packages))] + pub max_packages: usize, + #[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().max_type_size))] + pub max_type_size: usize, + #[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().max_interface_items))] + pub max_interface_items: usize, + #[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().max_world_items))] + pub max_world_items: usize, + #[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().max_pkg_items))] + pub max_pkg_items: usize, + #[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().max_type_parts))] + pub max_type_parts: usize, + #[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().max_files_per_package))] + pub max_files_per_package: usize, + #[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().max_resource_items))] + pub max_resource_items: usize, +} + +impl Default for Config { + fn default() -> Config { + Config { + max_packages: 10, + max_type_size: 100, + max_interface_items: 10, + max_world_items: 10, + max_pkg_items: 10, + max_type_parts: 10, + max_files_per_package: 10, + max_resource_items: 10, + } + } +} + +impl Arbitrary<'_> for Config { + fn arbitrary(u: &mut Unstructured<'_>) -> Result { + Ok(Config { + max_packages: u.int_in_range(1..=20)?, + max_files_per_package: u.int_in_range(1..=10)?, + max_type_size: u.int_in_range(0..=1000)?, + max_interface_items: u.int_in_range(0..=20)?, + max_world_items: u.int_in_range(0..=10)?, + max_pkg_items: u.int_in_range(0..=10)?, + max_type_parts: u.int_in_range(1..=10)?, + max_resource_items: u.int_in_range(0..=10)?, + }) + } +} diff --git a/crates/wit-smith/src/generate.rs b/crates/wit-smith/src/generate.rs new file mode 100644 index 0000000000..66d8a7b9e8 --- /dev/null +++ b/crates/wit-smith/src/generate.rs @@ -0,0 +1,1003 @@ +use crate::config::Config; +use arbitrary::{Arbitrary, Result, Unstructured}; +use indexmap::IndexMap; +use semver::Version; +use std::collections::hash_map::{Entry, HashMap}; +use std::collections::HashSet; +use std::fmt::Write; +use std::rc::Rc; +use std::str; +use wit_parser::*; + +pub struct Generator { + config: Config, + packages: PackageList, + next_interface_id: u32, +} + +type TypeList = Vec; +type InterfaceList = IndexMap; +type PackageList = Vec<(PackageName, InterfaceList)>; + +struct InterfaceGenerator<'a> { + gen: &'a Generator, + file: &'a mut File, + config: &'a Config, + unique_names: HashSet, + types_in_interface: TypeList, +} + +#[derive(Clone)] +struct Type { + name: String, + size: usize, + is_resource: bool, +} + +pub struct Package { + pub name: PackageName, + pub sources: SourceMap, +} + +#[derive(Clone)] +pub struct PackageName { + pub namespace: String, + pub name: String, + pub version: Option, +} + +impl Generator { + pub fn new(config: Config) -> Generator { + Generator { + config, + packages: Default::default(), + next_interface_id: 0, + } + } + + pub fn gen(&mut self, u: &mut Unstructured<'_>) -> Result> { + let mut packages = Vec::new(); + let mut names = HashSet::new(); + while packages.len() < self.config.max_packages && (packages.is_empty() || u.arbitrary()?) { + let (pkg, interfaces) = self.gen_package(u, &mut names)?; + if interfaces.len() > 0 { + self.packages.push((pkg.name.clone(), interfaces)); + } + packages.push(pkg); + } + Ok(packages) + } + + fn gen_package( + &mut self, + u: &mut Unstructured<'_>, + names: &mut HashSet, + ) -> Result<(Package, InterfaceList)> { + let namespace = gen_unique_name(u, names)?; + let name = gen_unique_name(u, names)?; + let version = if u.arbitrary()? { + Some(gen_version(u)?) + } else { + None + }; + let mut ret = Package { + name: PackageName { + namespace, + name, + version, + }, + sources: SourceMap::new(), + }; + + #[derive(Arbitrary)] + enum Generate { + Interface, + Use, + World, + Done, + } + + let mut items = 0; + let mut files = vec![File::default()]; + let mut package_names = HashSet::new(); + let mut package = File::default(); + log::debug!("===================== new package ===================="); + while items < self.config.max_pkg_items && !u.is_empty() { + items += 1; + let max = if files.len() < self.config.max_files_per_package { + files.len() + 1 + } else { + files.len() + }; + let i = u.int_in_range(0..=max)?; + let file = match files.get_mut(i) { + Some(file) => file, + None => { + files.push(File { + items: Vec::new(), + namespace: package + .interfaces + .iter() + .map(|(k, _)| (k.clone(), Definition::Package)) + .collect(), + interfaces: package.interfaces.clone(), + }); + files.last_mut().unwrap() + } + }; + match u.arbitrary()? { + Generate::World => { + let name = file.gen_unique_package_name(u, &mut package_names)?; + log::debug!("new world `{name}` in {i}"); + let world = self.gen_world(u, &name, file)?; + file.items.push(world); + } + Generate::Interface => { + let name = file.gen_unique_package_name(u, &mut package_names)?; + log::debug!("new interface `{name}` in {i}"); + let id = self.next_interface_id; + self.next_interface_id += 1; + let (src, types) = self.gen_interface(u, Some(&name), file)?; + file.items.push(src); + if types.is_empty() { + continue; + } + let interface = FileInterface { + name, + id, + types: Rc::new(types), + }; + + // This interface is defined at the package level, and it + // must be unique. + let prev = package + .interfaces + .insert(interface.name.clone(), interface.clone()); + assert!(prev.is_none()); + + // This is also defined at the file level, and it must be + // unique here too. + let prev = file + .interfaces + .insert(interface.name.clone(), interface.clone()); + assert!(prev.is_none()); + + // Insert the definition into all other files as well. + for file in files.iter_mut() { + file.insert_definition(interface.clone()); + } + } + Generate::Use => { + let mut piece = String::new(); + piece.push_str("use "); + let (name, id, types) = match self.gen_path(u, &mut package, &mut piece)? { + Some(i) => i, + None => continue, + }; + let name = name.to_string(); + let types = types.clone(); + let name = + if file.namespace.get(&name) == Some(&Definition::File) || u.arbitrary()? { + let name = file.gen_unique_file_name(u)?; + piece.push_str(" as %"); + piece.push_str(&name); + name + } else { + file.namespace.insert(name.clone(), Definition::File); + name + }; + log::debug!("new use `{name}` in {i}"); + file.interfaces + .insert(name.clone(), FileInterface { name, id, types }); + file.items.push(piece) + } + Generate::Done => break, + }; + } + + shuffle(u, &mut files)?; + for file in files.iter_mut() { + shuffle(u, &mut file.items)?; + } + + let mut has_name = false; + let len = files.len(); + for (i, file) in files.iter_mut().enumerate() { + let mut s = String::new(); + if u.arbitrary()? || (!has_name && i == len - 1) { + has_name = true; + s.push_str("package "); + s.push_str("%"); + s.push_str(&ret.name.namespace); + s.push_str(":"); + s.push_str("%"); + s.push_str(&ret.name.name); + if let Some(version) = &ret.name.version { + s.push_str(&format!("@{version}")); + } + s.push_str("\n\n"); + } + for piece in file.items.iter() { + s.push_str(&piece); + s.push_str("\n\n"); + } + log::trace!("==============================================="); + log::trace!("{s}"); + ret.sources.push(format!("wit{i}.wit").as_ref(), &s); + } + Ok((ret, package.interfaces)) + } + + fn gen_world( + &mut self, + u: &mut Unstructured<'_>, + name: &str, + file: &mut File, + ) -> Result { + InterfaceGenerator::new(self, file).gen_world(u, name) + } + + fn gen_interface( + &mut self, + u: &mut Unstructured<'_>, + name: Option<&str>, + file: &mut File, + ) -> Result<(String, TypeList)> { + let mut gen = InterfaceGenerator::new(self, file); + let ret = gen.gen_interface(u, name)?; + Ok((ret, gen.types_in_interface)) + } + + fn gen_path<'a>( + &'a self, + u: &mut Unstructured<'_>, + file: &'a mut File, + dst: &mut String, + ) -> Result)>> { + enum Choice { + Interfaces, + Packages, + } + let mut choices = Vec::new(); + if !file.interfaces.is_empty() { + choices.push(Choice::Interfaces); + } + if !self.packages.is_empty() { + choices.push(Choice::Packages); + } + if choices.is_empty() { + return Ok(None); + } + Ok(match u.choose(&choices)? { + Choice::Interfaces => { + let i = u.int_in_range(0..=file.interfaces.len() - 1)?; + let (name, i) = file.interfaces.get_index(i).unwrap(); + // Once a name is used from a file's local namespace then it + // can't be overridden in that namespace so switch it to a file + // definition from whatever it previously was. + file.namespace.insert(name.clone(), Definition::File); + dst.push_str("%"); + dst.push_str(&i.name); + Some((&i.name, i.id, &i.types)) + } + Choice::Packages => { + let (pkg, ifaces) = u.choose(&self.packages)?; + dst.push_str("%"); + dst.push_str(&pkg.namespace); + dst.push_str(":"); + dst.push_str("%"); + dst.push_str(&pkg.name); + dst.push_str("/"); + let i = u.int_in_range(0..=ifaces.len() - 1)?; + let i = &ifaces[i]; + dst.push_str("%"); + dst.push_str(&i.name); + if let Some(version) = &pkg.version { + dst.push_str(&format!("@{version}")); + } + Some((&i.name, i.id, &i.types)) + } + }) + } +} + +impl<'a> InterfaceGenerator<'a> { + fn new(gen: &'a Generator, file: &'a mut File) -> InterfaceGenerator<'a> { + // Claim the name `memory` to avoid conflicting with the canonical ABI + // always using a linear memory named `memory`. + let mut unique_names = HashSet::new(); + unique_names.insert("memory".to_string()); + InterfaceGenerator { + gen, + file, + config: &gen.config, + types_in_interface: Vec::new(), + unique_names, + } + } + + fn gen_interface(&mut self, u: &mut Unstructured<'_>, name: Option<&str>) -> Result { + let mut ret = String::new(); + ret.push_str("interface "); + if let Some(name) = name { + ret.push_str("%"); + ret.push_str(name); + ret.push_str(" "); + } + ret.push_str("{\n"); + + #[derive(Arbitrary)] + enum Generate { + Use, + Type, + Function, + } + + let mut parts = Vec::new(); + while parts.len() < self.config.max_interface_items && u.arbitrary()? { + match u.arbitrary()? { + Generate::Use => { + let mut part = String::new(); + if self.gen_use(u, &mut part)? { + parts.push(part); + } + } + Generate::Type => { + let name = self.gen_unique_name(u)?; + let (ty, mut typedef) = self.gen_typedef(u, &name)?; + let is_resource = ty.is_resource; + self.types_in_interface.push(ty); + if is_resource && u.arbitrary()? { + typedef.push_str(" {\n"); + self.gen_resource_funcs(u, &mut typedef)?; + typedef.push_str("}"); + } + parts.push(typedef); + } + Generate::Function => { + parts.push(self.gen_func(u)?); + } + } + } + + shuffle(u, &mut parts)?; + for part in parts { + ret.push_str(&part); + ret.push_str("\n\n"); + } + + ret.push_str("}"); + Ok(ret) + } + + fn gen_world(&mut self, u: &mut Unstructured<'_>, name: &str) -> Result { + let mut ret = String::new(); + ret.push_str("world %"); + ret.push_str(name); + ret.push_str(" {\n"); + + #[derive(Arbitrary, Copy, Clone)] + enum Direction { + Import, + Export, + } + + #[derive(Arbitrary)] + enum ItemKind { + Func(Direction), + Interface(Direction), + AnonInterface(Direction), + Type, + Use, + } + + let mut parts = Vec::new(); + let mut imported_interfaces = HashSet::new(); + let mut exported_interfaces = HashSet::new(); + + while parts.len() < self.config.max_world_items && !u.is_empty() && u.arbitrary()? { + let kind = u.arbitrary::()?; + let (direction, named) = match kind { + ItemKind::Func(dir) | ItemKind::AnonInterface(dir) => (Some(dir), true), + ItemKind::Interface(dir) => (Some(dir), false), + ItemKind::Type => (None, true), + ItemKind::Use => (None, false), + }; + + let mut part = String::new(); + if let Some(dir) = direction { + part.push_str(match dir { + Direction::Import => "import ", + Direction::Export => "export ", + }); + } + + let name = if named { + let name = gen_unique_name(u, &mut self.unique_names)?; + if direction.is_some() { + part.push_str("%"); + part.push_str(&name); + part.push_str(": "); + } + Some(name) + } else { + None + }; + + match kind { + ItemKind::Func(_) => { + self.gen_func_sig(u, &mut part, false)?; + } + ItemKind::Interface(dir) => { + let id = match self.gen.gen_path(u, self.file, &mut part)? { + Some((_name, id, _types)) => id, + // If an interface couldn't be chosen or wasn't + // chosen then skip this import. A unique name was + // selecteed above but we just sort of leave that + // floating in the wild to get handled by some other + // test case. + None => continue, + }; + + // If this interface has already been imported or + // exported this document can't do so again. Throw out + // this item in that situation. + let unique = match dir { + Direction::Import => imported_interfaces.insert(id), + Direction::Export => exported_interfaces.insert(id), + }; + if !unique { + continue; + } + } + ItemKind::AnonInterface(_) => { + let iface = + InterfaceGenerator::new(self.gen, self.file).gen_interface(u, None)?; + part.push_str(&iface); + } + + ItemKind::Type => { + let name = name.unwrap(); + let (ty, typedef) = self.gen_typedef(u, &name)?; + assert!(part.is_empty()); + part = typedef; + let is_resource = ty.is_resource; + self.types_in_interface.push(ty); + + if is_resource && u.arbitrary()? { + part.push_str(" {\n"); + self.gen_resource_funcs(u, &mut part)?; + part.push_str("}"); + } + } + + ItemKind::Use => { + if !self.gen_use(u, &mut part)? { + continue; + } + } + } + parts.push(part); + } + + shuffle(u, &mut parts)?; + + for part in parts { + ret.push_str(&part); + ret.push_str("\n"); + } + + ret.push_str("}"); + + Ok(ret) + } + + fn gen_resource_funcs(&mut self, u: &mut Unstructured<'_>, ret: &mut String) -> Result<()> { + let mut parts = Vec::new(); + + #[derive(Arbitrary)] + enum Item { + Constructor, + Static, + Method, + } + + let mut has_constructor = false; + let mut names = HashSet::new(); + while parts.len() < self.config.max_resource_items && !u.is_empty() && u.arbitrary()? { + match u.arbitrary()? { + Item::Constructor if has_constructor => {} + Item::Constructor => { + has_constructor = true; + let mut part = format!("constructor"); + self.gen_params(u, &mut part, false)?; + parts.push(part); + } + Item::Static => { + let mut part = format!("%"); + part.push_str(&gen_unique_name(u, &mut names)?); + part.push_str(": static "); + self.gen_func_sig(u, &mut part, false)?; + parts.push(part); + } + Item::Method => { + let mut part = format!("%"); + part.push_str(&gen_unique_name(u, &mut names)?); + part.push_str(": "); + self.gen_func_sig(u, &mut part, true)?; + parts.push(part); + } + } + } + + shuffle(u, &mut parts)?; + + for part in parts { + ret.push_str(&part); + ret.push_str("\n"); + } + Ok(()) + } + + fn gen_use(&mut self, u: &mut Unstructured<'_>, part: &mut String) -> Result { + let mut path = String::new(); + let (_name, _id, types) = match self.gen.gen_path(u, self.file, &mut path)? { + Some(types) => types, + None => return Ok(false), + }; + part.push_str("use "); + part.push_str(&path); + part.push_str(".{"); + let ty = u.choose(types)?; + part.push_str("%"); + part.push_str(&ty.name); + let size = ty.size; + let is_resource = ty.is_resource; + let name = if self.unique_names.contains(&ty.name) || u.arbitrary()? { + part.push_str(" as %"); + let name = self.gen_unique_name(u)?; + part.push_str(&name); + name + } else { + assert!(self.unique_names.insert(ty.name.clone())); + ty.name.clone() + }; + self.types_in_interface.push(Type { + name, + size, + is_resource, + }); + part.push_str("}"); + Ok(true) + } + + fn gen_typedef(&mut self, u: &mut Unstructured<'_>, name: &str) -> Result<(Type, String)> { + #[derive(Arbitrary)] + pub enum Kind { + Record, + Flags, + Variant, + Enum, + Anonymous, + Resource, + } + + let mut fuel = self.config.max_type_size; + let mut ret = String::new(); + let mut is_resource = false; + match u.arbitrary()? { + Kind::Record => { + ret.push_str("record %"); + ret.push_str(name); + ret.push_str(" {\n"); + for _ in 0..u.int_in_range(1..=self.config.max_type_parts)? { + ret.push_str(" %"); + ret.push_str(&self.gen_unique_name(u)?); + ret.push_str(": "); + self.gen_type(u, &mut fuel, &mut ret)?; + ret.push_str(",\n"); + } + ret.push_str("}"); + } + Kind::Variant => { + ret.push_str("variant %"); + ret.push_str(name); + ret.push_str(" {\n"); + for _ in 0..u.int_in_range(1..=self.config.max_type_parts)? { + ret.push_str(" %"); + ret.push_str(&self.gen_unique_name(u)?); + if u.arbitrary()? { + ret.push_str("("); + self.gen_type(u, &mut fuel, &mut ret)?; + ret.push_str(")"); + } + ret.push_str(",\n"); + } + ret.push_str("}"); + } + Kind::Enum => { + ret.push_str("enum %"); + ret.push_str(name); + ret.push_str(" {\n"); + for _ in 0..u.int_in_range(1..=self.config.max_type_parts)? { + ret.push_str(" %"); + ret.push_str(&self.gen_unique_name(u)?); + ret.push_str(",\n"); + } + ret.push_str("}"); + } + Kind::Flags => { + ret.push_str("flags %"); + ret.push_str(name); + ret.push_str(" {\n"); + for _ in 0..u.int_in_range(1..=self.config.max_type_parts)? { + ret.push_str(" %"); + ret.push_str(&self.gen_unique_name(u)?); + ret.push_str(",\n"); + } + ret.push_str("}"); + } + Kind::Anonymous => { + ret.push_str("type %"); + ret.push_str(name); + ret.push_str(" = "); + self.gen_type(u, &mut fuel, &mut ret)?; + } + Kind::Resource => { + is_resource = true; + ret.push_str("resource %"); + ret.push_str(name); + } + } + + let ty = Type { + size: self.config.max_type_size - fuel, + is_resource, + name: name.to_string(), + }; + Ok((ty, ret)) + } + + fn gen_type( + &mut self, + u: &mut Unstructured<'_>, + fuel: &mut usize, + dst: &mut String, + ) -> Result<()> { + #[derive(Arbitrary)] + enum Kind { + Bool, + U8, + U16, + U32, + U64, + S8, + S16, + S32, + S64, + Float32, + Float64, + Char, + String, + Id, + Tuple, + Option, + Result, + List, + } + + *fuel = match fuel.checked_sub(1) { + Some(fuel) => fuel, + None => { + dst.push_str("bool"); + return Ok(()); + } + }; + loop { + break match u.arbitrary()? { + Kind::Bool => dst.push_str("bool"), + Kind::U8 => dst.push_str("u8"), + Kind::S8 => dst.push_str("s8"), + Kind::U16 => dst.push_str("u16"), + Kind::S16 => dst.push_str("s16"), + Kind::U32 => dst.push_str("u32"), + Kind::S32 => dst.push_str("s32"), + Kind::U64 => dst.push_str("u64"), + Kind::S64 => dst.push_str("s64"), + Kind::Float32 => dst.push_str("float32"), + Kind::Float64 => dst.push_str("float64"), + Kind::Char => dst.push_str("char"), + Kind::String => dst.push_str("string"), + Kind::Id => { + if self.types_in_interface.is_empty() { + continue; + } + let ty = u.choose(&self.types_in_interface)?; + *fuel = match fuel.checked_sub(ty.size) { + Some(fuel) => fuel, + None => continue, + }; + let own_wrapper = if ty.is_resource && u.arbitrary()? { + dst.push_str("own<"); + true + } else { + false + }; + dst.push_str("%"); + dst.push_str(&ty.name); + if own_wrapper { + dst.push_str(">"); + } + } + Kind::Tuple => { + let fields = u.int_in_range(1..=self.config.max_type_parts)?; + *fuel = match fuel.checked_sub(fields) { + Some(fuel) => fuel, + None => continue, + }; + dst.push_str("tuple<"); + for i in 0..fields { + if i > 0 { + dst.push_str(", "); + } + self.gen_type(u, fuel, dst)?; + } + dst.push_str(">"); + } + Kind::Option => { + *fuel = match fuel.checked_sub(1) { + Some(fuel) => fuel, + None => continue, + }; + dst.push_str("option<"); + self.gen_type(u, fuel, dst)?; + dst.push_str(">"); + } + Kind::List => { + *fuel = match fuel.checked_sub(1) { + Some(fuel) => fuel, + None => continue, + }; + dst.push_str("list<"); + self.gen_type(u, fuel, dst)?; + dst.push_str(">"); + } + Kind::Result => { + *fuel = match fuel.checked_sub(2) { + Some(fuel) => fuel, + None => continue, + }; + dst.push_str("result"); + let ok = u.arbitrary()?; + let err = u.arbitrary()?; + match (ok, err) { + (true, true) => { + dst.push_str("<"); + self.gen_type(u, fuel, dst)?; + dst.push_str(", "); + self.gen_type(u, fuel, dst)?; + dst.push_str(">"); + } + (true, false) => { + dst.push_str("<"); + self.gen_type(u, fuel, dst)?; + dst.push_str(">"); + } + (false, true) => { + dst.push_str("<_, "); + self.gen_type(u, fuel, dst)?; + dst.push_str(">"); + } + (false, false) => {} + } + } + }; + } + + Ok(()) + } + + fn gen_func(&mut self, u: &mut Unstructured<'_>) -> Result { + let mut ret = "%".to_string(); + ret.push_str(&self.gen_unique_name(u)?); + ret.push_str(": "); + self.gen_func_sig(u, &mut ret, false)?; + Ok(ret) + } + + fn gen_func_sig( + &mut self, + u: &mut Unstructured<'_>, + dst: &mut String, + method: bool, + ) -> Result<()> { + dst.push_str("func"); + self.gen_params(u, dst, method)?; + if u.arbitrary()? { + dst.push_str(" -> "); + self.gen_params(u, dst, false)?; + } else if u.arbitrary()? { + dst.push_str(" -> "); + let mut fuel = self.config.max_type_size; + self.gen_type(u, &mut fuel, dst)?; + } + Ok(()) + } + + fn gen_params( + &mut self, + u: &mut Unstructured<'_>, + dst: &mut String, + method: bool, + ) -> Result<()> { + dst.push_str("("); + let mut names = HashSet::new(); + if method { + names.insert("self".to_string()); + } + let mut fuel = self.config.max_type_size; + for i in 0..u.int_in_range(0..=self.config.max_type_parts)? { + if i > 0 { + dst.push_str(", "); + } + dst.push_str("%"); + dst.push_str(&gen_unique_name(u, &mut names)?); + dst.push_str(": "); + self.gen_type(u, &mut fuel, dst)?; + } + dst.push_str(")"); + Ok(()) + } + + fn gen_unique_name(&mut self, u: &mut Unstructured<'_>) -> Result { + gen_unique_name(u, &mut self.unique_names) + } +} + +fn gen_unique_name(u: &mut Unstructured<'_>, set: &mut HashSet) -> Result { + let mut name = gen_name(u)?; + while !set.insert(name.clone()) { + write!(&mut name, "{}", set.len()).unwrap(); + } + Ok(name) +} + +fn gen_name(u: &mut Unstructured<'_>) -> Result { + let size = u.arbitrary_len::()?; + let size = std::cmp::min(size, 20); + let name = match str::from_utf8(u.peek_bytes(size).unwrap()) { + Ok(s) => { + u.bytes(size).unwrap(); + s.to_string() + } + Err(e) => { + let i = e.valid_up_to(); + let valid = u.bytes(i).unwrap(); + str::from_utf8(valid).unwrap().to_string() + } + }; + let name = name + .chars() + .map(|x| if x.is_ascii_lowercase() { x } else { 'x' }) + .collect::(); + Ok(if name.is_empty() { + "name".to_string() + } else { + name + }) +} + +fn shuffle(u: &mut Unstructured<'_>, mut slice: &mut [T]) -> Result<()> { + while slice.len() > 0 { + let pos = u.int_in_range(0..=slice.len() - 1)?; + slice.swap(0, pos); + slice = &mut slice[1..]; + } + Ok(()) +} + +#[derive(Default)] +struct File { + items: Vec, + namespace: HashMap, + interfaces: IndexMap, +} + +#[derive(Clone)] +struct FileInterface { + name: String, + id: u32, + types: Rc, +} + +#[derive(PartialEq)] +enum Definition { + Package, + File, +} + +impl File { + fn gen_unique_package_name( + &mut self, + u: &mut Unstructured<'_>, + names: &mut HashSet, + ) -> Result { + let mut name = gen_name(u)?; + loop { + // Find a package-unique name first + if !names.insert(name.clone()) { + write!(&mut name, "{}", names.len()).unwrap(); + continue; + } + + // Then make sure it's file-unique too + if self.claim_file_name(&mut name) { + break; + } + } + Ok(name) + } + + fn gen_unique_file_name(&mut self, u: &mut Unstructured<'_>) -> Result { + let mut name = gen_name(u)?; + while !self.claim_file_name(&mut name) { + // try again on the next iteration + } + Ok(name) + } + + fn claim_file_name(&mut self, name: &mut String) -> bool { + match self.namespace.entry(name.clone()) { + Entry::Occupied(mut e) => match e.get() { + // If this name is already claimed elsewhere in the package + // then that's ok as we're going to shadow it, so switch it + // to a file definition. + Definition::Package => *e.get_mut() = Definition::File, + + // If it's already defined in the file try to add more stuff + // to the name to make the next try not collide. + Definition::File => { + name.push_str("y"); + write!(name, "{}", self.namespace.len()).unwrap(); + return false; + } + }, + + // Not defined? Claim it. + Entry::Vacant(v) => { + v.insert(Definition::File); + } + } + true + } + + fn insert_definition(&mut self, def: FileInterface) { + match self.namespace.get(&def.name) { + Some(Definition::File) => return, + Some(Definition::Package) => unreachable!(), + None => {} + } + let prev = self.namespace.insert(def.name.clone(), Definition::Package); + assert!(prev.is_none()); + let prev = self.interfaces.insert(def.name.clone(), def); + assert!(prev.is_none()); + } +} + +fn gen_version(u: &mut Unstructured<'_>) -> Result { + Ok(Version { + major: u.int_in_range(0..=10)?, + minor: u.int_in_range(0..=10)?, + patch: u.int_in_range(0..=10)?, + pre: if u.arbitrary()? { + semver::Prerelease::new("alpha.0").unwrap() + } else { + semver::Prerelease::EMPTY + }, + build: if u.arbitrary()? { + semver::BuildMetadata::new("1.2.0").unwrap() + } else { + semver::BuildMetadata::EMPTY + }, + }) +} diff --git a/crates/wit-smith/src/lib.rs b/crates/wit-smith/src/lib.rs new file mode 100644 index 0000000000..bbd5e86338 --- /dev/null +++ b/crates/wit-smith/src/lib.rs @@ -0,0 +1,42 @@ +//! A small crate to generate arbitrary WIT documents. +//! +//! This crate is modeled after the `wasm-smith` crate but is used to generate +//! WIT documents instead of WebAssembly modules. This crate is intended to +//! generate "interesting" WIT package structures in addition to interesting +//! type structures. + +use arbitrary::{Result, Unstructured}; +use wit_parser::Resolve; + +mod config; +pub use self::config::Config; +mod generate; + +/// Generates an arbitrary WIT document encoded as a WebAssembly binary. +/// +/// The `config` guides the generation of the document and the `u` bytes are +/// used as input to construct the document. +pub fn smith(config: &Config, u: &mut Unstructured<'_>) -> Result> { + let pkgs = generate::Generator::new(config.clone()).gen(u)?; + let mut resolve = Resolve::default(); + let mut last = None; + for pkg in pkgs { + let unresolved = pkg.sources.parse().unwrap(); + let id = match resolve.push(unresolved) { + Ok(id) => id, + Err(e) => { + if e.to_string().contains( + "interface transitively depends on an interface in \ + incompatible ways", + ) { + return Err(arbitrary::Error::IncorrectFormat); + } + panic!("bad wit parse: {e:?}") + } + }; + last = Some(id); + } + let pkg = last.unwrap(); + + Ok(wit_component::encode(&resolve, pkg).expect("failed to encode WIT document")) +} diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index ce01922302..b163b513ea 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -2,63 +2,36 @@ name = "wasm-tools-fuzz" version = "0.0.1" publish = false -edition = "2021" +edition.workspace = true [package.metadata] cargo-fuzz = true [dependencies] -anyhow = "1" -arbitrary = "1" -env_logger = "0.9" -libfuzzer-sys = "0.4.0" -log = "0.4" +anyhow = { workspace = true } +arbitrary = { workspace = true } +env_logger = { workspace = true } +libfuzzer-sys = { workspace = true } +log = { workspace = true } tempfile = "3.0" wasm-mutate = { path = "../crates/wasm-mutate" } wasm-smith = { path = "../crates/wasm-smith" } wasmparser = { path = "../crates/wasmparser" } wasmprinter = { path = "../crates/wasmprinter" } -wasmtime = { version = "0.38.1", optional = true } +wasmtime = { workspace = true, optional = true } wast = { path = "../crates/wast" } wat = { path = "../crates/wat" } +wit-parser = { path = "../crates/wit-parser" } +wit-smith = { path = "../crates/wit-smith" } +wit-component = { path = "../crates/wit-component", features = ['dummy-module'] } +wasm-encoder = { path = "../crates/wasm-encoder" } [lib] test = false doctest = false [[bin]] -name = "text-parser" -path = "fuzz_targets/text-parser.rs" +name = "run" +path = "fuzz_targets/run.rs" test = false - -[[bin]] -name = "validate" -path = "fuzz_targets/validate.rs" -test = false - -[[bin]] -name = "print" -path = "fuzz_targets/print.rs" -test = false - -[[bin]] -name = "roundtrip" -path = "fuzz_targets/roundtrip.rs" -test = false - -[[bin]] -name = "incremental-parse" -path = "fuzz_targets/incremental-parse.rs" -test = false - -[[bin]] -name = "validate-valid-module" -path = "fuzz_targets/validate-valid-module.rs" -test = false -doc = false - -[[bin]] -name = "mutate" -path = "fuzz_targets/mutate.rs" -test = false -doc = false +bench = false diff --git a/fuzz/fuzz_targets/incremental-parse.rs b/fuzz/fuzz_targets/incremental-parse.rs deleted file mode 100644 index 2bef49f2a0..0000000000 --- a/fuzz/fuzz_targets/incremental-parse.rs +++ /dev/null @@ -1,216 +0,0 @@ -#![no_main] - -use libfuzzer_sys::*; -use wasmparser::*; -use Payload::*; - -// Simulate receiving chunks of data by fuzzing over a `Vec>` where each -// element of the outer vec is a chunk of data we received. -// -// The assertion here is that parsing everything in one go should always produce -// the exact same results as an incremental parse. -fuzz_target!(|data: Vec>| { - drop(env_logger::try_init()); - - // Concatenate everything together, create our expected iterator of - // payloads, and then write out `input.wasm` if debugging is enabled. - let everything = data.iter().flat_map(|a| a).copied().collect::>(); - let mut expected = Parser::new(0).parse_all(&everything); - if log::log_enabled!(log::Level::Debug) { - std::fs::write("input.wasm", &everything).unwrap(); - } - - // Create our parser as well as a stack of nested parsers for parsing nested - // modules. - let mut stack = Vec::new(); - let mut parser = Parser::new(0); - - // We'll be parsing data from `buf` starting at `pos`, and we translate - // `data` into an iterator of chunks so when requested we'll take another - // chunk of data and feed it in. - let mut pos = 0; - let mut buf = Vec::new(); - let mut data = data.into_iter().peekable(); - loop { - log::debug!("parsing {}..{}", pos, buf.len()); - let payload = match parser.parse(&buf[pos..], data.peek().is_none()) { - // If more data is requested then we're guaranteed that `data` - // should have another element in its iterato, so pull that off and - // add it to the end of the `buf`. - Ok(Chunk::NeedMoreData(_n)) => { - buf.extend(data.next().unwrap()); - continue; - } - Ok(Chunk::Parsed { consumed, payload }) => { - log::debug!("parsed {} bytes", consumed); - pos += consumed; - payload - } - - // On failure we should receive the same failure as if we did a full - // parse. - Err(actual) => { - let expected = expected - .next() - .expect("full parse stopped early") - .err() - .expect("full parse didn't return an error"); - assert_eq!(expected.offset(), actual.offset()); - assert_eq!(expected.message(), actual.message()); - break; - } - }; - log::debug!("parsed payload {:?}", payload); - let expected_payload = expected - .next() - .expect("full parse stopped early") - .expect("full parse failed but incremental succeeded"); - match (payload, expected_payload) { - (End(_), End(_)) => match stack.pop() { - Some(p) => parser = p, - None => { - log::debug!("no more parsers"); - assert!(expected.next().is_none()); - break; - } - }, - ( - Version { - num: a, - encoding: ae, - range: ar, - }, - Version { - num: b, - encoding: be, - range: br, - }, - ) => { - assert_eq!(a, b); - assert_eq!(ae, be); - assert_eq!(ar, br); - } - - (TypeSection(a), TypeSection(b)) => assert_eq!(a.range(), b.range()), - (ImportSection(a), ImportSection(b)) => assert_eq!(a.range(), b.range()), - (FunctionSection(a), FunctionSection(b)) => assert_eq!(a.range(), b.range()), - (TableSection(a), TableSection(b)) => assert_eq!(a.range(), b.range()), - (MemorySection(a), MemorySection(b)) => assert_eq!(a.range(), b.range()), - (GlobalSection(a), GlobalSection(b)) => assert_eq!(a.range(), b.range()), - (ExportSection(a), ExportSection(b)) => assert_eq!(a.range(), b.range()), - (TagSection(a), TagSection(b)) => assert_eq!(a.range(), b.range()), - (StartSection { func: a, range: ar }, StartSection { func: b, range: br }) => { - assert_eq!(a, b); - assert_eq!(ar, br); - } - (ElementSection(a), ElementSection(b)) => assert_eq!(a.range(), b.range()), - ( - DataCountSection { - count: a, - range: ar, - }, - DataCountSection { - count: b, - range: br, - }, - ) => { - assert_eq!(a, b); - assert_eq!(ar, br); - } - (DataSection(a), DataSection(b)) => assert_eq!(a.range(), b.range()), - (CustomSection(ca), CustomSection(cb)) => { - assert_eq!(ca.name(), cb.name()); - assert_eq!(ca.data_offset(), cb.data_offset()); - assert_eq!(ca.data(), cb.data()); - assert_eq!(ca.range(), cb.range()); - } - ( - CodeSectionStart { - count: a, - range: ar, - size: asz, - }, - CodeSectionStart { - count: b, - range: br, - size: bsz, - }, - ) => { - assert_eq!(a, b); - assert_eq!(ar, br); - assert_eq!(asz, bsz); - } - - (CodeSectionEntry(a), CodeSectionEntry(b)) => { - assert_eq!(a.get_binary_reader().range(), b.get_binary_reader().range()); - } - - ( - ModuleSection { - parser: p, - range: a, - }, - ModuleSection { range: b, .. }, - ) => { - assert_eq!(a, b); - stack.push(parser); - parser = p; - } - (InstanceSection(a), InstanceSection(b)) => assert_eq!(a.range(), b.range()), - ( - ComponentSection { - parser: p, - range: a, - }, - ComponentSection { range: b, .. }, - ) => { - assert_eq!(a, b); - stack.push(parser); - parser = p; - } - (ComponentInstanceSection(a), ComponentInstanceSection(b)) => { - assert_eq!(a.range(), b.range()) - } - (ComponentAliasSection(a), ComponentAliasSection(b)) => { - assert_eq!(a.range(), b.range()) - } - (ComponentTypeSection(a), ComponentTypeSection(b)) => assert_eq!(a.range(), b.range()), - (ComponentCanonicalSection(a), ComponentCanonicalSection(b)) => { - assert_eq!(a.range(), b.range()) - } - (ComponentStartSection(a), ComponentStartSection(b)) => { - assert_eq!(a.range(), b.range()) - } - (ComponentImportSection(a), ComponentImportSection(b)) => { - assert_eq!(a.range(), b.range()) - } - (ComponentExportSection(a), ComponentExportSection(b)) => { - assert_eq!(a.range(), b.range()) - } - (CoreTypeSection(a), CoreTypeSection(b)) => { - assert_eq!(a.range(), b.range()) - } - - ( - UnknownSection { - id: a, - contents: ac, - range: ar, - }, - UnknownSection { - id: b, - contents: bc, - range: br, - }, - ) => { - assert_eq!(a, b); - assert_eq!(ar, br); - assert_eq!(ac, bc); - } - - (a, b) => { - panic!("expected {:?}\ngot {:?}", b, a); - } - } - } -}); diff --git a/fuzz/fuzz_targets/mutate.rs b/fuzz/fuzz_targets/mutate.rs deleted file mode 100644 index 9131f9a8b3..0000000000 --- a/fuzz/fuzz_targets/mutate.rs +++ /dev/null @@ -1,267 +0,0 @@ -#![no_main] - -use arbitrary::Unstructured; -use libfuzzer_sys::fuzz_target; -use std::sync::atomic::{AtomicU64, Ordering}; -use wasmparser::WasmFeatures; - -static NUM_RUNS: AtomicU64 = AtomicU64::new(0); -static NUM_SUCCESSFUL_MUTATIONS: AtomicU64 = AtomicU64::new(0); - -fuzz_target!(|bytes: &[u8]| { - let _ = env_logger::try_init(); - - // Generate a random Wasm module with `wasm-smith` as well as a RNG seed for - // use with `wasm-mutate`. - - let mut seed = 0; - let mut u = Unstructured::new(bytes); - let (wasm, config) = match wasm_tools_fuzz::generate_valid_module(&mut u, |config, u| { - config.exceptions_enabled = false; - seed = u.arbitrary()?; - Ok(()) - }) { - Ok(m) => m, - Err(_) => return, - }; - log::debug!("seed = {}", seed); - - // Keep track of how many runs we've done thus far and how many of those - // runs had successful mutations. - - let old_num_runs = NUM_RUNS.fetch_add(1, Ordering::Relaxed); - if old_num_runs % 4096 == 4095 && log::log_enabled!(log::Level::Info) { - let successful = NUM_SUCCESSFUL_MUTATIONS.load(Ordering::Relaxed); - let percent = successful as f64 / old_num_runs as f64 * 100.0; - log::info!( - "{} / {} ({:.2}%) successful mutations.", - successful, - old_num_runs, - percent - ); - } - - // Mutate the Wasm with `wasm-mutate`. Assert that each mutation is still - // valid Wasm. - - let mut wasm_mutate = wasm_mutate::WasmMutate::default(); - wasm_mutate.seed(seed); - wasm_mutate.fuel(300); - wasm_mutate.preserve_semantics( - // If we are going to check that we get the same evaluated results - // before and after mutation, then we need to preserve semantics. - cfg!(feature = "wasmtime"), - ); - - let iterator = match wasm_mutate.run(&wasm) { - Ok(iterator) => iterator, - Err(e) => { - log::warn!("Failed to mutate the Wasm: {}", e); - return; - } - }; - - // Note that on-by-default features in wasmparser are not disabled here if - // the feature was disabled in `config` when the module was generated. For - // example if the input module doesn't have simd then wasm-mutate may - // produce a module that uses simd, which is ok and expected. - // - // Otherwise only forward some off-by-default features which are affected by - // wasm-smith's generation of modules and wasm-mutate otherwise won't add - // itself if it doesn't already exist. - let mut features = WasmFeatures::default(); - features.relaxed_simd = config.relaxed_simd_enabled; - features.multi_memory = config.max_memories > 1; - features.memory64 = config.memory64_enabled; - features.threads = config.threads_enabled; - - for (i, mutated_wasm) in iterator.take(10).enumerate() { - let mutated_wasm = match mutated_wasm { - Ok(w) => w, - Err(e) => match e.kind() { - wasm_mutate::ErrorKind::NoMutationsApplicable => continue, - _ => panic!("Unexpected mutation failure: {}", e), - }, - }; - - // Increase ony once for the same input Wasm. - if i == 0 { - NUM_SUCCESSFUL_MUTATIONS.fetch_add(1, Ordering::Relaxed); - } - - let validation_result = - wasmparser::Validator::new_with_features(features).validate_all(&mutated_wasm); - - if log::log_enabled!(log::Level::Debug) { - log::debug!("writing mutated Wasm to `mutated.wasm`"); - std::fs::write("mutated.wasm", &mutated_wasm) - .expect("should write `mutated.wasm` okay"); - if let Ok(mutated_wat) = wasmprinter::print_bytes(&mutated_wasm) { - log::debug!("writing mutated WAT to `mutated.wat`"); - std::fs::write("mutated.wat", &mutated_wat) - .expect("should write `mutated.wat` okay"); - } - } - - validation_result.expect("`wasm-mutate` should always produce a valid Wasm file"); - - #[cfg(feature = "wasmtime")] - eval::assert_same_evaluation(&wasm, &mutated_wasm); - } -}); - -#[cfg(feature = "wasmtime")] -#[path = "../../crates/fuzz-stats/src/dummy.rs"] -pub mod dummy; - -#[cfg(feature = "wasmtime")] -mod eval { - use super::dummy; - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - - /// Compile, instantiate, and evaluate both the original and mutated Wasm. - /// - /// We should get identical results because we told `wasm-mutate` to preserve - /// semantics. - pub fn assert_same_evaluation(wasm: &[u8], mutated_wasm: &[u8]) { - let mut config = wasmtime::Config::default(); - config.cranelift_nan_canonicalization(true); - config.consume_fuel(true); - - let engine = wasmtime::Engine::new(&config).unwrap(); - - let (orig_module, mutated_module) = match ( - wasmtime::Module::new(&engine, &wasm), - wasmtime::Module::new(&engine, &mutated_wasm), - ) { - (Ok(o), Ok(m)) => (o, m), - // Ideally we would assert that they both errored if either one did, but - // it is possible that a mutation bumped some count above/below an - // implementation limit. - (_, _) => return, - }; - - let mut store = wasmtime::Store::new(&engine, ()); - let (orig_imports, mutated_imports) = match dummy::dummy_imports(&mut store, &orig_module) { - Ok(imps) => (imps.clone(), imps), - Err(_) => return, - }; - - let (orig_instance, mutated_instance) = match ( - wasmtime::Instance::new(&mut store, &orig_module, &orig_imports), - wasmtime::Instance::new(&mut store, &mutated_module, &mutated_imports), - ) { - (Ok(x), Ok(y)) => (x, y), - (_, _) => return, - }; - - assert_same_state(&mut store, &orig_module, orig_instance, mutated_instance); - assert_same_calls(&mut store, &orig_module, orig_instance, mutated_instance); - assert_same_state(&mut store, &orig_module, orig_instance, mutated_instance); - } - - fn assert_same_state( - store: &mut wasmtime::Store<()>, - orig_module: &wasmtime::Module, - orig_instance: wasmtime::Instance, - mutated_instance: wasmtime::Instance, - ) { - for export in orig_module.exports() { - match export.ty() { - wasmtime::ExternType::Global(_) => { - let orig = orig_instance - .get_export(&mut *store, export.name()) - .unwrap() - .into_global() - .unwrap() - .get(&mut *store); - let mutated = mutated_instance - .get_export(&mut *store, export.name()) - .unwrap() - .into_global() - .unwrap() - .get(&mut *store); - assert_val_eq(&orig, &mutated); - } - wasmtime::ExternType::Memory(_) => { - let orig = orig_instance - .get_export(&mut *store, export.name()) - .unwrap() - .into_memory() - .unwrap(); - let mut h = DefaultHasher::default(); - orig.data(&store).hash(&mut h); - let orig = h.finish(); - let mutated = mutated_instance - .get_export(&mut *store, export.name()) - .unwrap() - .into_memory() - .unwrap(); - let mut h = DefaultHasher::default(); - mutated.data(&store).hash(&mut h); - let mutated = h.finish(); - assert_eq!(orig, mutated, "original and mutated Wasm memories diverged"); - } - _ => continue, - } - } - } - - fn assert_same_calls( - store: &mut wasmtime::Store<()>, - orig_module: &wasmtime::Module, - orig_instance: wasmtime::Instance, - mutated_instance: wasmtime::Instance, - ) { - for export in orig_module.exports() { - match export.ty() { - wasmtime::ExternType::Func(func_ty) => { - let orig_func = orig_instance.get_func(&mut *store, export.name()).unwrap(); - let mutated_func = mutated_instance - .get_func(&mut *store, export.name()) - .unwrap(); - let args = dummy::dummy_values(func_ty.params()); - match ( - { - store.add_fuel(1_000).unwrap(); - orig_func.call(&mut *store, &args) - }, - { - let consumed = store.fuel_consumed().unwrap(); - store.add_fuel(consumed).unwrap(); - mutated_func.call(&mut *store, &args) - }, - ) { - (Ok(orig_vals), Ok(mutated_vals)) => { - assert_eq!(orig_vals.len(), mutated_vals.len()); - for (orig_val, mutated_val) in orig_vals.iter().zip(mutated_vals.iter()) - { - assert_val_eq(orig_val, mutated_val); - } - } - (Err(_), Err(_)) => continue, - (orig, mutated) => panic!( - "mutated and original Wasm diverged: orig = {:?}; mutated = {:?}", - orig, mutated, - ), - } - } - _ => continue, - } - } - } - - fn assert_val_eq(orig_val: &wasmtime::Val, mutated_val: &wasmtime::Val) { - match (orig_val, mutated_val) { - (wasmtime::Val::I32(o), wasmtime::Val::I32(m)) => assert_eq!(o, m), - (wasmtime::Val::I64(o), wasmtime::Val::I64(m)) => assert_eq!(o, m), - (wasmtime::Val::F32(o), wasmtime::Val::F32(m)) => assert_eq!(o, m), - (wasmtime::Val::F64(o), wasmtime::Val::F64(m)) => assert_eq!(o, m), - (o, m) => panic!( - "mutated and original Wasm diverged: orig = {:?}; mutated = {:?}", - o, m, - ), - } - } -} diff --git a/fuzz/fuzz_targets/print.rs b/fuzz/fuzz_targets/print.rs deleted file mode 100644 index 3da7f2471d..0000000000 --- a/fuzz/fuzz_targets/print.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![no_main] - -use libfuzzer_sys::*; - -fuzz_target!(|data: &[u8]| { - drop(wasmprinter::print_bytes(data)); -}); diff --git a/fuzz/fuzz_targets/roundtrip.rs b/fuzz/fuzz_targets/roundtrip.rs deleted file mode 100644 index a25e6daf20..0000000000 --- a/fuzz/fuzz_targets/roundtrip.rs +++ /dev/null @@ -1,101 +0,0 @@ -#![no_main] - -use libfuzzer_sys::*; -use std::str; - -fuzz_target!(|data: &[u8]| { - let string = match str::from_utf8(data) { - Ok(s) => s, - Err(_) => return, - }; - // Weed out `(module binary ...)` because when we print the bytes and - // convert it back to binary it's not guaranteed to be exactly the same. - // (think of something like an over-long LEB encoding) - if string.contains("binary") { - return; - } - - // Also weed out `@custom` custom sections since we don't print those right - // now. - if string.contains("@custom") { - return; - } - let wasm = match wat::parse_str(string) { - Ok(bytes) => bytes, - Err(_) => return, - }; - - // Only roundtrip valid modules for now since invalid modules can often have - // bizarre structures which aren't intended to print correctly or roundtrip - // well. - if wasmparser::validate(&wasm).is_err() { - return; - } - - // And finally validate that the name section, if present, is valid. This - // can be invalid if names in the name section are too long (e.g. exceeding - // the maximum length of a string). The printing process will skip invalid - // name sections, so if it's invalid then our roundtrip'd bytes will - // trivially not match, but not in an interesting way. - if validate_name_section(&wasm).is_err() { - return; - } - let string2 = match wasmprinter::print_bytes(&wasm) { - Ok(s) => s, - Err(_) => return, - }; - - let wasm2 = wat::parse_str(&string2).unwrap(); - if wasm == wasm2 { - return; - } - - std::fs::write("wasm1.wasm", &wasm).unwrap(); - std::fs::write("wasm1.wat", &string).unwrap(); - std::fs::write("wasm2.wasm", &wasm2).unwrap(); - std::fs::write("wasm2.wat", &string2).unwrap(); - panic!("wasm bytes differ on roundtrip"); -}); - -fn validate_name_section(wasm: &[u8]) -> wasmparser::Result<()> { - use wasmparser::*; - for payload in Parser::new(0).parse_all(wasm) { - let reader = match payload? { - Payload::CustomSection(c) if c.name() == "name" => { - NameSectionReader::new(c.data(), c.data_offset())? - } - _ => continue, - }; - for section in reader { - match section? { - Name::Module(n) => { - n.get_name()?; - } - Name::Function(n) - | Name::Type(n) - | Name::Table(n) - | Name::Memory(n) - | Name::Global(n) - | Name::Element(n) - | Name::Data(n) => { - let mut map = n.get_map()?; - for _ in 0..map.get_count() { - map.read()?; - } - } - Name::Local(n) | Name::Label(n) => { - let mut reader = n.get_indirect_map()?; - for _ in 0..reader.get_indirect_count() { - let local_name = reader.read()?; - let mut map = local_name.get_map()?; - for _ in 0..map.get_count() { - map.read()?; - } - } - } - Name::Unknown { .. } => {} - } - } - } - Ok(()) -} diff --git a/fuzz/fuzz_targets/run.rs b/fuzz/fuzz_targets/run.rs new file mode 100644 index 0000000000..b9b196a88c --- /dev/null +++ b/fuzz/fuzz_targets/run.rs @@ -0,0 +1,82 @@ +#![no_main] + +use arbitrary::Unstructured; +use libfuzzer_sys::fuzz_target; +use std::sync::OnceLock; + +// Helper macro which takes a static list of fuzzers as input which are then +// delegated to internally based on the fuzz target selected. +// +// In general this fuzz target will execute a number of fuzzers all with the +// same input. The `FUZZER` environment variable can be used to forcibly disable +// all but one. +macro_rules! run_fuzzers { + ($($fuzzer:ident: $kind:ident,)*) => { + static ENABLED: OnceLock = OnceLock::new(); + + fuzz_target!(|bytes: &[u8]| { + // Lazily initialize this fuzzer in terms of logging as well as + // enabled fuzzers via the `FUZZER` env var. + let enabled = *ENABLED.get_or_init(|| { + env_logger::init(); + let configured = std::env::var("FUZZER").ok(); + let configured = configured.as_deref(); + let mut enabled = 0; + let mut index = 0; + + $( + if configured.is_none() || configured == Some(stringify!($fuzzer)) { + enabled |= 1 << index; + } + index += 1; + )* + let _ = index; + + enabled + }); + + let mut index = 0; + $( + if enabled & (1 << index) != 0 { + run_fuzzers!(@run $fuzzer $kind bytes index); + } + index += 1; + )* + let _ = index; + }); + }; + + (@run $fuzzer:ident unstructured $bytes:ident $index:ident) => { + // Use the first byte of input as a discriminant of which fuzzer to + // select. + // + // Afterwards run the specific fuzzer that the fuzz input is + // targeted for so long as it's enabled. + if let Some((which_fuzzer, bytes)) = $bytes.split_first() { + if *which_fuzzer == $index { + let mut u = Unstructured::new(bytes); + let _ = wasm_tools_fuzz::$fuzzer::run(&mut u); + } + } + }; + + (@run $fuzzer:ident string $bytes:ident $index:ident) => { + // For string-based fuzzers run all fuzzers enabled for all + // string-looking inputs. + if let Ok(s) = std::str::from_utf8($bytes) { + wasm_tools_fuzz::$fuzzer::run(s); + } + }; +} + +run_fuzzers! { + mutate: unstructured, + validate_valid_module: unstructured, + roundtrip_wit: unstructured, + no_traps: unstructured, + validate: unstructured, + incremental_parse: unstructured, + print: unstructured, + roundtrip: string, + text_parser: string, +} diff --git a/fuzz/fuzz_targets/text-parser.rs b/fuzz/fuzz_targets/text-parser.rs deleted file mode 100644 index f614a16a90..0000000000 --- a/fuzz/fuzz_targets/text-parser.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_main] - -use libfuzzer_sys::*; -use std::str; - -fuzz_target!(|data: &[u8]| { - let s = match str::from_utf8(data) { - Ok(s) => s, - Err(_) => return, - }; - let buf = match wast::parser::ParseBuffer::new(s) { - Ok(b) => b, - Err(_) => return, - }; - drop(wast::parser::parse::(&buf)); -}); diff --git a/fuzz/fuzz_targets/validate-valid-module.rs b/fuzz/fuzz_targets/validate-valid-module.rs deleted file mode 100644 index 0204c5a4d8..0000000000 --- a/fuzz/fuzz_targets/validate-valid-module.rs +++ /dev/null @@ -1,85 +0,0 @@ -#![no_main] - -use arbitrary::Unstructured; -use libfuzzer_sys::fuzz_target; - -// Define a fuzz target that accepts arbitrary -// `Module`s or `Component`s as input. -fuzz_target!(|data: &[u8]| { - let mut u = Unstructured::new(data); - - // We want to prioritize fuzzing of modules for the time being - // so we'll only generate a component 10% of the time - // - // TODO: remove this `false && ...` once this fuzzer works again for - // components. - let generate_component = false - && match u.ratio::(1, 10) { - Ok(b) => b, - Err(_) => false, - }; - let (wasm_bytes, config) = if generate_component { - match wasm_tools_fuzz::generate_valid_component(&mut u, |c, u| { - c.max_components = u.int_in_range(0..=1_000)?; - c.max_instances = u.int_in_range(0..=1_000)?; - c.max_values = u.int_in_range(0..=1_000)?; - Ok(()) - }) { - Ok(c) => c, - Err(_) => return, - } - } else { - match wasm_tools_fuzz::generate_valid_module(&mut u, |_, _| Ok(())) { - Ok(m) => m, - Err(_) => return, - } - }; - - // Validate the module or component and assert that it passes validation. - let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { - component_model: generate_component, - multi_value: config.multi_value_enabled, - multi_memory: config.max_memories > 1, - bulk_memory: true, - reference_types: true, - simd: config.simd_enabled, - relaxed_simd: config.relaxed_simd_enabled, - memory64: config.memory64_enabled, - threads: config.threads_enabled, - exceptions: config.exceptions_enabled, - ..wasmparser::WasmFeatures::default() - }); - if let Err(e) = validator.validate_all(&wasm_bytes) { - let component_or_module = if generate_component { - "component" - } else { - "module" - }; - panic!("Invalid {}: {}", component_or_module, e); - } - - // After validation make sure that binary-to-text and text-to-binary - // transforms all work as well. - let wat_string = wasmprinter::print_bytes(&wasm_bytes).unwrap_or_else(|e| { - panic!( - "failed first disassembly of Wasm into wat with `wasmprinter::print_bytes`: {}", - e - ) - }); - let wasm_bytes = wat::parse_str(&wat_string).unwrap_or_else(|e| { - panic!( - "failed to assemble wat into Wasm with `wat::parse_str`: {}", - e - ) - }); - let wat_string2 = wasmprinter::print_bytes(&wasm_bytes).unwrap_or_else(|e| { - panic!( - "failed second disassembly of Wasm into wat with `wasmprinter::print_bytes`: {}", - e - ) - }); - - if wat_string != wat_string2 { - panic!("failed to roundtrip valid module"); - } -}); diff --git a/fuzz/fuzz_targets/validate.rs b/fuzz/fuzz_targets/validate.rs deleted file mode 100644 index 3eaebc8427..0000000000 --- a/fuzz/fuzz_targets/validate.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![no_main] - -use arbitrary::{Arbitrary, Unstructured}; -use libfuzzer_sys::*; -use wasm_smith::MaybeInvalidModule; -use wasmparser::{Validator, WasmFeatures}; - -fuzz_target!(|data: &[u8]| { - drop(env_logger::try_init()); - let byte1 = match data.get(0) { - Some(byte) => byte, - None => return, - }; - let byte2 = match data.get(1) { - Some(byte) => byte, - None => return, - }; - let byte3 = match data.get(2) { - Some(byte) => byte, - None => return, - }; - let mut validator = Validator::new_with_features(WasmFeatures { - reference_types: (byte1 & 0b0000_0001) != 0, - multi_value: (byte1 & 0b0000_0010) != 0, - threads: (byte1 & 0b0000_0100) != 0, - simd: (byte1 & 0b0000_1000) != 0, - component_model: (byte1 & 0b0001_0000) != 0, - tail_call: (byte1 & 0b0010_0000) != 0, - bulk_memory: (byte1 & 0b0100_0000) != 0, - deterministic_only: (byte1 & 0b1000_0000) != 0, - multi_memory: (byte2 & 0b0000_0001) != 0, - memory64: (byte2 & 0b0000_0010) != 0, - exceptions: (byte2 & 0b0000_0100) != 0, - relaxed_simd: (byte2 & 0b0000_1000) != 0, - extended_const: (byte2 & 0b0001_0000) != 0, - mutable_global: (byte2 & 0b0010_0000) != 0, - saturating_float_to_int: (byte2 & 0b0100_0000) != 0, - sign_extension: (byte2 & 0b1000_0000) != 0, - }); - let use_maybe_invalid = byte3 & 0b0000_0001 != 0; - - let wasm = &data[3..]; - if log::log_enabled!(log::Level::Debug) { - log::debug!("writing input to `test.wasm`"); - std::fs::write("test.wasm", wasm).unwrap(); - } - if use_maybe_invalid { - let mut u = Unstructured::new(wasm); - if let Ok(module) = MaybeInvalidModule::arbitrary(&mut u) { - drop(validator.validate_all(&module.to_bytes())); - } - } else { - drop(validator.validate_all(wasm)); - } -}); diff --git a/fuzz/src/incremental_parse.rs b/fuzz/src/incremental_parse.rs new file mode 100644 index 0000000000..3da05167d9 --- /dev/null +++ b/fuzz/src/incremental_parse.rs @@ -0,0 +1,215 @@ +use arbitrary::{Result, Unstructured}; +use wasmparser::*; +use Payload::*; + +// Simulate receiving chunks of data by fuzzing over a `Vec>` where each +// element of the outer vec is a chunk of data we received. +// +// The assertion here is that parsing everything in one go should always produce +// the exact same results as an incremental parse. +pub fn run(u: &mut Unstructured<'_>) -> Result<()> { + let data: Vec> = u.arbitrary()?; + + // Concatenate everything together, create our expected iterator of + // payloads, and then write out `input.wasm` if debugging is enabled. + let everything = data.iter().flat_map(|a| a).copied().collect::>(); + let mut expected = Parser::new(0).parse_all(&everything); + if log::log_enabled!(log::Level::Debug) { + std::fs::write("input.wasm", &everything).unwrap(); + } + + // Create our parser as well as a stack of nested parsers for parsing nested + // modules. + let mut stack = Vec::new(); + let mut parser = Parser::new(0); + + // We'll be parsing data from `buf` starting at `pos`, and we translate + // `data` into an iterator of chunks so when requested we'll take another + // chunk of data and feed it in. + let mut pos = 0; + let mut buf = Vec::new(); + let mut data = data.into_iter().peekable(); + loop { + log::debug!("parsing {}..{}", pos, buf.len()); + let payload = match parser.parse(&buf[pos..], data.peek().is_none()) { + // If more data is requested then we're guaranteed that `data` + // should have another element in its iterato, so pull that off and + // add it to the end of the `buf`. + Ok(Chunk::NeedMoreData(_n)) => { + buf.extend(data.next().unwrap()); + continue; + } + Ok(Chunk::Parsed { consumed, payload }) => { + log::debug!("parsed {} bytes", consumed); + pos += consumed; + payload + } + + // On failure we should receive the same failure as if we did a full + // parse. + Err(actual) => { + let expected = expected + .next() + .expect("full parse stopped early") + .err() + .expect("full parse didn't return an error"); + assert_eq!(expected.offset(), actual.offset()); + assert_eq!(expected.message(), actual.message()); + break; + } + }; + log::debug!("parsed payload {:?}", payload); + let expected_payload = expected + .next() + .expect("full parse stopped early") + .expect("full parse failed but incremental succeeded"); + match (payload, expected_payload) { + (End(_), End(_)) => match stack.pop() { + Some(p) => parser = p, + None => { + log::debug!("no more parsers"); + assert!(expected.next().is_none()); + break; + } + }, + ( + Version { + num: a, + encoding: ae, + range: ar, + }, + Version { + num: b, + encoding: be, + range: br, + }, + ) => { + assert_eq!(a, b); + assert_eq!(ae, be); + assert_eq!(ar, br); + } + + (TypeSection(a), TypeSection(b)) => assert_eq!(a.range(), b.range()), + (ImportSection(a), ImportSection(b)) => assert_eq!(a.range(), b.range()), + (FunctionSection(a), FunctionSection(b)) => assert_eq!(a.range(), b.range()), + (TableSection(a), TableSection(b)) => assert_eq!(a.range(), b.range()), + (MemorySection(a), MemorySection(b)) => assert_eq!(a.range(), b.range()), + (GlobalSection(a), GlobalSection(b)) => assert_eq!(a.range(), b.range()), + (ExportSection(a), ExportSection(b)) => assert_eq!(a.range(), b.range()), + (TagSection(a), TagSection(b)) => assert_eq!(a.range(), b.range()), + (StartSection { func: a, range: ar }, StartSection { func: b, range: br }) => { + assert_eq!(a, b); + assert_eq!(ar, br); + } + (ElementSection(a), ElementSection(b)) => assert_eq!(a.range(), b.range()), + ( + DataCountSection { + count: a, + range: ar, + }, + DataCountSection { + count: b, + range: br, + }, + ) => { + assert_eq!(a, b); + assert_eq!(ar, br); + } + (DataSection(a), DataSection(b)) => assert_eq!(a.range(), b.range()), + (CustomSection(ca), CustomSection(cb)) => { + assert_eq!(ca.name(), cb.name()); + assert_eq!(ca.data_offset(), cb.data_offset()); + assert_eq!(ca.data(), cb.data()); + assert_eq!(ca.range(), cb.range()); + } + ( + CodeSectionStart { + count: a, + range: ar, + size: asz, + }, + CodeSectionStart { + count: b, + range: br, + size: bsz, + }, + ) => { + assert_eq!(a, b); + assert_eq!(ar, br); + assert_eq!(asz, bsz); + } + + (CodeSectionEntry(a), CodeSectionEntry(b)) => { + assert_eq!(a.get_binary_reader().range(), b.get_binary_reader().range()); + } + + ( + ModuleSection { + parser: p, + range: a, + }, + ModuleSection { range: b, .. }, + ) => { + assert_eq!(a, b); + stack.push(parser); + parser = p; + } + (InstanceSection(a), InstanceSection(b)) => assert_eq!(a.range(), b.range()), + ( + ComponentSection { + parser: p, + range: a, + }, + ComponentSection { range: b, .. }, + ) => { + assert_eq!(a, b); + stack.push(parser); + parser = p; + } + (ComponentInstanceSection(a), ComponentInstanceSection(b)) => { + assert_eq!(a.range(), b.range()) + } + (ComponentAliasSection(a), ComponentAliasSection(b)) => { + assert_eq!(a.range(), b.range()) + } + (ComponentTypeSection(a), ComponentTypeSection(b)) => assert_eq!(a.range(), b.range()), + (ComponentCanonicalSection(a), ComponentCanonicalSection(b)) => { + assert_eq!(a.range(), b.range()) + } + (ComponentStartSection { range: a, .. }, ComponentStartSection { range: b, .. }) => { + assert_eq!(a, b) + } + (ComponentImportSection(a), ComponentImportSection(b)) => { + assert_eq!(a.range(), b.range()) + } + (ComponentExportSection(a), ComponentExportSection(b)) => { + assert_eq!(a.range(), b.range()) + } + (CoreTypeSection(a), CoreTypeSection(b)) => { + assert_eq!(a.range(), b.range()) + } + + ( + UnknownSection { + id: a, + contents: ac, + range: ar, + }, + UnknownSection { + id: b, + contents: bc, + range: br, + }, + ) => { + assert_eq!(a, b); + assert_eq!(ar, br); + assert_eq!(ac, bc); + } + + (a, b) => { + panic!("expected {:?}\ngot {:?}", b, a); + } + } + } + Ok(()) +} diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs index 666f69876c..d3eb197366 100644 --- a/fuzz/src/lib.rs +++ b/fuzz/src/lib.rs @@ -2,6 +2,16 @@ use libfuzzer_sys::arbitrary::{Result, Unstructured}; use std::fmt::Debug; use wasm_smith::{Component, Module, SwarmConfig}; +pub mod incremental_parse; +pub mod mutate; +pub mod no_traps; +pub mod print; +pub mod roundtrip; +pub mod roundtrip_wit; +pub mod text_parser; +pub mod validate; +pub mod validate_valid_module; + pub fn generate_valid_module( u: &mut Unstructured, configure: impl FnOnce(&mut SwarmConfig, &mut Unstructured<'_>) -> Result<()>, @@ -16,6 +26,7 @@ pub fn generate_valid_module( config.threads_enabled = u.arbitrary()?; config.exceptions_enabled = u.arbitrary()?; config.canonicalize_nans = u.arbitrary()?; + config.tail_call_enabled = u.arbitrary()?; configure(&mut config, u)?; diff --git a/fuzz/src/mutate.rs b/fuzz/src/mutate.rs new file mode 100644 index 0000000000..a735a5151d --- /dev/null +++ b/fuzz/src/mutate.rs @@ -0,0 +1,339 @@ +use arbitrary::{Result, Unstructured}; +use std::sync::atomic::{AtomicU64, Ordering}; +use wasmparser::WasmFeatures; + +static NUM_RUNS: AtomicU64 = AtomicU64::new(0); +static NUM_SUCCESSFUL_MUTATIONS: AtomicU64 = AtomicU64::new(0); + +pub fn run(u: &mut Unstructured<'_>) -> Result<()> { + // Generate a random Wasm module with `wasm-smith` as well as a RNG seed for + // use with `wasm-mutate`. + + let mut seed = 0; + let mut preserve_semantics = false; + let (wasm, config) = crate::generate_valid_module(u, |config, u| { + config.exceptions_enabled = false; + seed = u.arbitrary()?; + preserve_semantics = u.arbitrary()?; + Ok(()) + })?; + log::debug!("seed = {}", seed); + + // Keep track of how many runs we've done thus far and how many of those + // runs had successful mutations. + + let old_num_runs = NUM_RUNS.fetch_add(1, Ordering::Relaxed); + if old_num_runs % 4096 == 4095 && log::log_enabled!(log::Level::Info) { + let successful = NUM_SUCCESSFUL_MUTATIONS.load(Ordering::Relaxed); + let percent = successful as f64 / old_num_runs as f64 * 100.0; + log::info!( + "{} / {} ({:.2}%) successful mutations.", + successful, + old_num_runs, + percent + ); + } + + // Mutate the Wasm with `wasm-mutate`. Assert that each mutation is still + // valid Wasm. + + let mut wasm_mutate = wasm_mutate::WasmMutate::default(); + wasm_mutate.seed(seed); + wasm_mutate.fuel(300); + wasm_mutate.preserve_semantics( + // If we are going to check that we get the same evaluated results + // before and after mutation, then we need to preserve semantics. + cfg!(feature = "wasmtime") && preserve_semantics, + ); + + let iterator = match wasm_mutate.run(&wasm) { + Ok(iterator) => iterator, + Err(e) => { + log::warn!("Failed to mutate the Wasm: {}", e); + return Ok(()); + } + }; + + // Note that on-by-default features in wasmparser are not disabled here if + // the feature was disabled in `config` when the module was generated. For + // example if the input module doesn't have simd then wasm-mutate may + // produce a module that uses simd, which is ok and expected. + // + // Otherwise only forward some off-by-default features which are affected by + // wasm-smith's generation of modules and wasm-mutate otherwise won't add + // itself if it doesn't already exist. + let mut features = WasmFeatures::default(); + features.relaxed_simd = config.relaxed_simd_enabled; + features.multi_memory = config.max_memories > 1; + features.memory64 = config.memory64_enabled; + features.threads = config.threads_enabled; + + for (i, mutated_wasm) in iterator.take(10).enumerate() { + let mutated_wasm = match mutated_wasm { + Ok(w) => w, + Err(e) => match e.kind() { + wasm_mutate::ErrorKind::NoMutationsApplicable => continue, + _ => panic!("Unexpected mutation failure: {}", e), + }, + }; + + // Increase ony once for the same input Wasm. + if i == 0 { + NUM_SUCCESSFUL_MUTATIONS.fetch_add(1, Ordering::Relaxed); + } + + let validation_result = + wasmparser::Validator::new_with_features(features).validate_all(&mutated_wasm); + + if log::log_enabled!(log::Level::Debug) { + log::debug!("writing mutated Wasm to `mutated.wasm`"); + std::fs::write("mutated.wasm", &mutated_wasm) + .expect("should write `mutated.wasm` okay"); + if let Ok(mutated_wat) = wasmprinter::print_bytes(&mutated_wasm) { + log::debug!("writing mutated WAT to `mutated.wat`"); + std::fs::write("mutated.wat", &mutated_wat) + .expect("should write `mutated.wat` okay"); + } + } + + validation_result.expect("`wasm-mutate` should always produce a valid Wasm file"); + + #[cfg(feature = "wasmtime")] + if preserve_semantics { + eval::assert_same_evaluation(&wasm, &mutated_wasm); + } + } + + Ok(()) +} + +#[cfg(feature = "wasmtime")] +#[path = "../../crates/fuzz-stats/src/lib.rs"] +pub mod fuzz_stats; + +#[cfg(feature = "wasmtime")] +mod eval { + use super::fuzz_stats::{dummy, limits::StoreLimits}; + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + use wasmtime::{ResourceLimiter, Val}; + + /// Compile, instantiate, and evaluate both the original and mutated Wasm. + /// + /// We should get identical results because we told `wasm-mutate` to preserve + /// semantics. + pub fn assert_same_evaluation(wasm: &[u8], mutated_wasm: &[u8]) { + // FIXME: should re-enable this when the fuzzer works again, needs + // someone to invest energy into running this locally for a long time + // and then be on the hook for incoming oss-fuzz bugs. + if true { + return; + } + + let mut config = wasmtime::Config::default(); + config.cranelift_nan_canonicalization(true); + config.consume_fuel(true); + + let engine = wasmtime::Engine::new(&config).unwrap(); + + let (orig_module, mutated_module) = match ( + wasmtime::Module::new(&engine, &wasm), + wasmtime::Module::new(&engine, &mutated_wasm), + ) { + (Ok(o), Ok(m)) => (o, m), + // Ideally we would assert that they both errored if either one did, but + // it is possible that a mutation bumped some count above/below an + // implementation limit. + (_, _) => return, + }; + + let limits = StoreLimits { + remaining_memory: 1 << 30, + oom: false, + }; + let mut orig_store = wasmtime::Store::new(&engine, limits.clone()); + let mut mutated_store = wasmtime::Store::new(&engine, limits); + orig_store.limiter(|s| s as &mut dyn ResourceLimiter); + mutated_store.limiter(|s| s as &mut dyn ResourceLimiter); + let orig_imports = match dummy::dummy_imports(&mut orig_store, &orig_module) { + Ok(imps) => imps, + Err(_) => return, + }; + let mutated_imports = match dummy::dummy_imports(&mut mutated_store, &mutated_module) { + Ok(imps) => imps, + Err(_) => return, + }; + + let (orig_instance, mutated_instance) = match ( + wasmtime::Instance::new(&mut orig_store, &orig_module, &orig_imports), + wasmtime::Instance::new(&mut mutated_store, &mutated_module, &mutated_imports), + ) { + (Ok(x), Ok(y)) => (x, y), + (_, _) => return, + }; + + assert_same_state( + &orig_module, + &mut orig_store, + orig_instance, + &mut mutated_store, + mutated_instance, + ); + let should_have_same_state = assert_same_calls( + &orig_module, + &mut orig_store, + orig_instance, + &mut mutated_store, + mutated_instance, + ); + + if should_have_same_state { + assert_same_state( + &orig_module, + &mut orig_store, + orig_instance, + &mut mutated_store, + mutated_instance, + ); + } + } + + fn assert_same_state( + orig_module: &wasmtime::Module, + orig_store: &mut wasmtime::Store, + orig_instance: wasmtime::Instance, + mutated_store: &mut wasmtime::Store, + mutated_instance: wasmtime::Instance, + ) { + for export in orig_module.exports() { + match export.ty() { + wasmtime::ExternType::Global(_) => { + let orig = orig_instance + .get_export(&mut *orig_store, export.name()) + .unwrap() + .into_global() + .unwrap() + .get(&mut *orig_store); + let mutated = mutated_instance + .get_export(&mut *mutated_store, export.name()) + .unwrap() + .into_global() + .unwrap() + .get(&mut *mutated_store); + assert_val_eq(&orig, &mutated); + } + wasmtime::ExternType::Memory(_) => { + let orig = orig_instance + .get_export(&mut *orig_store, export.name()) + .unwrap() + .into_memory() + .unwrap(); + let mut h = DefaultHasher::default(); + orig.data(&orig_store).hash(&mut h); + let orig = h.finish(); + let mutated = mutated_instance + .get_export(&mut *mutated_store, export.name()) + .unwrap() + .into_memory() + .unwrap(); + let mut h = DefaultHasher::default(); + mutated.data(&mutated_store).hash(&mut h); + let mutated = h.finish(); + assert_eq!(orig, mutated, "original and mutated Wasm memories diverged"); + } + _ => continue, + } + } + } + + fn assert_same_calls( + orig_module: &wasmtime::Module, + orig_store: &mut wasmtime::Store, + orig_instance: wasmtime::Instance, + mutated_store: &mut wasmtime::Store, + mutated_instance: wasmtime::Instance, + ) -> bool { + for export in orig_module.exports() { + let func_ty = match export.ty() { + wasmtime::ExternType::Func(func_ty) => func_ty, + _ => continue, + }; + let orig_func = orig_instance + .get_func(&mut *orig_store, export.name()) + .unwrap(); + let mutated_func = mutated_instance + .get_func(&mut *mutated_store, export.name()) + .unwrap(); + let args = dummy::dummy_values(func_ty.params()); + let mut orig_results = vec![Val::I32(0); func_ty.results().len()]; + let mut mutated_results = orig_results.clone(); + log::debug!("invoking `{}`", export.name()); + match ( + { + orig_store.add_fuel(1_000).unwrap(); + orig_func.call(&mut *orig_store, &args, &mut orig_results) + }, + { + mutated_store.add_fuel(1000).unwrap(); + mutated_func.call(&mut *mutated_store, &args, &mut mutated_results) + }, + ) { + (Ok(()), Ok(())) => { + for (orig_val, mutated_val) in orig_results.iter().zip(mutated_results.iter()) { + assert_val_eq(orig_val, mutated_val); + } + } + // If either test case ran out of fuel then that's ok since + // mutation may add code or delete code which causes one side to + // take more or less fuel than the other. In this situation, + // however, execution has diverged so throw out the test case. + (Err(e), _) | (_, Err(e)) + if e.downcast_ref() == Some(&wasmtime::Trap::OutOfFuel) => + { + return false + } + (Err(orig), Err(mutated)) => { + log::debug!("original error {orig:?}"); + log::debug!("mutated error {mutated:?}"); + continue; + } + (orig, mutated) => panic!( + "mutated and original Wasm diverged: orig = {:?}; mutated = {:?}", + orig, mutated, + ), + } + } + + true + } + + fn assert_val_eq(orig_val: &wasmtime::Val, mutated_val: &wasmtime::Val) { + match (orig_val, mutated_val) { + (wasmtime::Val::I32(o), wasmtime::Val::I32(m)) => assert_eq!(o, m), + (wasmtime::Val::I64(o), wasmtime::Val::I64(m)) => assert_eq!(o, m), + (wasmtime::Val::F32(o), wasmtime::Val::F32(m)) => { + let o = f32::from_bits(*o); + let m = f32::from_bits(*m); + assert!(o == m || (o.is_nan() && m.is_nan())); + } + (wasmtime::Val::F64(o), wasmtime::Val::F64(m)) => { + let o = f64::from_bits(*o); + let m = f64::from_bits(*m); + assert!(o == m || (o.is_nan() && m.is_nan())); + } + (wasmtime::Val::V128(o), wasmtime::Val::V128(m)) => { + assert_eq!(o, m) + } + (wasmtime::Val::ExternRef(o), wasmtime::Val::ExternRef(m)) => { + assert_eq!(o.is_none(), m.is_none()) + } + (wasmtime::Val::FuncRef(o), wasmtime::Val::FuncRef(m)) => { + assert_eq!(o.is_none(), m.is_none()) + } + (o, m) => panic!( + "mutated and original Wasm diverged: orig = {:?}; mutated = {:?}", + o, m, + ), + } + } +} diff --git a/fuzz/src/no_traps.rs b/fuzz/src/no_traps.rs new file mode 100644 index 0000000000..12e6f1c331 --- /dev/null +++ b/fuzz/src/no_traps.rs @@ -0,0 +1,119 @@ +use arbitrary::{Result, Unstructured}; +use wasm_smith::SwarmConfig; +#[cfg(feature = "wasmtime")] +use wasmtime::*; + +#[cfg(feature = "wasmtime")] +#[path = "../../crates/fuzz-stats/src/lib.rs"] +pub mod fuzz_stats; + +// Define a fuzz target that accepts arbitrary +// `Module`s as input. +pub fn run(u: &mut Unstructured<'_>) -> Result<()> { + // Use data to generate a random wasm module + let (wasm_bytes, config) = crate::generate_valid_module(u, |config, _| { + config.disallow_traps = true; + config.threads_enabled = false; + config.exceptions_enabled = false; + config.max_memory_pages = config.max_memory_pages.min(100); + Ok(()) + })?; + validate_module(config.clone(), &wasm_bytes); + + // Tail calls aren't implemented in wasmtime, so don't try to run them + // there. + if config.tail_call_enabled { + return Ok(()); + } + + #[cfg(feature = "wasmtime")] + { + // Configure the engine, module, and store + let mut eng_conf = Config::new(); + eng_conf.wasm_memory64(true); + eng_conf.wasm_multi_memory(true); + eng_conf.consume_fuel(true); + let engine = Engine::new(&eng_conf).unwrap(); + let module = Module::from_binary(&engine, &wasm_bytes).unwrap(); + + // Call all exported functions + for export in module.exports() { + match export.ty() { + ExternType::Func(func_ty) => { + let mut store = Store::new( + &engine, + fuzz_stats::limits::StoreLimits { + remaining_memory: 1 << 30, + oom: false, + }, + ); + store.limiter(|s| s as &mut dyn ResourceLimiter); + store.add_fuel(1_000).unwrap(); + + // Instantiate the module + let inst_result = fuzz_stats::dummy::dummy_imports(&mut store, &module) + .and_then(|imports| Instance::new(&mut store, &module, &imports)); + let instance = match inst_result { + Ok(r) => r, + Err(err) => return Ok(check_err(err)), + }; + + let args = fuzz_stats::dummy::dummy_values(func_ty.params()); + let mut results = fuzz_stats::dummy::dummy_values(func_ty.results()); + let func = instance.get_func(&mut store, export.name()).unwrap(); + match func.call(&mut store, &args, &mut results) { + Ok(_) => {} + Err(err) => check_err(err), + } + } + _ => continue, + } + } + + fn check_err(err: anyhow::Error) { + // Allow stack overflow since this generally can't be protected + // against as it's an implementation detail of cranelift we could + // expose regardless of the limits placed on the function. + if let Some(wasmtime::Trap::StackOverflow) = err.downcast_ref::() { + return; + } + + // Allow out of fuel on module instantiation + if let Some(wasmtime::Trap::OutOfFuel) = err.downcast_ref::() { + return; + } + + let s = err.to_string(); + // Allow "nominal" traps such as running out of fuel and the + // module trying to allocate more resources than we'd like to + // allow it (e.g. lots of memories or lots of tables). + if s.contains("all fuel consumed") || s.contains("Insufficient resources") { + return; + } + + // Otherwise though this is a bug. + panic!("generated wasm trapped in non-trapping mode: {}", err) + } + } + Ok(()) +} + +fn validate_module(config: SwarmConfig, wasm_bytes: &Vec) { + // Validate the module or component and assert that it passes validation. + let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { + component_model: false, + multi_value: config.multi_value_enabled, + multi_memory: config.max_memories > 1, + bulk_memory: true, + reference_types: true, + simd: config.simd_enabled, + relaxed_simd: config.relaxed_simd_enabled, + memory64: config.memory64_enabled, + threads: config.threads_enabled, + exceptions: config.exceptions_enabled, + ..wasmparser::WasmFeatures::default() + }); + if let Err(e) = validator.validate_all(wasm_bytes) { + panic!("Invalid module: {}", e); + } +} diff --git a/fuzz/src/print.rs b/fuzz/src/print.rs new file mode 100644 index 0000000000..d9b8874205 --- /dev/null +++ b/fuzz/src/print.rs @@ -0,0 +1,7 @@ +use arbitrary::{Result, Unstructured}; + +pub fn run(u: &mut Unstructured<'_>) -> Result<()> { + let data = u.bytes(u.len())?; + drop(wasmprinter::print_bytes(data)); + Ok(()) +} diff --git a/fuzz/src/roundtrip.rs b/fuzz/src/roundtrip.rs new file mode 100644 index 0000000000..70c6daf7a8 --- /dev/null +++ b/fuzz/src/roundtrip.rs @@ -0,0 +1,96 @@ +use std::str; + +pub fn run(string: &str) { + write_file("wasm1.wat", &string); + // Weed out `(module binary ...)` because when we print the bytes and + // convert it back to binary it's not guaranteed to be exactly the same. + // (think of something like an over-long LEB encoding) + if string.contains("binary") { + return; + } + + // Also weed out `@custom` custom sections since we don't print those right + // now. + if string.contains("@custom") { + return; + } + let wasm = match wat::parse_str(string) { + Ok(bytes) => bytes, + Err(_) => return, + }; + write_file("wasm1.wasm", &wasm); + + // Only roundtrip valid modules for now since invalid modules can often have + // bizarre structures which aren't intended to print correctly or roundtrip + // well. + if wasmparser::validate(&wasm).is_err() { + return; + } + + // And finally validate that the name section, if present, is valid. This + // can be invalid if names in the name section are too long (e.g. exceeding + // the maximum length of a string). The printing process will skip invalid + // name sections, so if it's invalid then our roundtrip'd bytes will + // trivially not match, but not in an interesting way. + if validate_name_section(&wasm).is_err() { + return; + } + let string2 = match wasmprinter::print_bytes(&wasm) { + Ok(s) => s, + Err(_) => return, + }; + write_file("wasm2.wat", &string2); + + let wasm2 = wat::parse_str(&string2).unwrap(); + write_file("wasm2.wasm", &wasm2); + if wasm == wasm2 { + return; + } + + panic!("wasm bytes differ on roundtrip"); +} + +fn write_file(path: &str, contents: impl AsRef<[u8]>) { + if !log::log_enabled!(log::Level::Debug) { + return; + } + log::debug!("writing file {path}"); + std::fs::write(path, contents.as_ref()).unwrap(); +} + +fn validate_name_section(wasm: &[u8]) -> wasmparser::Result<()> { + use wasmparser::*; + for payload in Parser::new(0).parse_all(wasm) { + let reader = match payload? { + Payload::CustomSection(c) if c.name() == "name" => { + NameSectionReader::new(c.data(), c.data_offset()) + } + _ => continue, + }; + for section in reader { + match section? { + Name::Module { .. } => {} + Name::Function(n) + | Name::Type(n) + | Name::Table(n) + | Name::Memory(n) + | Name::Global(n) + | Name::Element(n) + | Name::Data(n) => { + for name in n { + name?; + } + } + Name::Local(n) | Name::Label(n) => { + for name in n { + for name in name?.names { + name?; + } + } + } + Name::Unknown { .. } => {} + } + } + } + Ok(()) +} diff --git a/fuzz/src/roundtrip_wit.rs b/fuzz/src/roundtrip_wit.rs new file mode 100644 index 0000000000..9a6c74c287 --- /dev/null +++ b/fuzz/src/roundtrip_wit.rs @@ -0,0 +1,103 @@ +use arbitrary::{Result, Unstructured}; +use std::borrow::Cow; +use std::path::Path; +use wasm_encoder::{CustomSection, Encode, Section}; +use wit_component::*; +use wit_parser::{Resolve, SourceMap}; + +pub fn run(u: &mut Unstructured<'_>) -> Result<()> { + let wasm = u.arbitrary().and_then(|config| { + log::debug!("config: {config:#?}"); + wit_smith::smith(&config, u) + })?; + write_file("doc1.wasm", &wasm); + let (resolve, _pkg) = match wit_component::decode(&wasm).unwrap() { + DecodedWasm::WitPackage(resolve, pkg) => (resolve, pkg), + DecodedWasm::Component(..) => unreachable!(), + }; + roundtrip_through_printing("doc1", &resolve, &wasm); + + let (resolve2, pkg2) = match wit_component::decode(&wasm).unwrap() { + DecodedWasm::WitPackage(resolve, pkg) => (resolve, pkg), + DecodedWasm::Component(..) => unreachable!(), + }; + + let wasm2 = wit_component::encode(&resolve2, pkg2).expect("failed to encode WIT document"); + write_file("doc2.wasm", &wasm2); + roundtrip_through_printing("doc2", &resolve2, &wasm2); + + if wasm != wasm2 { + panic!("roundtrip wasm didn't match"); + } + + // If there's hundreds or thousands of worlds only work with the first few + // to avoid timing out this fuzzer with asan enabled. + for (id, _world) in resolve.worlds.iter().take(20) { + let mut dummy = wit_component::dummy_module(&resolve, id); + let metadata = + wit_component::metadata::encode(&resolve, id, StringEncoding::UTF8, None).unwrap(); + let section = CustomSection { + name: "component-type".into(), + data: Cow::Borrowed(&metadata), + }; + dummy.push(section.id()); + section.encode(&mut dummy); + + write_file("dummy.wasm", &dummy); + let wasm = wit_component::ComponentEncoder::default() + .module(&dummy) + .unwrap() + .encode() + .unwrap(); + write_file("dummy.component.wasm", &wasm); + wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { + component_model: true, + ..Default::default() + }) + .validate_all(&wasm) + .unwrap(); + + wit_component::decode(&wasm).unwrap(); + } + Ok(()) +} + +fn roundtrip_through_printing(file: &str, resolve: &Resolve, wasm: &[u8]) { + // For all packages in `resolve` print them all to a string, then re-parse + // them and insert them into a `new_resolve`. + let mut new_resolve = Resolve::default(); + let mut last = None; + for (id, pkg) in resolve.packages.iter() { + let mut map = SourceMap::new(); + let pkg_name = &pkg.name; + let doc = WitPrinter::default().print(resolve, id).unwrap(); + write_file(&format!("{file}-{pkg_name}.wit"), &doc); + map.push(format!("{pkg_name}.wit").as_ref(), doc); + let unresolved = map.parse().unwrap(); + let id = new_resolve.push(unresolved).unwrap(); + last = Some(id); + } + + // Finally encode the `new_resolve` which should be the exact same as + // before. + let wasm2 = wit_component::encode(&new_resolve, last.unwrap()).unwrap(); + write_file(&format!("{file}-reencoded.wasm"), &wasm2); + if wasm != wasm2 { + panic!("failed to roundtrip through text printing"); + } +} + +fn write_file(path: &str, contents: impl AsRef<[u8]>) { + if !log::log_enabled!(log::Level::Debug) { + return; + } + log::debug!("writing file {path}"); + let contents = contents.as_ref(); + let path = Path::new(path); + std::fs::write(path, contents).unwrap(); + if path.extension().and_then(|s| s.to_str()) == Some("wasm") { + let path = path.with_extension("wat"); + log::debug!("writing file {}", path.display()); + std::fs::write(path, wasmprinter::print_bytes(&contents).unwrap()).unwrap(); + } +} diff --git a/fuzz/src/text_parser.rs b/fuzz/src/text_parser.rs new file mode 100644 index 0000000000..ff592aae44 --- /dev/null +++ b/fuzz/src/text_parser.rs @@ -0,0 +1,7 @@ +pub fn run(s: &str) { + let buf = match wast::parser::ParseBuffer::new(s) { + Ok(b) => b, + Err(_) => return, + }; + drop(wast::parser::parse::(&buf)); +} diff --git a/fuzz/src/validate.rs b/fuzz/src/validate.rs new file mode 100644 index 0000000000..81edcdf9ea --- /dev/null +++ b/fuzz/src/validate.rs @@ -0,0 +1,42 @@ +use arbitrary::{Arbitrary, Result, Unstructured}; +use wasm_smith::MaybeInvalidModule; +use wasmparser::{Validator, WasmFeatures}; + +pub fn run(u: &mut Unstructured<'_>) -> Result<()> { + let mut validator = Validator::new_with_features(WasmFeatures { + reference_types: u.arbitrary()?, + multi_value: u.arbitrary()?, + threads: u.arbitrary()?, + simd: u.arbitrary()?, + component_model: u.arbitrary()?, + tail_call: u.arbitrary()?, + bulk_memory: u.arbitrary()?, + floats: u.arbitrary()?, + multi_memory: u.arbitrary()?, + memory64: u.arbitrary()?, + exceptions: u.arbitrary()?, + relaxed_simd: u.arbitrary()?, + extended_const: u.arbitrary()?, + mutable_global: u.arbitrary()?, + saturating_float_to_int: u.arbitrary()?, + sign_extension: u.arbitrary()?, + memory_control: u.arbitrary()?, + function_references: u.arbitrary()?, + gc: u.arbitrary()?, + component_model_values: u.arbitrary()?, + }); + let use_maybe_invalid = u.arbitrary()?; + + if use_maybe_invalid { + if let Ok(module) = MaybeInvalidModule::arbitrary(u) { + let wasm = module.to_bytes(); + crate::log_wasm(&wasm, ""); + drop(validator.validate_all(&wasm)); + } + } else { + let wasm = u.bytes(u.len())?; + crate::log_wasm(wasm, ""); + drop(validator.validate_all(wasm)); + } + Ok(()) +} diff --git a/fuzz/src/validate_valid_module.rs b/fuzz/src/validate_valid_module.rs new file mode 100644 index 0000000000..66cad448d3 --- /dev/null +++ b/fuzz/src/validate_valid_module.rs @@ -0,0 +1,75 @@ +use arbitrary::{Result, Unstructured}; + +// Define a fuzz target that accepts arbitrary +// `Module`s or `Component`s as input. +pub fn run(u: &mut Unstructured<'_>) -> Result<()> { + // We want to prioritize fuzzing of modules for the time being + // so we'll only generate a component 10% of the time + // + // TODO: remove this `false && ...` once this fuzzer works again for + // components. + let generate_component = false + && match u.ratio::(1, 10) { + Ok(b) => b, + Err(_) => false, + }; + let (wasm_bytes, config) = if generate_component { + crate::generate_valid_component(u, |c, u| { + c.max_components = u.int_in_range(0..=1_000)?; + c.max_instances = u.int_in_range(0..=1_000)?; + c.max_values = u.int_in_range(0..=1_000)?; + Ok(()) + })? + } else { + crate::generate_valid_module(u, |_, _| Ok(()))? + }; + + // Validate the module or component and assert that it passes validation. + let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { + component_model: generate_component, + multi_value: config.multi_value_enabled, + multi_memory: config.max_memories > 1, + bulk_memory: true, + reference_types: true, + simd: config.simd_enabled, + relaxed_simd: config.relaxed_simd_enabled, + memory64: config.memory64_enabled, + threads: config.threads_enabled, + exceptions: config.exceptions_enabled, + ..wasmparser::WasmFeatures::default() + }); + if let Err(e) = validator.validate_all(&wasm_bytes) { + let component_or_module = if generate_component { + "component" + } else { + "module" + }; + panic!("Invalid {}: {}", component_or_module, e); + } + + // After validation make sure that binary-to-text and text-to-binary + // transforms all work as well. + let wat_string = wasmprinter::print_bytes(&wasm_bytes).unwrap_or_else(|e| { + panic!( + "failed first disassembly of Wasm into wat with `wasmprinter::print_bytes`: {}", + e + ) + }); + let wasm_bytes = wat::parse_str(&wat_string).unwrap_or_else(|e| { + panic!( + "failed to assemble wat into Wasm with `wat::parse_str`: {}", + e + ) + }); + let wat_string2 = wasmprinter::print_bytes(&wasm_bytes).unwrap_or_else(|e| { + panic!( + "failed second disassembly of Wasm into wat with `wasmprinter::print_bytes`: {}", + e + ) + }); + + if wat_string != wat_string2 { + panic!("failed to roundtrip valid module"); + } + Ok(()) +} diff --git a/src/bin/wasm-tools/addr2line.rs b/src/bin/wasm-tools/addr2line.rs new file mode 100644 index 0000000000..5478a7cb45 --- /dev/null +++ b/src/bin/wasm-tools/addr2line.rs @@ -0,0 +1,160 @@ +use addr2line::{Context, LookupResult}; +use anyhow::{bail, Context as _, Result}; +use gimli::EndianSlice; +use std::collections::HashMap; +use std::io::Write; +use std::u64; +use wasmparser::{Parser, Payload}; + +/// Translate a WebAssembly address to a filename and line number using DWARF +/// debugging information. +/// +/// WebAssembly binaries compiled with Clang can have DWARF debug information +/// inserted into them to map from WebAssembly instruction offsets to original +/// filenames and line numbers. For example when compiling C the `-g` argument +/// can be used or when compiling Rust the `-Cdebuginfo=1` argument can be used +/// (or the default `dev` profile for Cargo). This subcommand will parse the +/// DWARF debugging information and translate a list of addresses to their +/// original filenames and line numbers. +/// +/// Each address may have multiple lines printed for it indicating that the +/// address is an inlined function into another function. Frames are printed +/// innermost or youngest first. +#[derive(clap::Parser)] +pub struct Opts { + #[clap(flatten)] + io: wasm_tools::InputOutput, + + /// Addresses to convert to filenames and line numbers. + /// + /// Arguments can be specified as either `0x...` or `@...` in hexadecimal or + /// are otherwise parsed as a base-10 address. Addresses should be relative + /// to the beginning of the module unless `--code-section-relative` is + /// passed in which case they should be relative to the beginning of the + /// contents of the code section. + addresses: Vec, + + /// Indicates that addresses are code-section-relative instead of offsets + /// from the beginning of the module. + #[clap(long)] + code_section_relative: bool, +} + +impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + + pub fn run(&self) -> Result<()> { + let wasm = self.io.parse_input_wasm()?; + + let (code_start, custom_sections) = self + .parse_custom_sections(&wasm) + .context("failed to parse input and read custom sections")?; + + let dwarf = gimli::Dwarf::load(|id| -> Result<_> { + let data = custom_sections.get(id.name()).copied().unwrap_or(&[]); + Ok(EndianSlice::new(data, gimli::LittleEndian)) + })?; + let cx = Context::from_dwarf(dwarf) + .context("failed to create addr2line dwarf mapping context")?; + + let mut output = self.io.output_writer()?; + + for addr in self.addresses.iter() { + self.addr2line(&addr, code_start, &cx, &mut output) + .with_context(|| format!("failed to find frames for `{addr}`"))?; + } + + Ok(()) + } + + fn parse_custom_sections<'a>( + &self, + wasm: &'a [u8], + ) -> Result<(Option, HashMap<&'a str, &'a [u8]>)> { + let mut ret = HashMap::new(); + let mut code_start = None; + for payload in Parser::new(0).parse_all(wasm) { + match payload? { + Payload::CustomSection(s) => { + ret.insert(s.name(), s.data()); + } + Payload::CodeSectionStart { range, .. } => { + code_start = Some(range.start as u64); + } + _ => {} + } + } + Ok((code_start, ret)) + } + + fn addr2line( + &self, + addr: &str, + code_start: Option, + cx: &Context>, + out: &mut dyn Write, + ) -> Result<()> { + // Support either `0x` or `@` prefixes for hex addresses since 0x is + // standard and @ is used by wasmprinter (and web browsers I think?) + let addr = if let Some(hex) = addr.strip_prefix("0x").or_else(|| addr.strip_prefix("@")) { + u64::from_str_radix(hex, 16)? + } else { + addr.parse()? + }; + + // Addresses in DWARF are relative to the start of the text section, so + // factor that in here. + let text_relative_addr = if self.code_section_relative { + addr + } else { + match code_start { + Some(start) => addr + .checked_sub(start) + .context("address is before the beginning of the text section")?, + None => bail!("no code section found in module"), + } + }; + + let mut frames = match cx.find_frames(text_relative_addr) { + LookupResult::Output(result) => result?, + LookupResult::Load { .. } => { + bail!("split-dwarf is not supported yet"); + } + }; + + let mut first = true; + while let Some(frame) = frames.next()? { + if first { + write!(out, "{addr:#x}: ")?; + } else { + write!(out, "\t")?; + } + first = false; + if let Some(func) = &frame.function { + write!(out, "{}", func.demangle()?)?; + } else { + write!(out, "")?; + } + + if let Some(loc) = &frame.location { + write!(out, " ")?; + if let Some(file) = loc.file { + write!(out, "{file}")?; + } + if let Some(line) = loc.line { + write!(out, ":{line}")?; + } + if let Some(column) = loc.column { + write!(out, ":{column}")?; + } + } + writeln!(out, "")?; + } + if first { + writeln!(out, "{addr:#x}: no dwarf frames found for this address")?; + } + Ok(()) + } +} diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs new file mode 100644 index 0000000000..0ba7aa3b95 --- /dev/null +++ b/src/bin/wasm-tools/component.rs @@ -0,0 +1,642 @@ +//! The WebAssembly component tool command line interface. + +use std::collections::HashMap; +use std::io::Read; +use std::path::{Path, PathBuf}; + +use anyhow::{bail, Context, Result}; +use clap::Parser; + +use wasm_tools::Output; +use wit_component::{ + embed_component_metadata, is_wasm_binary_or_wat, parse_wit_from_path, ComponentEncoder, + DecodedWasm, Linker, StringEncoding, WitPrinter, +}; +use wit_parser::{Resolve, UnresolvedPackage}; + +/// WebAssembly wit-based component tooling. +#[derive(Parser)] +pub enum Opts { + New(NewOpts), + Wit(WitOpts), + Embed(EmbedOpts), + Targets(TargetsOpts), + Link(LinkOpts), +} + +impl Opts { + pub fn run(self) -> Result<()> { + match self { + Opts::New(new) => new.run(), + Opts::Wit(wit) => wit.run(), + Opts::Embed(embed) => embed.run(), + Opts::Targets(targets) => targets.run(), + Opts::Link(link) => link.run(), + } + } + + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + match self { + Opts::New(new) => new.general_opts(), + Opts::Wit(wit) => wit.general_opts(), + Opts::Embed(embed) => embed.general_opts(), + Opts::Targets(targets) => targets.general_opts(), + Opts::Link(link) => link.general_opts(), + } + } +} + +fn parse_optionally_name_file(s: &str) -> (&str, &str) { + let mut parts = s.splitn(2, '='); + let name_or_path = parts.next().unwrap(); + match parts.next() { + Some(path) => (name_or_path, path), + None => { + let name = Path::new(name_or_path) + .file_name() + .unwrap() + .to_str() + .unwrap(); + let name = match name.find('.') { + Some(i) => &name[..i], + None => name, + }; + (name, name_or_path) + } + } +} + +fn parse_adapter(s: &str) -> Result<(String, Vec)> { + let (name, path) = parse_optionally_name_file(s); + let wasm = wat::parse_file(path)?; + Ok((name.to_string(), wasm)) +} + +/// WebAssembly component encoder from an input core wasm binary. +/// +/// This subcommand will create a new component `*.wasm` file from an input core +/// wasm binary. The input core wasm binary must have metadata embedded within +/// it about the component-types used during its compilation. This is done +/// automatically for `wit-bindgen`-based projects, for example, and can be +/// manually done through the `wasm-tools component embed` subcommand. +/// +/// This command will perform translation by collecting all type information +/// used during compilation of the core wasm module and will produce a component +/// with all of this type information resolved. +#[derive(Parser)] +pub struct NewOpts { + /// The path to an adapter module to satisfy imports not otherwise bound to + /// WIT interfaces. + /// + /// An adapter module can be used to translate the `wasi_snapshot_preview1` + /// ABI, for example, to one that uses the component model. The first + /// `[NAME=]` specified in the argument is inferred from the name of file + /// specified by `MODULE` if not present and is the name of the import + /// module that's being implemented (e.g. `wasi_snapshot_preview1.wasm`. + /// + /// The second part of this argument, optionally specified, is the interface + /// that this adapter module imports. If not specified then the interface + /// imported is inferred from the adapter module itself. + #[clap(long = "adapt", value_name = "[NAME=]MODULE", value_parser = parse_adapter)] + adapters: Vec<(String, Vec)>, + + #[clap(flatten)] + io: wasm_tools::InputOutput, + + /// Skip validation of the output component. + #[clap(long)] + skip_validation: bool, + + /// Print the output in the WebAssembly text format instead of binary. + #[clap(long, short = 't')] + wat: bool, + + /// Use memory.grow to realloc memory and stack allocation. + #[clap(long)] + realloc_via_memory_grow: bool, +} + +impl NewOpts { + fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + + /// Executes the application. + fn run(self) -> Result<()> { + let wasm = self.io.parse_input_wasm()?; + let mut encoder = ComponentEncoder::default() + .validate(!self.skip_validation) + .module(&wasm)?; + + for (name, wasm) in self.adapters.iter() { + encoder = encoder.adapter(name, wasm)?; + } + + encoder = encoder.realloc_via_memory_grow(self.realloc_via_memory_grow); + + let bytes = encoder + .encode() + .context("failed to encode a component from module")?; + + self.io.output(Output::Wasm { + bytes: &bytes, + wat: self.wat, + })?; + + Ok(()) + } +} + +/// Embeds metadata for a component inside of a core wasm module. +/// +/// This subcommand is a convenience tool provided for producing core wasm +/// binaries which will get consumed by `wasm-tools component new`. This will +/// embed metadata for a component within a core wasm binary as a custom +/// section. +/// +/// This metadata describe the imports and exports of a core wasm module with a +/// WIT package's `world`. The metadata will be used when creating a full +/// component. +/// +/// Note that this subcommand may not be required most of the time since most +/// language tooling will already embed this metadata in the final wasm binary +/// for you. This is primarily intended for one-off testing or for developers +/// working with text format wasm. +#[derive(Parser)] +pub struct EmbedOpts { + /// The WIT package where the `world` that the core wasm module implements + /// lives. + /// + /// This can either be a directory or a path to a single `*.wit` file. + wit: PathBuf, + + #[clap(flatten)] + io: wasm_tools::InputOutput, + + /// The expected string encoding format for the component. + /// + /// Supported values are: `utf8` (default), `utf16`, and `compact-utf16`. + /// This is only applicable to the `--wit` argument to describe the string + /// encoding of the functions in that world. + #[clap(long, value_name = "ENCODING")] + encoding: Option, + + /// The world that the component uses. + /// + /// This is the path, within the `WIT` package provided as a positional + /// argument, to the `world` that the core wasm module works with. This can + /// either be a bare string which a document name that has a `default + /// world`, or it can be a `foo/bar` name where `foo` names a document and + /// `bar` names a world within that document. + #[clap(short, long)] + world: Option, + + /// Don't read a core wasm module as input, instead generating a "dummy" + /// module as a placeholder. + /// + /// This flag will generate a dummy core wasm module on the fly to match the + /// `WIT` argument provided. This dummy module will have the correct + /// imports/exports and the right signatures for the component model. This + /// can be useful to, perhaps, inspect a template module and what it looks + /// like to work with an interface in the component model. + #[clap(long)] + dummy: bool, + + /// Print the output in the WebAssembly text format instead of binary. + #[clap(long, short = 't')] + wat: bool, +} + +impl EmbedOpts { + fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + + /// Executes the application. + fn run(self) -> Result<()> { + let wasm = if self.dummy { + None + } else { + Some(self.io.parse_input_wasm()?) + }; + let (resolve, id) = parse_wit_from_path(self.wit)?; + let world = resolve.select_world(id, self.world.as_deref())?; + + let mut wasm = wasm.unwrap_or_else(|| wit_component::dummy_module(&resolve, world)); + + embed_component_metadata( + &mut wasm, + &resolve, + world, + self.encoding.unwrap_or(StringEncoding::UTF8), + )?; + + self.io.output(Output::Wasm { + bytes: &wasm, + wat: self.wat, + })?; + + Ok(()) + } +} + +fn parse_optionally_name_library(s: &str) -> (&str, &str) { + let mut parts = s.splitn(2, '='); + let name_or_path = parts.next().unwrap(); + match parts.next() { + Some(path) => (name_or_path, path), + None => { + let name = Path::new(name_or_path) + .file_name() + .unwrap() + .to_str() + .unwrap(); + (name, name_or_path) + } + } +} + +fn parse_library(s: &str) -> Result<(String, Vec)> { + let (name, path) = parse_optionally_name_library(s); + let wasm = wat::parse_file(path)?; + Ok((name.to_string(), wasm)) +} + +/// Link one or more dynamic library modules, producing a component +/// +/// This is similar to the `new` subcommand, except that it accepts an arbitrary number of input modules rather +/// than a single "main" module. Those modules are expected to conform to the [dynamic linking +/// convention](https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md). +/// +/// The resulting component's type will be the union of the types found in any `component-type*` custom sections in +/// the input modules. +/// +/// See +/// https://github.com/WebAssembly/component-model/blob/main/design/mvp/examples/SharedEverythingDynamicLinking.md +/// for further details. +#[derive(Parser)] +pub struct LinkOpts { + /// Input libraries to link + #[clap(value_name = "[NAME=]MODULE", value_parser = parse_library)] + inputs: Vec<(String, Vec)>, + + /// Input library to link and make available for dynamic resolution via `dlopen` (may be repeated) + #[clap(long, value_name = "[NAME=]MODULE", value_parser = parse_library)] + dl_openable: Vec<(String, Vec)>, + + /// The path to an adapter module to satisfy imports not otherwise bound to + /// WIT interfaces. + /// + /// An adapter module can be used to translate the `wasi_snapshot_preview1` + /// ABI, for example, to one that uses the component model. The first + /// `[NAME=]` specified in the argument is inferred from the name of file + /// specified by `MODULE` if not present and is the name of the import + /// module that's being implemented (e.g. `wasi_snapshot_preview1.wasm`. + /// + /// The second part of this argument, optionally specified, is the interface + /// that this adapter module imports. If not specified then the interface + /// imported is inferred from the adapter module itself. + #[clap(long = "adapt", value_name = "[NAME=]MODULE", value_parser = parse_adapter)] + adapters: Vec<(String, Vec)>, + + /// Size of stack (in bytes) to allocate in the synthesized main module + #[clap(long)] + stack_size: Option, + + #[clap(flatten)] + output: wasm_tools::OutputArg, + + #[clap(flatten)] + general: wasm_tools::GeneralOpts, + + /// Skip validation of the output component. + #[clap(long)] + skip_validation: bool, + + /// Print the output in the WebAssembly text format instead of binary. + #[clap(long, short = 't')] + wat: bool, + + /// Generate trapping stubs for any missing functions + #[clap(long)] + stub_missing_functions: bool, +} + +impl LinkOpts { + fn general_opts(&self) -> &wasm_tools::GeneralOpts { + &self.general + } + + /// Executes the application. + fn run(self) -> Result<()> { + let mut linker = Linker::default() + .validate(!self.skip_validation) + .stub_missing_functions(self.stub_missing_functions); + + if let Some(stack_size) = self.stack_size { + linker = linker.stack_size(stack_size); + } + + for (name, wasm) in &self.inputs { + linker = linker.library(name, wasm, false)?; + } + + for (name, wasm) in &self.dl_openable { + linker = linker.library(name, wasm, true)?; + } + + for (name, wasm) in &self.adapters { + linker = linker.adapter(name, wasm)?; + } + + let bytes = linker + .encode() + .context("failed to encode a component from modules")?; + + self.output.output(Output::Wasm { + bytes: &bytes, + wat: self.wat, + })?; + + Ok(()) + } +} + +/// Tool for working with the WIT text format for components. +/// +/// This subcommand can be used to inspect and debug the WIT text or binary +/// format with either WIT packages or binary components. Using this subcommand +/// a WIT package can be translated to binary, a WIT binary can be translated +/// back to text, and a WIT document can be extracted from a component binary to +/// inspect its interfaces. +#[derive(Parser)] +pub struct WitOpts { + #[clap(flatten)] + general: wasm_tools::GeneralOpts, + + /// Input file or directory to process. + /// + /// The file specified can be a `*.wit` file parsed as a single-document + /// package. It can be a directory to be parsed as a WIT package. It can be + /// a `*.wat` or `*.wasm` file for either the binary representation of a WIT + /// package or a component itself to extract the interface from. The type of + /// input is inferred from the contents of the path specified. + /// + /// If not provided or if this is `-` then stdin is read entirely and + /// processed. + input: Option, + + #[clap(flatten)] + output: wasm_tools::OutputArg, + + /// Emit a WebAssembly binary representation instead of the WIT text format. + #[clap(short, long, conflicts_with = "wat", conflicts_with = "out_dir")] + wasm: bool, + + /// Emit a WebAssembly textual representation instead of the WIT text + /// format. + #[clap(short = 't', long, conflicts_with = "wasm", conflicts_with = "out_dir")] + wat: bool, + + /// Do not include doc comments when emitting WIT text. + #[clap(long)] + no_docs: bool, + + /// Emit the entire WIT resolution graph instead of just the "top level" + /// package to the output directory specified. + /// + /// The output directory will contain textual WIT files which represent all + /// packages known from the input. + #[clap( + long, + conflicts_with = "wasm", + conflicts_with = "wat", + conflicts_with = "output" + )] + out_dir: Option, + + /// Skips the validation performed when using the `--wasm` and `--wat` + /// options. + #[clap(long)] + skip_validation: bool, + + /// Emit the WIT document as JSON instead of text. + #[clap( + short, + long, + conflicts_with = "wasm", + conflicts_with = "out_dir", + conflicts_with = "wat" + )] + json: bool, +} + +impl WitOpts { + fn general_opts(&self) -> &wasm_tools::GeneralOpts { + &self.general + } + + /// Executes the application. + fn run(self) -> Result<()> { + // First up determine the actual `DecodedWasm` as the input. This could + // come from a number of sources: + // + // * If a `*.wat` or `*.wasm` is specified, use `wit_component::decode` + // * If a directory is specified, parse it as a `Resolve`-oriented + // package with a `deps` directory optionally available. + // * If a file is specified then it's just a normal wit package where + // deps can't be resolved. + // * If no file is specified then parse the input as either `*.wat`, + // `*.wasm`, or `*.wit` and do as above. + // + // Eventually there will want to be more flags for things like + // specifying a directory but specifying the WIT dependencies are + // located elsewhere. This should be sufficient for now though. + let decoded = match &self.input { + Some(input) => match input.extension().and_then(|s| s.to_str()) { + Some("wat") | Some("wasm") => { + let bytes = wat::parse_file(&input)?; + decode_wasm(&bytes).context("failed to decode WIT document")? + } + _ => { + let (resolve, id) = parse_wit_from_path(input)?; + DecodedWasm::WitPackage(resolve, id) + } + }, + None => { + let mut stdin = Vec::new(); + std::io::stdin() + .read_to_end(&mut stdin) + .context("failed to read ")?; + + if is_wasm_binary_or_wat(&stdin) { + let bytes = wat::parse_bytes(&stdin).map_err(|mut e| { + e.set_path(""); + e + })?; + + decode_wasm(&bytes).context("failed to decode WIT document")? + } else { + let stdin = match std::str::from_utf8(&stdin) { + Ok(s) => s, + Err(_) => bail!("stdin was not valid utf-8"), + }; + let mut resolve = Resolve::default(); + let pkg = UnresolvedPackage::parse("".as_ref(), stdin)?; + let id = resolve.push(pkg)?; + DecodedWasm::WitPackage(resolve, id) + } + } + }; + + // Now that the WIT document has been decoded, it's time to emit it. + // This interprets all of the output options and performs such a task. + if self.json { + self.emit_json(&decoded)?; + return Ok(()); + } + if self.wasm || self.wat { + self.emit_wasm(&decoded)?; + } else { + self.emit_wit(&decoded)?; + } + Ok(()) + } + + fn emit_wasm(&self, decoded: &DecodedWasm) -> Result<()> { + assert!(self.wasm || self.wat); + assert!(self.out_dir.is_none()); + + let bytes = wit_component::encode(decoded.resolve(), decoded.package())?; + if !self.skip_validation { + wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { + component_model: true, + ..Default::default() + }) + .validate_all(&bytes)?; + } + self.output.output(Output::Wasm { + bytes: &bytes, + wat: self.wat, + })?; + Ok(()) + } + + fn emit_wit(&self, decoded: &DecodedWasm) -> Result<()> { + assert!(!self.wasm && !self.wat); + + let resolve = decoded.resolve(); + let main = decoded.package(); + + let mut printer = WitPrinter::default(); + printer.emit_docs(!self.no_docs); + + match &self.out_dir { + Some(dir) => { + assert!(self.output.output_path().is_none()); + std::fs::create_dir_all(dir) + .with_context(|| format!("failed to create directory: {dir:?}"))?; + + // Classify all packages by name to determine how to name their + // output directories. + let mut names = HashMap::new(); + for (_id, pkg) in resolve.packages.iter() { + let cnt = names + .entry(&pkg.name.name) + .or_insert(HashMap::new()) + .entry(&pkg.name.namespace) + .or_insert(0); + *cnt += 1; + } + + for (id, pkg) in resolve.packages.iter() { + let output = printer.print(resolve, id)?; + let out_dir = if id == main { + dir.clone() + } else { + let dir = dir.join("deps"); + let packages_with_same_name = &names[&pkg.name.name]; + if packages_with_same_name.len() == 1 { + dir.join(&pkg.name.name) + } else { + let packages_with_same_namespace = + packages_with_same_name[&pkg.name.namespace]; + if packages_with_same_namespace == 1 { + dir.join(format!("{}:{}", pkg.name.namespace, pkg.name.name)) + } else { + dir.join(pkg.name.to_string()) + } + } + }; + std::fs::create_dir_all(&out_dir) + .with_context(|| format!("failed to create directory: {out_dir:?}"))?; + let path = out_dir.join("main.wit"); + std::fs::write(&path, &output) + .with_context(|| format!("failed to write file: {path:?}"))?; + println!("Writing: {}", path.display()); + } + } + None => { + let output = printer.print(resolve, main)?; + self.output.output(Output::Wat(&output))?; + } + } + + Ok(()) + } + + fn emit_json(&self, decoded: &DecodedWasm) -> Result<()> { + assert!(!self.wasm && !self.wat); + + let resolve = decoded.resolve(); + let output = serde_json::to_string_pretty(&resolve)?; + self.output.output(Output::Json(&output))?; + + Ok(()) + } +} + +/// Tool for verifying whether a component conforms to a world. +#[derive(Parser)] +pub struct TargetsOpts { + #[clap(flatten)] + general: wasm_tools::GeneralOpts, + + /// The WIT package containing the `world` used to test a component for conformance. + /// + /// This can either be a directory or a path to a single `*.wit` file. + wit: PathBuf, + + /// The world used to test whether a component conforms to its signature. + #[clap(short, long)] + world: Option, + + #[clap(flatten)] + input: wasm_tools::InputArg, +} + +impl TargetsOpts { + fn general_opts(&self) -> &wasm_tools::GeneralOpts { + &self.general + } + + /// Executes the application. + fn run(self) -> Result<()> { + let (resolve, package_id) = parse_wit_from_path(&self.wit)?; + let world = resolve.select_world(package_id, self.world.as_deref())?; + let component_to_test = self.input.parse_wasm()?; + + wit_component::targets(&resolve, world, &component_to_test)?; + + Ok(()) + } +} + +fn decode_wasm(bytes: &[u8]) -> Result { + if wasmparser::Parser::is_component(bytes) { + wit_component::decode(bytes) + } else { + let (_wasm, bindgen) = wit_component::metadata::decode(bytes)?; + Ok(DecodedWasm::Component(bindgen.resolve, bindgen.world)) + } +} diff --git a/src/bin/wasm-tools/compose.rs b/src/bin/wasm-tools/compose.rs index 97cbaf5bca..0d781e1a7a 100644 --- a/src/bin/wasm-tools/compose.rs +++ b/src/bin/wasm-tools/compose.rs @@ -1,15 +1,120 @@ -use anyhow::Result; +//! Module for CLI parsing. + +use anyhow::{Context, Result}; use clap::Parser; -use wasm_compose::cli::WasmComposeCommand; +use std::path::{Path, PathBuf}; +use wasm_compose::{composer::ComponentComposer, config::Config}; +use wasmparser::{Validator, WasmFeatures}; +/// WebAssembly component composer. +/// +/// A tool for composing WebAssembly components together. #[derive(Parser)] +#[clap(name = "component-encoder", version = env!("CARGO_PKG_VERSION"))] pub struct Opts { #[clap(flatten)] - cmd: WasmComposeCommand, + general: wasm_tools::GeneralOpts, + + #[clap(flatten)] + output: wasm_tools::OutputArg, + + /// The path to the configuration file to use. + #[clap(long, short = 'c', value_name = "CONFIG")] + config: Option, + + /// Definition components whose exports define import dependencies to fulfill from. + #[clap(long = "definitions", short = 'd', value_name = "DEFS")] + defs: Vec, + + /// A path to search for imports. + #[clap(long = "search-path", short = 'p', value_name = "PATH")] + paths: Vec, + + /// Skip validation of the composed output component. + #[clap(long)] + skip_validation: bool, + + /// Do not allow instance imports in the composed output component. + #[clap(long = "no-imports")] + disallow_imports: bool, + + /// The path to the root component to compose. + #[clap(value_name = "COMPONENT")] + component: PathBuf, + + /// Output the text format of WebAssembly instead of the binary format. + #[clap(short = 't', long)] + wat: bool, } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + &self.general + } + pub fn run(self) -> Result<()> { - self.cmd.execute() + let config = self.create_config()?; + log::debug!("configuration:\n{:#?}", config); + + let bytes = ComponentComposer::new(&self.component, &config).compose()?; + + self.output.output(wasm_tools::Output::Wasm { + bytes: &bytes, + wat: self.wat, + })?; + + if config.skip_validation { + log::debug!("output validation was skipped"); + } else { + Validator::new_with_features(WasmFeatures { + component_model: true, + ..Default::default() + }) + .validate_all(&bytes) + .with_context(|| { + let output = match self.output.output_path() { + Some(s) => format!(" `{}`", s.display()), + None => String::new(), + }; + format!("failed to validate output component{output}") + })?; + + log::debug!("output component validated successfully"); + } + + if let Some(path) = self.output.output_path() { + println!("composed component `{}`", path.display()); + } + + Ok(()) + } + + fn create_config(&self) -> Result { + let mut config = if let Some(config) = &self.config { + Config::from_file(config)? + } else { + // Pretend a default configuration file is sitting next to the component + Config { + dir: self + .component + .parent() + .map(Path::to_path_buf) + .unwrap_or_default(), + ..Default::default() + } + }; + + // Use paths relative to the current directory; otherwise, the paths are interpreted as + // relative to the configuration file. + let cur_dir = std::env::current_dir().context("failed to get current directory")?; + config + .definitions + .extend(self.defs.iter().map(|p| cur_dir.join(p))); + config + .search_paths + .extend(self.paths.iter().map(|p| cur_dir.join(p))); + config.skip_validation |= self.skip_validation; + config.disallow_imports |= self.disallow_imports; + Ok(config) } } diff --git a/src/bin/wasm-tools/demangle.rs b/src/bin/wasm-tools/demangle.rs new file mode 100644 index 0000000000..262ec3122c --- /dev/null +++ b/src/bin/wasm-tools/demangle.rs @@ -0,0 +1,107 @@ +use anyhow::{bail, Result}; +use wasm_encoder::{IndirectNameMap, NameMap, NameSection, RawSection}; +use wasmparser::{Name, NameSectionReader, Parser, Payload::*}; + +/// Demangle Rust and C++ symbol names in the `name` section. +/// +/// This command will detect a `name` section in a wasm executable and demangle +/// any Rust and C++ symbol names found within it. Tooling for debugging a wasm +/// module which otherwise uses the `name` section but doesn't run a demangler +/// will use the demangled names since the `name` section will be replaced. +#[derive(clap::Parser)] +pub struct Opts { + #[clap(flatten)] + io: wasm_tools::InputOutput, + + /// Output the text format of WebAssembly instead of the binary format. + #[clap(short = 't', long)] + wat: bool, +} + +impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + + pub fn run(&self) -> Result<()> { + let input = self.io.parse_input_wasm()?; + let mut module = wasm_encoder::Module::new(); + + for payload in Parser::new(0).parse_all(&input) { + let payload = payload?; + match &payload { + CustomSection(c) if c.name() == "name" => { + match self.demangle(c.data(), c.data_offset()) { + Ok(new_section) => { + module.section(&new_section); + continue; + } + Err(e) => log::debug!("error parsing name section {e:?}"), + } + } + Version { encoding, .. } if *encoding == wasmparser::Encoding::Component => { + bail!("demangling components is not supported"); + } + _ => {} + } + if let Some((id, range)) = payload.as_section() { + module.section(&RawSection { + id, + data: &input[range], + }); + } + } + + self.io.output(wasm_tools::Output::Wasm { + bytes: module.as_slice(), + wat: self.wat, + })?; + Ok(()) + } + + fn demangle(&self, section: &[u8], offset: usize) -> Result { + let mut new_section = NameSection::new(); + for section in NameSectionReader::new(section, offset) { + match section? { + Name::Module { name, .. } => new_section.module(name), + Name::Memory(names) => new_section.memories(&self.name_map(names)?), + Name::Global(names) => new_section.globals(&self.name_map(names)?), + Name::Function(names) => new_section.functions(&self.name_map(names)?), + Name::Type(names) => new_section.types(&self.name_map(names)?), + Name::Table(names) => new_section.tables(&self.name_map(names)?), + Name::Element(names) => new_section.elements(&self.name_map(names)?), + Name::Data(names) => new_section.data(&self.name_map(names)?), + Name::Local(names) => new_section.locals(&self.indirect_name_map(names)?), + Name::Label(names) => new_section.labels(&self.indirect_name_map(names)?), + Name::Unknown { .. } => bail!("unknown name section"), + } + } + Ok(new_section) + } + + fn name_map(&self, names: wasmparser::NameMap<'_>) -> Result { + let mut ret = NameMap::new(); + for naming in names { + let naming = naming?; + let name = match rustc_demangle::try_demangle(naming.name) { + Ok(name) => name.to_string(), + Err(_) => match cpp_demangle::Symbol::new(naming.name) { + Ok(name) => name.to_string(), + Err(_) => naming.name.to_string(), + }, + }; + ret.append(naming.index, &name); + } + Ok(ret) + } + + fn indirect_name_map(&self, names: wasmparser::IndirectNameMap<'_>) -> Result { + let mut ret = IndirectNameMap::new(); + for naming in names { + let naming = naming?; + let map = self.name_map(naming.names)?; + ret.append(naming.index, &map); + } + Ok(ret) + } +} diff --git a/src/bin/wasm-tools/dump.rs b/src/bin/wasm-tools/dump.rs index 6d013d0ced..01175a752f 100644 --- a/src/bin/wasm-tools/dump.rs +++ b/src/bin/wasm-tools/dump.rs @@ -1,4 +1,8 @@ use anyhow::Result; +use std::fmt::Write as _; +use std::io::Write; +use termcolor::{Color, ColorSpec, WriteColor}; +use wasmparser::*; /// Debugging utility to dump information about a wasm binary. /// @@ -11,10 +15,711 @@ pub struct Opts { } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + pub fn run(&self) -> Result<()> { let input = self.io.parse_input_wasm()?; let output = self.io.output_writer()?; - wasmparser_dump::dump_wasm_into(&input, output)?; + let mut d = Dump::new(&input, output); + d.run()?; + Ok(()) + } +} + +struct Dump<'a> { + bytes: &'a [u8], + cur: usize, + state: String, + dst: Box, + nesting: u32, + offset_width: usize, +} + +#[derive(Default)] +struct Indices { + // Core module indexes + core_types: u32, + core_funcs: u32, + core_globals: u32, + core_tables: u32, + core_memories: u32, + core_tags: u32, + core_modules: u32, + core_instances: u32, + + // Component indexes + types: u32, + funcs: u32, + components: u32, + instances: u32, + values: u32, +} + +enum ComponentTypeKind { + Func, + Component, + Instance, + DefinedType, + Resource, +} + +const NBYTES: usize = 4; + +impl<'a> Dump<'a> { + fn new(bytes: &'a [u8], dst: impl WriteColor + 'a) -> Dump<'a> { + Dump { + bytes, + cur: 0, + nesting: 0, + state: String::new(), + dst: Box::new(dst) as _, + offset_width: format!("{:x}", bytes.len()).len() + 1, + } + } + + fn run(&mut self) -> Result<()> { + self.print_module()?; + assert_eq!(self.cur, self.bytes.len()); + Ok(()) + } + + fn print_module(&mut self) -> Result<()> { + let mut stack = Vec::new(); + let mut i = Indices::default(); + let mut component_types = Vec::new(); + self.nesting += 1; + + for item in Parser::new(0).parse_all(self.bytes) { + match item? { + Payload::Version { + num, + encoding, + range, + } => { + write!(self.state, "version {} ({:?})", num, encoding)?; + self.color_print(range.end)?; + } + Payload::TypeSection(s) => self.section(s, "type", |me, end, t| { + write!(me.state, "[type {}] {:?}", inc(&mut i.core_types), t)?; + me.print(end) + })?, + Payload::ImportSection(s) => self.section(s, "import", |me, end, imp| { + write!(me.state, "import ")?; + match imp.ty { + TypeRef::Func(_) => write!(me.state, "[func {}]", inc(&mut i.core_funcs))?, + TypeRef::Memory(_) => { + write!(me.state, "[memory {}]", inc(&mut i.core_memories))? + } + TypeRef::Tag(_) => write!(me.state, "[tag {}]", inc(&mut i.core_tags))?, + TypeRef::Table(_) => { + write!(me.state, "[table {}]", inc(&mut i.core_tables))? + } + TypeRef::Global(_) => { + write!(me.state, "[global {}]", inc(&mut i.core_globals))? + } + } + write!(me.state, " {:?}", imp)?; + me.print(end) + })?, + Payload::FunctionSection(s) => { + let mut cnt = i.core_funcs; + self.section(s, "func", |me, end, f| { + write!(me.state, "[func {}] type {:?}", inc(&mut cnt), f)?; + me.print(end) + })? + } + Payload::TableSection(s) => self.section(s, "table", |me, end, t| { + write!(me.state, "[table {}] {:?}", inc(&mut i.core_tables), t)?; + me.print(end) + })?, + Payload::MemorySection(s) => self.section(s, "memory", |me, end, m| { + write!(me.state, "[memory {}] {:?}", inc(&mut i.core_memories), m)?; + me.print(end) + })?, + Payload::TagSection(s) => self.section(s, "tag", |me, end, m| { + write!(me.state, "[tag {}] {:?}", inc(&mut i.core_tags), m)?; + me.print(end) + })?, + Payload::ExportSection(s) => self.section(s, "export", |me, end, e| { + write!(me.state, "export {:?}", e)?; + me.print(end) + })?, + Payload::GlobalSection(s) => self.section(s, "global", |me, _end, g| { + write!(me.state, "[global {}] {:?}", inc(&mut i.core_globals), g.ty)?; + me.print(g.init_expr.get_binary_reader().original_position())?; + me.print_ops(g.init_expr.get_operators_reader()) + })?, + Payload::StartSection { func, range } => { + write!(self.state, "start section")?; + self.print(range.start)?; + write!(self.state, "start function {}", func)?; + self.print(range.end)?; + } + Payload::DataCountSection { count, range } => { + write!(self.state, "data count section")?; + self.print(range.start)?; + write!(self.state, "data count {}", count)?; + self.print(range.end)?; + } + Payload::ElementSection(s) => self.section(s, "element", |me, _end, i| { + write!(me.state, "element")?; + let item_count = match &i.items { + ElementItems::Functions(reader) => reader.count(), + ElementItems::Expressions(_, reader) => reader.count(), + }; + match i.kind { + ElementKind::Passive => { + write!(me.state, " passive, {} items", item_count)?; + } + ElementKind::Active { + table_index, + offset_expr, + } => { + write!(me.state, " table[{:?}]", table_index)?; + me.print(offset_expr.get_binary_reader().original_position())?; + me.print_ops(offset_expr.get_operators_reader())?; + write!(me.state, "{} items", item_count)?; + } + ElementKind::Declared => { + write!(me.state, " declared {} items", item_count)?; + } + } + match i.items { + ElementItems::Functions(reader) => { + write!(me.state, " [indices]")?; + let mut iter = reader.into_iter(); + me.print(iter.original_position())?; + while let Some(item) = iter.next() { + write!(me.state, "item {:?}", item?)?; + me.print(iter.original_position())?; + } + } + ElementItems::Expressions(ty, reader) => { + write!(me.state, " [exprs {ty:?}]")?; + let mut iter = reader.into_iter(); + me.print(iter.original_position())?; + while let Some(item) = iter.next() { + write!(me.state, "item {:?}", item?)?; + me.print(iter.original_position())?; + } + } + } + Ok(()) + })?, + + Payload::DataSection(s) => self.section(s, "data", |me, end, i| { + match i.kind { + DataKind::Passive => { + write!(me.state, "data passive")?; + me.print(end - i.data.len())?; + } + DataKind::Active { + memory_index, + offset_expr, + } => { + write!(me.state, "data memory[{}]", memory_index)?; + me.print(offset_expr.get_binary_reader().original_position())?; + me.print_ops(offset_expr.get_operators_reader())?; + } + } + me.print_byte_header()?; + for _ in 0..NBYTES { + write!(me.dst, "---")?; + } + writeln!(me.dst, "-| ... {} bytes of data", i.data.len())?; + me.cur = end; + Ok(()) + })?, + + Payload::CodeSectionStart { count, range, size } => { + write!(self.state, "code section")?; + self.color_print(range.start)?; + write!(self.state, "{} count", count)?; + self.print(range.end - size as usize)?; + } + + Payload::CodeSectionEntry(body) => { + writeln!( + self.dst, + "============== func {} ====================", + inc(&mut i.core_funcs), + )?; + write!(self.state, "size of function")?; + self.print(body.get_binary_reader().original_position())?; + let mut locals = body.get_locals_reader()?; + write!(self.state, "{} local blocks", locals.get_count())?; + self.print(locals.original_position())?; + for _ in 0..locals.get_count() { + let (amt, ty) = locals.read()?; + write!(self.state, "{} locals of type {:?}", amt, ty)?; + self.print(locals.original_position())?; + } + self.print_ops(body.get_operators_reader()?)?; + } + + // Component sections + Payload::ModuleSection { range, .. } => { + write!( + self.state, + "[core module {}] inline size", + inc(&mut i.core_modules) + )?; + self.print(range.start)?; + self.nesting += 1; + stack.push(i); + i = Indices::default(); + } + + Payload::InstanceSection(s) => self.section(s, "core instance", |me, end, e| { + write!( + me.state, + "[core instance {}] {:?}", + inc(&mut i.core_instances), + e + )?; + me.print(end) + })?, + + Payload::CoreTypeSection(s) => self.section(s, "core type", |me, end, t| { + write!(me.state, "[core type {}] {:?}", inc(&mut i.core_types), t)?; + me.print(end) + })?, + + Payload::ComponentSection { range, .. } => { + write!( + self.state, + "[component {}] inline size", + inc(&mut i.components) + )?; + self.print(range.start)?; + self.nesting += 1; + stack.push(i); + i = Indices::default(); + } + + Payload::ComponentInstanceSection(s) => { + self.section(s, "component instance", |me, end, e| { + write!(me.state, "[instance {}] {:?}", inc(&mut i.instances), e)?; + me.print(end) + })? + } + + Payload::ComponentAliasSection(s) => { + self.section(s, "component alias", |me, end, a| { + let (kind, num) = match a { + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Module, + .. + } + | ComponentAlias::Outer { + kind: ComponentOuterAliasKind::CoreModule, + .. + } => ("module", inc(&mut i.core_modules)), + ComponentAlias::Outer { + kind: ComponentOuterAliasKind::CoreType, + .. + } => ("core type", inc(&mut i.core_types)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Func, + .. + } => ("func", inc(&mut i.funcs)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Value, + .. + } => ("value", inc(&mut i.values)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Type, + .. + } + | ComponentAlias::Outer { + kind: ComponentOuterAliasKind::Type, + .. + } => ("type", inc(&mut i.types)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Instance, + .. + } => ("instance", inc(&mut i.instances)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Component, + .. + } + | ComponentAlias::Outer { + kind: ComponentOuterAliasKind::Component, + .. + } => ("component", inc(&mut i.components)), + ComponentAlias::CoreInstanceExport { kind, .. } => match kind { + ExternalKind::Func => ("core func", inc(&mut i.core_funcs)), + ExternalKind::Table => ("core table", inc(&mut i.core_tables)), + ExternalKind::Memory => ("core memory", inc(&mut i.core_memories)), + ExternalKind::Global => ("core global", inc(&mut i.core_globals)), + ExternalKind::Tag => ("core tag", inc(&mut i.core_tags)), + }, + }; + + write!(me.state, "alias [{} {}] {:?}", kind, num, a)?; + me.print(end) + })? + } + + Payload::ComponentTypeSection(s) => { + self.section(s, "component type", |me, end, t| { + write!(me.state, "[type {}] {:?}", inc(&mut i.types), t)?; + component_types.push(match t { + ComponentType::Defined(_) => ComponentTypeKind::DefinedType, + ComponentType::Func(_) => ComponentTypeKind::Func, + ComponentType::Component(_) => ComponentTypeKind::Component, + ComponentType::Instance(_) => ComponentTypeKind::Instance, + ComponentType::Resource { .. } => ComponentTypeKind::Resource, + }); + me.print(end) + })? + } + + Payload::ComponentImportSection(s) => { + self.section(s, "component import", |me, end, item| { + let (desc, idx) = match item.ty { + ComponentTypeRef::Module(..) => ("module", inc(&mut i.core_modules)), + ComponentTypeRef::Func(..) => ("func", inc(&mut i.funcs)), + ComponentTypeRef::Value(..) => ("value", inc(&mut i.values)), + ComponentTypeRef::Type(..) => ("type", inc(&mut i.types)), + ComponentTypeRef::Instance(..) => ("instance", inc(&mut i.instances)), + ComponentTypeRef::Component(..) => { + ("component", inc(&mut i.components)) + } + }; + write!(me.state, "[{desc} {idx}] {item:?}")?; + me.print(end) + })? + } + + Payload::ComponentCanonicalSection(s) => { + self.section(s, "canonical function", |me, end, f| { + let (name, col) = match &f { + CanonicalFunction::Lift { .. } => ("func", &mut i.funcs), + CanonicalFunction::Lower { .. } + | CanonicalFunction::ResourceNew { .. } + | CanonicalFunction::ResourceDrop { .. } + | CanonicalFunction::ResourceRep { .. } => { + ("core func", &mut i.core_funcs) + } + }; + + write!(me.state, "[{} {}] {:?}", name, inc(col), f)?; + me.print(end) + })? + } + + Payload::ComponentExportSection(s) => { + self.section(s, "component export", |me, end, e| { + write!(me.state, "export {:?}", e)?; + me.print(end) + })? + } + + Payload::ComponentStartSection { start, range } => { + write!(self.state, "start section")?; + self.print(range.start)?; + write!(self.state, "{:?}", start)?; + self.print(range.end)?; + } + + Payload::CustomSection(c) => { + write!(self.state, "custom section")?; + self.color_print(c.range().start)?; + write!(self.state, "name: {:?}", c.name())?; + self.print(c.data_offset())?; + if c.name() == "name" { + let iter = NameSectionReader::new(c.data(), c.data_offset()); + self.print_custom_name_section(iter, |me, item, pos| { + me.print_core_name(item, pos) + })?; + } else if c.name() == "component-name" { + let iter = ComponentNameSectionReader::new(c.data(), c.data_offset()); + self.print_custom_name_section(iter, |me, item, pos| { + me.print_component_name(item, pos) + })?; + } else { + self.print_byte_header()?; + for _ in 0..NBYTES { + write!(self.dst, "---")?; + } + writeln!(self.dst, "-| ... {} bytes of data", c.data().len())?; + self.cur += c.data().len(); + } + } + Payload::UnknownSection { + id, + range, + contents, + } => { + write!(self.state, "unknown section: {}", id)?; + self.color_print(range.start)?; + self.print_byte_header()?; + for _ in 0..NBYTES { + write!(self.dst, "---")?; + } + writeln!(self.dst, "-| ... {} bytes of data", contents.len())?; + self.cur += contents.len(); + } + Payload::End(_) => { + self.nesting -= 1; + if self.nesting > 0 { + i = stack.pop().unwrap(); + } + } + } + } + + Ok(()) + } + + fn print_name_map(&mut self, thing: &str, n: NameMap<'_>) -> Result<()> { + self.section(n, &format!("{thing} name"), |me, end, naming| { + write!(me.state, "{:?}", naming)?; + me.print(end) + }) + } + + fn print_indirect_name_map( + &mut self, + thing_a: &str, + thing_b: &str, + n: IndirectNameMap<'_>, + ) -> Result<()> { + self.section(n, thing_b, |me, _end, naming| { + write!(me.state, "{} {} ", thing_a, naming.index)?; + me.print_name_map(thing_b, naming.names) + }) + } + + fn print_custom_name_section<'b, T>( + &mut self, + mut section: Subsections<'b, T>, + print_item: impl Fn(&mut Self, T, usize) -> Result<()>, + ) -> Result<()> + where + T: wasmparser::Subsection<'b>, + { + while let Some(item) = section.next() { + let pos = section.original_position(); + + let err = match item { + Ok(item) => match print_item(self, item, pos) { + Ok(()) => continue, + Err(e) => e.downcast()?, + }, + Err(e) => e, + }; + if self.cur != pos { + if self.state.is_empty() { + write!(self.state, "???")?; + } + self.print(pos)?; + } + self.print_byte_header()?; + for _ in 0..NBYTES { + write!(self.dst, "---")?; + } + let remaining = section.range().end - pos; + writeln!( + self.dst, + "-| ... failed to decode {remaining} more bytes: {err}" + )?; + self.cur += remaining; + break; + } + Ok(()) + } + + fn print_core_name(&mut self, name: Name<'_>, end: usize) -> Result<()> { + match name { + Name::Module { name, name_range } => { + write!(self.state, "module name")?; + self.print(name_range.start)?; + write!(self.state, "{:?}", name)?; + self.print(name_range.end)?; + } + Name::Function(n) => self.print_name_map("function", n)?, + Name::Local(n) => self.print_indirect_name_map("function", "local", n)?, + Name::Label(n) => self.print_indirect_name_map("function", "label", n)?, + Name::Type(n) => self.print_name_map("type", n)?, + Name::Table(n) => self.print_name_map("table", n)?, + Name::Memory(n) => self.print_name_map("memory", n)?, + Name::Global(n) => self.print_name_map("global", n)?, + Name::Element(n) => self.print_name_map("element", n)?, + Name::Data(n) => self.print_name_map("data", n)?, + Name::Unknown { ty, range, .. } => { + write!(self.state, "unknown names: {}", ty)?; + self.print(range.start)?; + self.print(end)?; + } + } Ok(()) } + + fn print_component_name(&mut self, name: ComponentName<'_>, end: usize) -> Result<()> { + match name { + ComponentName::Component { name, name_range } => { + write!(self.state, "component name")?; + self.print(name_range.start)?; + write!(self.state, "{:?}", name)?; + self.print(name_range.end)?; + } + ComponentName::CoreFuncs(n) => self.print_name_map("core func", n)?, + ComponentName::CoreTables(n) => self.print_name_map("core table", n)?, + ComponentName::CoreGlobals(n) => self.print_name_map("core global", n)?, + ComponentName::CoreMemories(n) => self.print_name_map("core memory", n)?, + ComponentName::CoreInstances(n) => self.print_name_map("core instance", n)?, + ComponentName::CoreModules(n) => self.print_name_map("core module", n)?, + ComponentName::CoreTypes(n) => self.print_name_map("core type", n)?, + ComponentName::Types(n) => self.print_name_map("type", n)?, + ComponentName::Instances(n) => self.print_name_map("instance", n)?, + ComponentName::Components(n) => self.print_name_map("component", n)?, + ComponentName::Funcs(n) => self.print_name_map("func", n)?, + ComponentName::Values(n) => self.print_name_map("value", n)?, + ComponentName::Unknown { ty, range, .. } => { + write!(self.state, "unknown names: {}", ty)?; + self.print(range.start)?; + self.print(end)?; + } + } + Ok(()) + } + + fn section<'b, T>( + &mut self, + iter: SectionLimited<'b, T>, + name: &str, + print: impl FnMut(&mut Self, usize, T) -> Result<()>, + ) -> Result<()> + where + T: FromReader<'b>, + { + write!(self.state, "{} section", name)?; + self.color_print(iter.range().start)?; + self.print_iter(iter, print) + } + + fn print_iter<'b, T>( + &mut self, + iter: SectionLimited<'b, T>, + mut print: impl FnMut(&mut Self, usize, T) -> Result<()>, + ) -> Result<()> + where + T: FromReader<'b>, + { + write!(self.state, "{} count", iter.count())?; + let mut iter = iter.into_iter(); + self.print(iter.original_position())?; + while let Some(item) = iter.next() { + print(self, iter.original_position(), item?)?; + } + Ok(()) + } + + fn print_ops(&mut self, mut i: OperatorsReader) -> Result<()> { + while !i.eof() { + match i.visit_operator(self) { + Ok(()) => {} + Err(_) => write!(self.state, "??")?, + } + self.print(i.original_position())?; + } + Ok(()) + } + + fn color_print(&mut self, end: usize) -> Result<()> { + self.print_(end, true) + } + + fn print(&mut self, end: usize) -> Result<()> { + self.print_(end, false) + } + + fn print_(&mut self, end: usize, color: bool) -> Result<()> { + assert!( + self.cur < end, + "{:#x} >= {:#x}\ntrying to print: {}", + self.cur, + end, + self.state, + ); + let bytes = &self.bytes[self.cur..end]; + self.print_byte_header()?; + for (i, chunk) in bytes.chunks(NBYTES).enumerate() { + if i > 0 { + for _ in 0..self.nesting - 1 { + write!(self.dst, " ")?; + } + for _ in 0..self.offset_width { + write!(self.dst, " ")?; + } + write!(self.dst, " |")?; + } + for j in 0..NBYTES { + match chunk.get(j) { + Some(b) => write!(self.dst, " {:02x}", b)?, + None => write!(self.dst, " ")?, + } + } + if i == 0 { + write!(self.dst, " | ")?; + if color { + self.dst + .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; + } + write!(self.dst, "{}", &self.state)?; + self.dst.set_color(ColorSpec::new().set_fg(None))?; + self.state.truncate(0); + } + writeln!(self.dst)?; + } + self.cur = end; + Ok(()) + } + + fn print_byte_header(&mut self) -> Result<()> { + for _ in 0..self.nesting - 1 { + write!(self.dst, " ")?; + } + write!( + self.dst, + "{:#width$x} |", + self.cur, + width = self.offset_width + 2 + )?; + Ok(()) + } +} + +fn inc(spot: &mut u32) -> u32 { + let ret = *spot; + *spot += 1; + ret +} + +macro_rules! define_visit_operator { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + $( + fn $visit(&mut self $($(,$arg: $argty)*)?) { + write!( + self.state, + concat!( + "{}" + $( $(, " ", stringify!($arg), ":{:?}")* )? + ), + stringify!($visit).strip_prefix("visit_").unwrap(), + $( $($arg,)* )? + ).unwrap(); + } + )* + } +} + +impl<'a> VisitOperator<'a> for Dump<'_> { + type Output = (); + + wasmparser::for_each_operator!(define_visit_operator); } diff --git a/src/bin/wasm-tools/main.rs b/src/bin/wasm-tools/main.rs index 591067d920..decb93ac0b 100644 --- a/src/bin/wasm-tools/main.rs +++ b/src/bin/wasm-tools/main.rs @@ -1,29 +1,29 @@ use anyhow::Result; use clap::Parser; -use std::io; +use std::io::{self, IsTerminal, Write}; use std::process::ExitCode; -use wasm_tools::Verbosity; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; macro_rules! subcommands { - ($(($name:ident, $string:tt))*) => { + ($( + $(#[$attr:meta])* + ($name:ident, $string:tt $($cfg:tt)*) + )*) => { $( #[cfg(feature = $string)] + $($cfg)* mod $name; )* #[derive(Parser)] - #[clap(version)] + #[clap(version = version())] #[allow(non_camel_case_types)] enum WasmTools { $( #[cfg(feature = $string)] - $name { - #[clap(flatten)] - opts: $name::Opts, - - #[clap(flatten)] - verbosity: Verbosity, - }, + $($cfg)* + $(#[$attr])* + $name($name::Opts), )* } @@ -32,10 +32,18 @@ macro_rules! subcommands { match self { $( #[cfg(feature = $string)] - Self::$name { opts, verbosity } => { - verbosity.init_logger(); - opts.run() - } + $($cfg)* + Self::$name(opts) => opts.run(), + )* + } + } + + fn general_opts(&self) -> &wasm_tools::GeneralOpts { + match *self { + $( + #[cfg(feature = $string)] + $($cfg)* + Self::$name(ref opts) => opts.general_opts(), )* } } @@ -48,16 +56,29 @@ subcommands! { (validate, "validate") (print, "print") (smith, "smith") - (shrink, "shrink") + // The shrink subcommand relies on executing new processes to test a + // predicate which isn't supported on wasm, so always omit this command on + // wasm. + (shrink, "shrink" #[cfg(not(target_family = "wasm"))]) (mutate, "mutate") (dump, "dump") (objdump, "objdump") (strip, "strip") (compose, "compose") + (demangle, "demangle") + #[command(subcommand)] + (component, "component") + #[command(subcommand)] + (metadata, "metadata") + (wit_smith, "wit-smith") + (addr2line, "addr2line") } fn main() -> ExitCode { - let err = match ::parse().run() { + let args = ::parse(); + args.general_opts().init_logger(); + let color = args.general_opts().color; + let err = match args.run() { Ok(()) => return ExitCode::SUCCESS, Err(e) => e, }; @@ -71,6 +92,54 @@ fn main() -> ExitCode { _ => {} } } - eprintln!("Error: {:?}", err); + + // ignore errors here since if we fail to print an error it's not like we + // can print it again. + let _ = print_error(color, err); ExitCode::FAILURE } + +fn print_error(color: ColorChoice, err: anyhow::Error) -> Result<()> { + let color = if color == ColorChoice::Auto && !io::stderr().is_terminal() { + ColorChoice::Never + } else { + color + }; + let mut stderr = StandardStream::stderr(color); + stderr.set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true))?; + write!(stderr, "error")?; + stderr.set_color(ColorSpec::new().set_fg(None).set_bold(true))?; + write!(stderr, ": ")?; + + let msg = err.to_string(); + for (i, line) in msg.lines().enumerate() { + writeln!(stderr, "{line}")?; + if i == 0 { + stderr.set_color(ColorSpec::new().set_reset(true))?; + } + } + + if err.chain().len() == 1 { + return Ok(()); + } + writeln!(stderr, "\nCaused by:")?; + for (i, err) in err.chain().skip(1).enumerate() { + writeln!( + stderr, + "{i:>5}: {}", + err.to_string().replace("\n", "\n ") + )?; + } + return Ok(()); +} + +/// If CARGO_VERSION_INFO is set, use it, otherwise use CARGO_PKG_VERSION. +fn version() -> &'static str { + option_env!("CARGO_VERSION_INFO").unwrap_or(env!("CARGO_PKG_VERSION")) +} + +#[test] +fn verify_cli() { + use clap::CommandFactory; + WasmTools::command().debug_assert() +} diff --git a/src/bin/wasm-tools/metadata.rs b/src/bin/wasm-tools/metadata.rs new file mode 100644 index 0000000000..83142db550 --- /dev/null +++ b/src/bin/wasm-tools/metadata.rs @@ -0,0 +1,87 @@ +use anyhow::Result; +use std::io::Write; + +/// Manipulate metadata (module name, producers) to a WebAssembly file. +#[derive(clap::Parser)] +pub enum Opts { + Show(ShowOpts), + Add(AddOpts), +} + +impl Opts { + pub fn run(&self) -> Result<()> { + match self { + Opts::Show(opts) => opts.run(), + Opts::Add(opts) => opts.run(), + } + } + + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + match self { + Opts::Show(opts) => opts.general_opts(), + Opts::Add(opts) => opts.general_opts(), + } + } +} + +/// Read metadata (module name, producers) from a WebAssembly file. +#[derive(clap::Parser)] +pub struct ShowOpts { + #[clap(flatten)] + io: wasm_tools::InputOutput, + + /// Output in JSON encoding + #[clap(long)] + json: bool, +} + +impl ShowOpts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + + pub fn run(&self) -> Result<()> { + let input = self.io.parse_input_wasm()?; + let mut output = self.io.output_writer()?; + + let metadata = wasm_metadata::Metadata::from_binary(&input)?; + if self.json { + write!(output, "{}", serde_json::to_string(&metadata)?)?; + } else { + write!(output, "{metadata}")?; + } + Ok(()) + } +} + +/// Add metadata (module name, producers) to a WebAssembly file +#[derive(clap::Parser)] +pub struct AddOpts { + #[clap(flatten)] + io: wasm_tools::InputOutput, + + #[clap(flatten)] + add_metadata: wasm_metadata::AddMetadata, + + /// Output the text format of WebAssembly instead of the binary format + #[clap(short = 't', long)] + wat: bool, +} + +impl AddOpts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + + pub fn run(&self) -> Result<()> { + let input = self.io.parse_input_wasm()?; + + let output = self.add_metadata.to_wasm(&input)?; + + self.io.output(wasm_tools::Output::Wasm { + bytes: output.as_slice(), + wat: self.wat, + })?; + Ok(()) + } +} diff --git a/src/bin/wasm-tools/mutate.rs b/src/bin/wasm-tools/mutate.rs index 2dd0f60eef..acb5a7e413 100644 --- a/src/bin/wasm-tools/mutate.rs +++ b/src/bin/wasm-tools/mutate.rs @@ -49,6 +49,10 @@ pub struct Opts { } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + pub fn run(mut self) -> Result<()> { let input_wasm = self.io.parse_input_wasm()?; diff --git a/src/bin/wasm-tools/objdump.rs b/src/bin/wasm-tools/objdump.rs index 2f2079b4bb..248fc18396 100644 --- a/src/bin/wasm-tools/objdump.rs +++ b/src/bin/wasm-tools/objdump.rs @@ -1,7 +1,8 @@ use anyhow::Result; use std::io::Write; use std::ops::Range; -use wasmparser::{Encoding, Parser, Payload::*, SectionReader}; +use termcolor::WriteColor; +use wasmparser::{Encoding, Parser, Payload::*}; /// Dumps information about sections in a WebAssembly file. /// @@ -14,6 +15,10 @@ pub struct Opts { } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + pub fn run(&self) -> Result<()> { let input = self.io.parse_input_wasm()?; @@ -59,10 +64,12 @@ impl Opts { ComponentAliasSection(s) => printer.section(s, "component alias")?, ComponentTypeSection(s) => printer.section(s, "component types")?, ComponentCanonicalSection(s) => printer.section(s, "canonical functions")?, - ComponentStartSection(s) => printer.section_raw(s.range(), 1, "component start")?, + ComponentStartSection { range, .. } => { + printer.section_raw(range.clone(), 1, "component start")? + } ComponentImportSection(s) => printer.section(s, "component imports")?, ComponentExportSection(s) => printer.section(s, "component exports")?, - + CustomSection(c) => printer.section_raw( c.data_offset()..c.data_offset() + c.data().len(), 1, @@ -88,7 +95,7 @@ struct IndexSpace { struct Printer { indices: Vec, - output: Box, + output: Box, } impl Printer { @@ -152,11 +159,15 @@ impl Printer { Ok(()) } - fn section(&mut self, section: T, name: &str) -> Result<()> + fn section<'a, T>( + &mut self, + section: wasmparser::SectionLimited<'a, T>, + name: &str, + ) -> Result<()> where - T: wasmparser::SectionWithLimitedItems + wasmparser::SectionReader, + T: wasmparser::FromReader<'a>, { - self.section_raw(section.range(), section.get_count(), name) + self.section_raw(section.range(), section.count(), name) } fn section_raw(&mut self, range: Range, count: u32, name: &str) -> Result<()> { diff --git a/src/bin/wasm-tools/parse.rs b/src/bin/wasm-tools/parse.rs index 4f83358a50..3274bfbeca 100644 --- a/src/bin/wasm-tools/parse.rs +++ b/src/bin/wasm-tools/parse.rs @@ -16,6 +16,10 @@ pub struct Opts { } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + pub fn run(&self) -> Result<()> { let binary = self.io.parse_input_wasm()?; self.io.output(wasm_tools::Output::Wasm { diff --git a/src/bin/wasm-tools/print.rs b/src/bin/wasm-tools/print.rs index 147ca89dbe..a7eae6f572 100644 --- a/src/bin/wasm-tools/print.rs +++ b/src/bin/wasm-tools/print.rs @@ -11,13 +11,24 @@ pub struct Opts { /// as comments for debugging. #[clap(short, long)] print_offsets: bool, + + /// Indicates that the "skeleton" of a module should be printed where items + /// such as function bodies, data segments, and element segments are + /// replaced with "..." instead of printing their actual contents. + #[clap(long)] + skeleton: bool, } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + pub fn run(&self) -> Result<()> { let wasm = self.io.parse_input_wasm()?; let mut printer = wasmprinter::Printer::new(); printer.print_offsets(self.print_offsets); + printer.print_skeleton(self.skeleton); let wat = printer.print(&wasm)?; self.io.output(wasm_tools::Output::Wat(&wat))?; Ok(()) diff --git a/src/bin/wasm-tools/shrink.rs b/src/bin/wasm-tools/shrink.rs index 553a074eb9..c70f550d53 100644 --- a/src/bin/wasm-tools/shrink.rs +++ b/src/bin/wasm-tools/shrink.rs @@ -25,24 +25,25 @@ use wasm_shrink::{IsInteresting, WasmShrink}; /// $ wasm-shrink compile.sh crasher.wasm -o shrunken.wasm #[derive(Parser)] pub struct Opts { - /// The output file path to write the shrunken Wasm file to. - /// - /// By default, a file path based on the input will be generated. - #[clap(short, long)] - output: Option, - #[clap(flatten)] shrink: WasmShrink, /// The interestingness predicate script. predicate: PathBuf, - /// The input Wasm. - input: PathBuf, + #[clap(flatten)] + io: wasm_tools::InputOutput, } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + pub fn run(self) -> Result<()> { + let input = self.io.parse_input_wasm()?; + let initial_size = input.len(); + // Prerequisites for the predicate. anyhow::ensure!( self.predicate.is_file(), @@ -55,14 +56,14 @@ impl Opts { self.predicate.display() ); - let input = wat::parse_file(&self.input) - .with_context(|| format!("Failed to read input Wasm file: {}", self.input.display()))?; - let initial_size = input.len(); - let output = self - .output - .clone() - .unwrap_or_else(|| self.input.with_extension("shrunken.wasm")); + .io + .output_path() + .map(|p| p.to_path_buf()) + .unwrap_or_else(|| match self.io.input_path() { + Some(path) => path.with_extension("shrunken.wasm"), + None => "shrunken.wasm".into(), + }); log::info!("Will write shrunken Wasm file to: {}", output.display()); let predicate = make_predicate(&self.predicate); diff --git a/src/bin/wasm-tools/smith.rs b/src/bin/wasm-tools/smith.rs index 7a1af22020..700383c039 100644 --- a/src/bin/wasm-tools/smith.rs +++ b/src/bin/wasm-tools/smith.rs @@ -38,7 +38,6 @@ pub struct Opts { /// The arbitrary input seed. /// /// `stdin` is used if this argument is not supplied. - #[clap(parse(from_os_str))] input: Option, #[clap(flatten)] @@ -70,14 +69,17 @@ pub struct Opts { fuel: Option, /// JSON configuration file with settings to control the wasm output. - #[clap(short = 'c', long = "config", parse(from_os_str))] + #[clap(short = 'c', long = "config")] config: Option, #[clap(flatten)] module_config: Config, + + #[clap(flatten)] + general: wasm_tools::GeneralOpts, } -#[derive(Default, Debug, Parser, Clone, serde::Deserialize)] +#[derive(Default, Debug, Parser, Clone, serde_derive::Deserialize)] #[serde(rename_all = "kebab-case")] struct Config { #[clap(long = "min-types")] @@ -144,6 +146,9 @@ struct Config { #[clap(long = "reference-types")] #[serde(rename = "reference-types")] reference_types_enabled: Option, + #[clap(long = "tail-call")] + #[serde(rename = "tail-call")] + tail_call_enabled: Option, #[clap(long = "simd")] #[serde(rename = "simd")] simd_enabled: Option, @@ -190,6 +195,10 @@ struct Config { } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + &self.general + } + pub fn run(&self) -> Result<()> { let seed = match &self.input { Some(f) => { @@ -294,6 +303,7 @@ impl wasm_smith::Config for CliAndJsonConfig { (min_uleb_size, u8, 1), (bulk_memory_enabled, bool, true), (reference_types_enabled, bool, true), + (tail_call_enabled, bool, true), (simd_enabled, bool, true), (relaxed_simd_enabled, bool, false), (exceptions_enabled, bool, false), diff --git a/src/bin/wasm-tools/strip.rs b/src/bin/wasm-tools/strip.rs index f9a9e3d704..5b66afa235 100644 --- a/src/bin/wasm-tools/strip.rs +++ b/src/bin/wasm-tools/strip.rs @@ -1,7 +1,7 @@ -use anyhow::{bail, Result}; -use std::ops::Range; -use wasm_encoder::{RawSection, SectionId}; -use wasmparser::{Encoding, Parser, Payload::*, SectionReader}; +use anyhow::Result; +use std::mem; +use wasm_encoder::{ComponentSectionId, Encode, RawSection, Section}; +use wasmparser::{Parser, Payload::*}; /// Removes custom sections from an input WebAssembly file. /// @@ -13,91 +13,98 @@ pub struct Opts { #[clap(flatten)] io: wasm_tools::InputOutput, - /// Strip all custom sections, including the `name` section + /// Remove all custom sections, regardless of name. #[clap(long, short)] all: bool, + /// Remove custom sections matching the specified regex. + #[clap(long, short, value_name = "REGEX")] + delete: Vec, + /// Output the text format of WebAssembly instead of the binary format. #[clap(short = 't', long)] wat: bool, } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + pub fn run(&self) -> Result<()> { let input = self.io.parse_input_wasm()?; + let to_delete = regex::RegexSet::new(self.delete.iter())?; - let mut module = wasm_encoder::Module::new(); + let strip_custom_section = |name: &str| { + // If explicitly specified, strip everything. + if self.all { + return true; + } - for payload in Parser::new(0).parse_all(&input) { - let payload = payload?; - let mut section = |id: SectionId, range: Range| { - module.section(&RawSection { - id: id as u8, - data: &input[range], - }); - }; - match payload { - Version { - encoding: Encoding::Module, - .. - } => {} - Version { - encoding: Encoding::Component, - .. - } => { - bail!("components are not supported yet with the `strip` command"); - } + // If any section was called out by name only delete those sections. + if !to_delete.is_empty() { + return to_delete.is_match(name); + } - TypeSection(s) => section(SectionId::Type, s.range()), - ImportSection(s) => section(SectionId::Import, s.range()), - FunctionSection(s) => section(SectionId::Function, s.range()), - TableSection(s) => section(SectionId::Table, s.range()), - MemorySection(s) => section(SectionId::Memory, s.range()), - TagSection(s) => section(SectionId::Tag, s.range()), - GlobalSection(s) => section(SectionId::Global, s.range()), - ExportSection(s) => section(SectionId::Export, s.range()), - ElementSection(s) => section(SectionId::Element, s.range()), - DataSection(s) => section(SectionId::Data, s.range()), - StartSection { range, .. } => section(SectionId::Start, range), - DataCountSection { range, .. } => section(SectionId::DataCount, range), - CodeSectionStart { range, .. } => section(SectionId::Code, range), - CodeSectionEntry(_) => {} + // Finally default strip everything but the `name` section. + name != "name" + }; - ModuleSection { .. } - | InstanceSection(_) - | CoreTypeSection(_) - | ComponentSection { .. } - | ComponentInstanceSection(_) - | ComponentAliasSection(_) - | ComponentTypeSection(_) - | ComponentCanonicalSection(_) - | ComponentStartSection(_) - | ComponentImportSection(_) - | ComponentExportSection(_) => unimplemented!("component model"), + let mut output = Vec::new(); + let mut stack = Vec::new(); - CustomSection(c) if c.name() == "name" && !self.all => { - module.section(&RawSection { - id: SectionId::Custom as u8, - data: &input[c.range()], + for payload in Parser::new(0).parse_all(&input) { + let payload = payload?; + + // Track nesting depth, so that we don't mess with inner producer sections: + match payload { + Version { encoding, .. } => { + output.extend_from_slice(match encoding { + wasmparser::Encoding::Component => &wasm_encoder::Component::HEADER, + wasmparser::Encoding::Module => &wasm_encoder::Module::HEADER, }); } + ModuleSection { .. } | ComponentSection { .. } => { + stack.push(mem::take(&mut output)); + continue; + } + End { .. } => { + let mut parent = match stack.pop() { + Some(c) => c, + None => break, + }; + if output.starts_with(&wasm_encoder::Component::HEADER) { + parent.push(ComponentSectionId::Component as u8); + output.encode(&mut parent); + } else { + parent.push(ComponentSectionId::CoreModule as u8); + output.encode(&mut parent); + } + output = parent; + } + _ => {} + } - CustomSection(_) => {} + match &payload { + CustomSection(c) => { + if strip_custom_section(c.name()) { + continue; + } + } - UnknownSection { + _ => {} + } + if let Some((id, range)) = payload.as_section() { + RawSection { id, - contents, - range: _, - } => { - module.section(&RawSection { id, data: contents }); + data: &input[range], } - - End(_) => {} + .append_to(&mut output); } } self.io.output(wasm_tools::Output::Wasm { - bytes: module.as_slice(), + bytes: &output, wat: self.wat, })?; Ok(()) diff --git a/src/bin/wasm-tools/validate.rs b/src/bin/wasm-tools/validate.rs index 30f9a33273..999f8da51d 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -17,6 +17,9 @@ use wasmparser::{FuncValidatorAllocations, Parser, ValidPayload, Validator, Wasm /// # Validate `foo.wasm` with the default Wasm feature proposals. /// $ wasm-tools validate foo.wasm /// +/// # Validate `foo.wasm` with more verbose output +/// $ wasm-tools validate -vv foo.wasm +/// /// # Validate `fancy.wasm` with all Wasm feature proposals enabled. /// $ wasm-tools validate --features all fancy.wasm /// @@ -30,7 +33,10 @@ pub struct Opts { /// The placeholder "all" can be used to enable all wasm features. If a "-" /// character is present in front of a feature it will disable that feature. /// For example "all,-simd" would enable everything but simd. - #[clap(long, short = 'f', parse(try_from_str = parse_features))] + /// + /// Available feature options can be found in the wasmparser crate: + /// https://github.com/bytecodealliance/wasm-tools/blob/main/crates/wasmparser/src/validator.rs + #[clap(long, short = 'f', value_parser = parse_features)] features: Option, #[clap(flatten)] @@ -38,6 +44,10 @@ pub struct Opts { } impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + self.io.general_opts() + } + pub fn run(&self) -> Result<()> { // Note that here we're copying the contents of // `Validator::validate_all`, but the end is followed up with a parallel @@ -89,23 +99,26 @@ fn parse_features(arg: &str) -> Result { const FEATURES: &[(&str, fn(&mut WasmFeatures) -> &mut bool)] = &[ ("reference-types", |f| &mut f.reference_types), + ("function-references", |f| &mut f.function_references), ("simd", |f| &mut f.simd), ("threads", |f| &mut f.threads), ("bulk-memory", |f| &mut f.bulk_memory), ("multi-value", |f| &mut f.multi_value), ("tail-call", |f| &mut f.tail_call), ("component-model", |f| &mut f.component_model), + ("component-model-values", |f| &mut f.component_model_values), ("multi-memory", |f| &mut f.multi_memory), ("exception-handling", |f| &mut f.exceptions), ("memory64", |f| &mut f.memory64), ("extended-const", |f| &mut f.extended_const), - ("deterministic", |f| &mut f.deterministic_only), + ("floats", |f| &mut f.floats), ("saturating-float-to-int", |f| { &mut f.saturating_float_to_int }), ("sign-extension", |f| &mut f.sign_extension), ("mutable-global", |f| &mut f.mutable_global), ("relaxed-simd", |f| &mut f.relaxed_simd), + ("gc", |f| &mut f.gc), ]; for part in arg.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()) { @@ -127,10 +140,17 @@ fn parse_features(arg: &str) -> Result { } name => { - let (_, accessor) = FEATURES - .iter() - .find(|(n, _)| *n == name) - .ok_or_else(|| anyhow!("unknown feature `{}`", name))?; + let (_, accessor) = FEATURES.iter().find(|(n, _)| *n == name).ok_or_else(|| { + anyhow!( + "unknown feature `{}`\nValid features: {}", + name, + FEATURES + .iter() + .map(|(name, _)| *name) + .collect::>() + .join(", "), + ) + })?; *accessor(&mut ret) = enable; } } diff --git a/src/bin/wasm-tools/wit_smith.rs b/src/bin/wasm-tools/wit_smith.rs new file mode 100644 index 0000000000..19716e6c64 --- /dev/null +++ b/src/bin/wasm-tools/wit_smith.rs @@ -0,0 +1,81 @@ +use anyhow::{Context, Result}; +use clap::Parser; +use std::io::{stdin, Read}; +use std::path::PathBuf; +use wit_smith::Config; + +/// A WIT test case generator. +/// +/// Given an arbitrary input seed, `wit-smith` generates a valid WIT package set +/// encoded as a WebAssembly component. The input seed is interpreted as a +/// series of predetermined choices through a decision tree. Given the same +/// input seed, `wit-smith` will always generate the same output WebAssembly +/// component; it is deterministic. This tool is suitable for taking +/// fuzz-generated input to generate a wide array of WIT documents. +/// +/// ## Example +/// +/// Generate a WIT document from 100 bytes of random data: +/// +/// $ head -c 100 /dev/urandom | wasm-tools wit-smith -t +#[derive(Parser)] +pub struct Opts { + /// The arbitrary input seed. + /// + /// `stdin` is used if this argument is not supplied. + input: Option, + + #[clap(flatten)] + output: wasm_tools::OutputArg, + + /// Output the text format of WebAssembly instead of the binary format. + #[clap(short = 't', long)] + wat: bool, + + #[clap(flatten)] + config: Config, + + /// Indicates that "arbitrary configuration" should be used meaning that the + /// input seed is first used to generate the configuration and then + /// afterwards the rest of the seed is used to generate the document. + #[clap(long)] + arbitrary_config: bool, + + #[clap(flatten)] + general: wasm_tools::GeneralOpts, +} + +impl Opts { + pub fn general_opts(&self) -> &wasm_tools::GeneralOpts { + &self.general + } + + pub fn run(&self) -> Result<()> { + let seed = match &self.input { + Some(f) => { + std::fs::read(f).with_context(|| format!("failed to read '{}'", f.display()))? + } + None => { + let mut seed = Vec::new(); + stdin() + .read_to_end(&mut seed) + .context("failed to read ")?; + seed + } + }; + + let mut u = arbitrary::Unstructured::new(&seed); + let config = if self.arbitrary_config { + u.arbitrary()? + } else { + self.config.clone() + }; + let wasm_bytes = wit_smith::smith(&config, &mut u)?; + + self.output.output(wasm_tools::Output::Wasm { + bytes: &wasm_bytes, + wat: self.wat, + })?; + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index d691569ecc..0a558d28f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,24 +2,30 @@ use anyhow::{bail, Context, Result}; use std::fs::File; +use std::io::IsTerminal; use std::io::{BufWriter, Read, Write}; use std::path::{Path, PathBuf}; +use termcolor::{Ansi, ColorChoice, NoColor, StandardStream, WriteColor}; -/// Implements the verbosity flag for the CLI commands. #[derive(clap::Parser)] -pub struct Verbosity { - /// Use verbose output (-vv very verbose output). - #[clap(long = "verbose", short = 'v', parse(from_occurrences))] - verbose: usize, +pub struct GeneralOpts { + /// Use verbose output (-v info, -vv debug, -vvv trace). + #[clap(long = "verbose", short = 'v', action = clap::ArgAction::Count)] + verbose: u8, + + /// Use colors in output. + #[clap(long = "color", default_value = "auto")] + pub color: ColorChoice, } -impl Verbosity { +impl GeneralOpts { /// Initializes the logger based on the verbosity level. pub fn init_logger(&self) { let default = match self.verbose { 0 => "warn", 1 => "info", - _ => "debug", + 2 => "debug", + _ => "trace", }; env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(default)) @@ -36,15 +42,44 @@ impl Verbosity { // and then the methods are used to read the arguments, #[derive(clap::Parser)] pub struct InputOutput { + #[clap(flatten)] + input: InputArg, + + #[clap(flatten)] + output: OutputArg, + + #[clap(flatten)] + general: GeneralOpts, +} + +#[derive(clap::Parser)] +pub struct InputArg { /// Input file to process. /// /// If not provided or if this is `-` then stdin is read entirely and /// processed. Note that for most subcommands this input can either be a /// binary `*.wasm` file or a textual format `*.wat` file. input: Option, +} - #[clap(flatten)] - output: OutputArg, +impl InputArg { + pub fn parse_wasm(&self) -> Result> { + if let Some(path) = &self.input { + if path != Path::new("-") { + let bytes = wat::parse_file(path)?; + return Ok(bytes); + } + } + let mut stdin = Vec::new(); + std::io::stdin() + .read_to_end(&mut stdin) + .context("failed to read ")?; + let bytes = wat::parse_bytes(&stdin).map_err(|mut e| { + e.set_path(""); + e + })?; + Ok(bytes.into_owned()) + } } #[derive(clap::Parser)] @@ -59,33 +94,32 @@ pub struct OutputArg { pub enum Output<'a> { Wat(&'a str), Wasm { bytes: &'a [u8], wat: bool }, + Json(&'a str), } impl InputOutput { pub fn parse_input_wasm(&self) -> Result> { - if let Some(path) = &self.input { - if path != Path::new("-") { - let bytes = wat::parse_file(path)?; - return Ok(bytes); - } - } - let mut stdin = Vec::new(); - std::io::stdin() - .read_to_end(&mut stdin) - .context("failed to read ")?; - let bytes = wat::parse_bytes(&stdin).map_err(|mut e| { - e.set_path(""); - e - })?; - Ok(bytes.into_owned()) + self.input.parse_wasm() } pub fn output(&self, bytes: Output<'_>) -> Result<()> { self.output.output(bytes) } - pub fn output_writer(&self) -> Result> { - self.output.output_writer() + pub fn output_writer(&self) -> Result> { + self.output.output_writer(self.general.color) + } + + pub fn output_path(&self) -> Option<&Path> { + self.output.output.as_deref() + } + + pub fn input_path(&self) -> Option<&Path> { + self.input.input.as_deref() + } + + pub fn general_opts(&self) -> &GeneralOpts { + &self.general } } @@ -103,16 +137,18 @@ impl OutputArg { .context(format!("failed to write `{}`", path.display()))?; } None => { - if atty::is(atty::Stream::Stdout) { + let mut stdout = std::io::stdout(); + if stdout.is_terminal() { bail!("cannot print binary wasm output to a terminal, pass the `-t` flag to print the text format"); } - std::io::stdout() + stdout .write_all(bytes) .context("failed to write to stdout")?; } } Ok(()) } + Output::Json(s) => self.output_str(s), } } @@ -129,10 +165,28 @@ impl OutputArg { Ok(()) } - pub fn output_writer(&self) -> Result> { + pub fn output_path(&self) -> Option<&Path> { + self.output.as_deref() + } + + pub fn output_writer(&self, color: ColorChoice) -> Result> { match &self.output { - Some(output) => Ok(Box::new(BufWriter::new(File::create(&output)?))), - None => Ok(Box::new(std::io::stdout())), + Some(output) => { + let writer = BufWriter::new(File::create(&output)?); + if color == ColorChoice::AlwaysAnsi { + Ok(Box::new(Ansi::new(writer))) + } else { + Ok(Box::new(NoColor::new(writer))) + } + } + None => { + let stdout = std::io::stdout(); + if color == ColorChoice::Auto && !stdout.is_terminal() { + Ok(Box::new(StandardStream::stdout(ColorChoice::Never))) + } else { + Ok(Box::new(StandardStream::stdout(color))) + } + } } } } diff --git a/tests/cli.rs b/tests/cli.rs new file mode 100644 index 0000000000..b9bb53c03e --- /dev/null +++ b/tests/cli.rs @@ -0,0 +1,201 @@ +//! A test suite to test the `wasm-tools` CLI itself. +//! +//! This test suite will look for `*.wat` files in the `tests/cli/**` directory, +//! recursively. Each wat file must have a directive of the form: +//! +//! ;; RUN: ... +//! +//! where `...` is a space-separate set of command to pass to the `wasm-tools` +//! CLI. The `%` argument is replaced with the path to the current file. For +//! example: +//! +//! ;; RUN: dump % +//! +//! would execute `wasm-tools dump the-current-file.wat`. The `cli` directory +//! additionally contains `*.stdout` and `*.stderr` files to assert the output +//! of the subcommand. Files are not present if the stdout/stderr are empty. +//! +//! This also supports a limited form of piping along the lines of: +//! +//! ;; RUN: strip % | objdump +//! +//! where a `|` will execute the first subcommand and pipe its stdout into the +//! stdin of the next command. +//! +//! Use `BLESS=1` in the environment to auto-update expectation files. Be sure +//! to look at the diff! + +use anyhow::{anyhow, bail, Context, Result}; +use pretty_assertions::StrComparison; +use rayon::prelude::*; +use std::env; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output, Stdio}; + +fn main() { + // This test suite can't run on wasm since it involves spawning + // subprocesses. + if cfg!(target_family = "wasm") { + return; + } + + let mut tests = Vec::new(); + find_tests("tests/cli".as_ref(), &mut tests); + let filter = std::env::args().nth(1); + + let bless = env::var("BLESS").is_ok(); + let tests = tests + .iter() + .filter(|test| { + if let Some(filter) = &filter { + if let Some(s) = test.file_name().and_then(|s| s.to_str()) { + if !s.contains(filter) { + return false; + } + } + } + true + }) + .collect::>(); + + println!("running {} tests\n", tests.len()); + + let errors = tests + .par_iter() + .filter_map(|test| { + run_test(test, bless) + .with_context(|| format!("failed test {test:?}")) + .err() + }) + .collect::>(); + + if !errors.is_empty() { + for msg in errors.iter() { + eprintln!("{:?}", msg); + } + + panic!("{} tests failed", errors.len()) + } + + println!("test result: ok. {} passed\n", tests.len()); +} + +fn wasm_tools_exe() -> Command { + Command::new(env!("CARGO_BIN_EXE_wasm-tools")) +} + +fn run_test(test: &Path, bless: bool) -> Result<()> { + let contents = std::fs::read_to_string(test)?; + let line = contents + .lines() + .filter_map(|l| l.strip_prefix(";; RUN: ").or(l.strip_prefix("// RUN: "))) + .next() + .ok_or_else(|| anyhow!("no line found with `;; RUN: ` directive"))?; + + let mut cmd = wasm_tools_exe(); + let mut stdin = None; + for arg in line.split_whitespace() { + if arg == "|" { + let output = execute(&mut cmd, stdin.as_deref())?; + stdin = Some(output.stdout); + cmd = wasm_tools_exe(); + } else if arg == "%" { + cmd.arg(test); + } else { + cmd.arg(arg); + } + } + + let output = execute(&mut cmd, stdin.as_deref())?; + let extension = test.extension().unwrap().to_str().unwrap(); + assert_output( + bless, + &output.stdout, + &test.with_extension(&format!("{extension}.stdout")), + ) + .context("failed to check stdout expectation (auto-update with BLESS=1)")?; + assert_output( + bless, + &output.stderr, + &test.with_extension(&format!("{extension}.stderr")), + ) + .context("failed to check stderr expectation (auto-update with BLESS=1)")?; + Ok(()) +} + +fn execute(cmd: &mut Command, stdin: Option<&[u8]>) -> Result { + cmd.stdin(Stdio::piped()); + cmd.stdout(Stdio::piped()); + cmd.stderr(Stdio::piped()); + let mut p = cmd + .spawn() + .with_context(|| format!("failed to spawn {cmd:?}"))?; + + let mut io = p.stdin.take().unwrap(); + if let Some(stdin) = stdin { + io.write_all(stdin)?; + } + drop(io); + + let output = p.wait_with_output()?; + + if !output.status.success() { + bail!( + "{cmd:?} failed: + status: {} + stdout: {} + stderr: {}", + output.status, + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + } + Ok(output) +} + +fn assert_output(bless: bool, output: &[u8], path: &Path) -> Result<()> { + if bless { + if output.is_empty() { + drop(std::fs::remove_file(path)); + } else { + std::fs::write(path, output).with_context(|| format!("failed to write {path:?}"))?; + } + return Ok(()); + } + + if output.is_empty() { + if path.exists() { + bail!("command had no output but {path:?} exists"); + } else { + Ok(()) + } + } else { + let output = std::str::from_utf8(output)?; + let contents = std::fs::read_to_string(path) + .with_context(|| format!("failed to read {path:?}"))? + .replace("\r\n", "\n"); + if output != contents { + bail!( + "failed test: result is not as expected:{}", + StrComparison::new(&contents, &output), + ); + } + Ok(()) + } +} + +fn find_tests(path: &Path, tests: &mut Vec) { + for f in path.read_dir().unwrap() { + let f = f.unwrap(); + if f.file_type().unwrap().is_dir() { + find_tests(&f.path(), tests); + continue; + } + match f.path().extension().and_then(|s| s.to_str()) { + Some("wat") | Some("wit") => {} + _ => continue, + } + tests.push(f.path()); + } +} diff --git a/tests/cli/add-metadata-merge-sections.wat b/tests/cli/add-metadata-merge-sections.wat new file mode 100644 index 0000000000..b5a8115c29 --- /dev/null +++ b/tests/cli/add-metadata-merge-sections.wat @@ -0,0 +1,2 @@ +;; RUN: metadata add --language foo % | metadata add --language bar | metadata add --sdk foo=2 | metadata show +(module) diff --git a/tests/cli/add-metadata-merge-sections.wat.stdout b/tests/cli/add-metadata-merge-sections.wat.stdout new file mode 100644 index 0000000000..4ad91a0ddb --- /dev/null +++ b/tests/cli/add-metadata-merge-sections.wat.stdout @@ -0,0 +1,6 @@ +module: + language: + foo + bar + sdk: + foo: 2 diff --git a/tests/cli/add-metadata-overwrite-name.wat b/tests/cli/add-metadata-overwrite-name.wat new file mode 100644 index 0000000000..7799e88368 --- /dev/null +++ b/tests/cli/add-metadata-overwrite-name.wat @@ -0,0 +1,2 @@ +;; RUN: metadata add % --name foo | metadata show +(module $bar) diff --git a/tests/cli/add-metadata-overwrite-name.wat.stdout b/tests/cli/add-metadata-overwrite-name.wat.stdout new file mode 100644 index 0000000000..085a5600b2 --- /dev/null +++ b/tests/cli/add-metadata-overwrite-name.wat.stdout @@ -0,0 +1 @@ +module foo: diff --git a/tests/cli/add-metadata.wat b/tests/cli/add-metadata.wat new file mode 100644 index 0000000000..857097f3dc --- /dev/null +++ b/tests/cli/add-metadata.wat @@ -0,0 +1,2 @@ +;; RUN: metadata add % --name foo --language bar --processed-by baz=1 --sdk my-sdk=2 | metadata show +(module) diff --git a/tests/cli/add-metadata.wat.stdout b/tests/cli/add-metadata.wat.stdout new file mode 100644 index 0000000000..681eadab3a --- /dev/null +++ b/tests/cli/add-metadata.wat.stdout @@ -0,0 +1,7 @@ +module foo: + language: + bar + processed-by: + baz: 1 + sdk: + my-sdk: 2 diff --git a/tests/cli/demangle1.wat b/tests/cli/demangle1.wat new file mode 100644 index 0000000000..9c1feb18bc --- /dev/null +++ b/tests/cli/demangle1.wat @@ -0,0 +1,7 @@ +;; RUN: demangle -t % + +(module + (func $do_no_demangle_me) + (func $_ZN4rustE) + (func $_Z3food) +) diff --git a/tests/cli/demangle1.wat.stdout b/tests/cli/demangle1.wat.stdout new file mode 100644 index 0000000000..6cd73b1919 --- /dev/null +++ b/tests/cli/demangle1.wat.stdout @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $do_no_demangle_me (;0;) (type 0)) + (func $rust (;1;) (type 0)) + (func $#func2 (@name "foo(double)") (;2;) (type 0)) +) \ No newline at end of file diff --git a/tests/cli/dump-invalid-name-section.wat b/tests/cli/dump-invalid-name-section.wat new file mode 100644 index 0000000000..11c04e96bb --- /dev/null +++ b/tests/cli/dump-invalid-name-section.wat @@ -0,0 +1,22 @@ +;; RUN: dump % + +(module binary + "\00asm" + "\01\00\00\00" + + "\00" ;; custom section + "\10" ;; byte length of entire section + "\04" ;; byte length of "name" + "name" + "\02" ;; local name subsection + "\07" ;; 7 byte subsection + "\06" ;; six names + "\22" ;; names for function 0x22 + "\00" ;; 0 count + "\00" ;; names for function 0 + "\00" ;; 0 count + "\00" ;; names for function 0 + "\40" ;; 0x40 count + "\00" ;; pad + "\00" ;; pad +) diff --git a/tests/cli/dump-invalid-name-section.wat.stdout b/tests/cli/dump-invalid-name-section.wat.stdout new file mode 100644 index 0000000000..b567ab8582 --- /dev/null +++ b/tests/cli/dump-invalid-name-section.wat.stdout @@ -0,0 +1,13 @@ + 0x0 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x8 | 00 10 | custom section + 0xa | 04 6e 61 6d | name: "name" + | 65 + 0xf | 02 07 | local section + 0x11 | 06 | 6 count + 0x12 | 22 | function 34 local name section + 0x13 | 00 | 0 count + 0x14 | 00 | function 0 local name section + 0x15 | 00 | 0 count + 0x16 | 00 40 | ??? + 0x18 |-------------| ... failed to decode 2 more bytes: unexpected end-of-file (at offset 0x18) diff --git a/tests/cli/dump-invalid-name-section2.wat b/tests/cli/dump-invalid-name-section2.wat new file mode 100644 index 0000000000..c7b96674e1 --- /dev/null +++ b/tests/cli/dump-invalid-name-section2.wat @@ -0,0 +1,22 @@ +;; RUN: dump % + +(module binary + "\00asm" + "\01\00\00\00" + + "\00" ;; custom section + "\10" ;; byte length of entire section + "\04" ;; byte length of "name" + "name" + "\02" ;; local name subsection + "\07" ;; 7 byte subsection + "\06" ;; six names + "\22" ;; names for function 0x22 + "\00" ;; 0 count + "\00" ;; names for function 0 + "\00" ;; 0 count + "\00" ;; names for function 0 + "\00" ;; 0 count + "\00" ;; pad + "\00" ;; pad +) diff --git a/tests/cli/dump-invalid-name-section2.wat.stdout b/tests/cli/dump-invalid-name-section2.wat.stdout new file mode 100644 index 0000000000..f6defa0b56 --- /dev/null +++ b/tests/cli/dump-invalid-name-section2.wat.stdout @@ -0,0 +1,14 @@ + 0x0 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x8 | 00 10 | custom section + 0xa | 04 6e 61 6d | name: "name" + | 65 + 0xf | 02 07 | local section + 0x11 | 06 | 6 count + 0x12 | 22 | function 34 local name section + 0x13 | 00 | 0 count + 0x14 | 00 | function 0 local name section + 0x15 | 00 | 0 count + 0x16 | 00 | function 0 local name section + 0x17 | 00 | 0 count + 0x18 |-------------| ... failed to decode 2 more bytes: unexpected end-of-file (at offset 0x18) diff --git a/tests/cli/dump-invalid-name-section3.wat b/tests/cli/dump-invalid-name-section3.wat new file mode 100644 index 0000000000..53f8429feb --- /dev/null +++ b/tests/cli/dump-invalid-name-section3.wat @@ -0,0 +1,14 @@ +;; RUN: dump % + +(module binary + "\00asm" + "\01\00\00\00" + + "\00" ;; custom section + "\08" ;; byte length of entire section + "\04" ;; byte length of "name" + "name" + "\02" ;; local name subsection + "\07" ;; 7 byte subsection + "\06" ;; six names +) diff --git a/tests/cli/dump-invalid-name-section3.wat.stdout b/tests/cli/dump-invalid-name-section3.wat.stdout new file mode 100644 index 0000000000..3c22468b4e --- /dev/null +++ b/tests/cli/dump-invalid-name-section3.wat.stdout @@ -0,0 +1,7 @@ + 0x0 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x8 | 00 08 | custom section + 0xa | 04 6e 61 6d | name: "name" + | 65 + 0xf | 02 07 | ??? + 0x11 |-------------| ... failed to decode 1 more bytes: unexpected end of section (at offset 0x12) diff --git a/tests/cli/dump/alias.wat b/tests/cli/dump/alias.wat new file mode 100644 index 0000000000..60bab1fa22 --- /dev/null +++ b/tests/cli/dump/alias.wat @@ -0,0 +1,21 @@ +;; RUN: dump % + +(component + (import "i" (instance $i + (export "f1" (func)) + (export "f2" (func (param "p1" string))) + )) + + (func (alias export $i "f1")) + (alias export $i "f2" (func)) + + (core func (canon lower (func $i "f1"))) + + (core module $m + (func (export "f3")) + ) + + (core instance $m (instantiate $m)) + (core func (alias core export $m "f3")) + (alias core export $m "f3" (core func)) +) diff --git a/tests/cli/dump/alias.wat.stdout b/tests/cli/dump/alias.wat.stdout new file mode 100644 index 0000000000..a8089ee796 --- /dev/null +++ b/tests/cli/dump/alias.wat.stdout @@ -0,0 +1,74 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 1f | component type section + 0xa | 01 | 1 count + 0xb | 42 04 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], results: Named([]) })), Export { name: Kebab("f1"), ty: Func(0) }, Type(Func(ComponentFuncType { params: [("p1", Primitive(String))], results: Named([]) })), Export { name: Kebab("f2"), ty: Func(1) }]) + | 00 01 00 04 + | 00 02 66 31 + | 01 00 01 40 + | 01 02 70 31 + | 73 01 00 04 + | 00 02 66 32 + | 01 01 + 0x29 | 0a 06 | component import section + 0x2b | 01 | 1 count + 0x2c | 00 01 69 05 | [instance 0] ComponentImport { name: Kebab("i"), ty: Instance(0) } + | 00 + 0x31 | 06 13 | component alias section + 0x33 | 03 | 3 count + 0x34 | 01 00 00 02 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "f1" } + | 66 31 + 0x3a | 01 00 00 02 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "f2" } + | 66 32 + 0x40 | 01 00 00 02 | alias [func 2] InstanceExport { kind: Func, instance_index: 0, name: "f1" } + | 66 31 + 0x46 | 08 05 | canonical function section + 0x48 | 01 | 1 count + 0x49 | 01 00 02 00 | [core func 0] Lower { func_index: 2, options: [] } + 0x4d | 01 2b | [core module 0] inline size + 0x4f | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x57 | 01 04 | type section + 0x59 | 01 | 1 count + 0x5a | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0x5d | 03 02 | func section + 0x5f | 01 | 1 count + 0x60 | 00 | [func 0] type 0 + 0x61 | 07 06 | export section + 0x63 | 01 | 1 count + 0x64 | 02 66 33 00 | export Export { name: "f3", kind: Func, index: 0 } + | 00 + 0x69 | 0a 04 | code section + 0x6b | 01 | 1 count +============== func 0 ==================== + 0x6c | 02 | size of function + 0x6d | 00 | 0 local blocks + 0x6e | 0b | end + 0x6f | 00 09 | custom section + 0x71 | 04 6e 61 6d | name: "name" + | 65 + 0x76 | 00 02 | module name + 0x78 | 01 6d | "m" + 0x7a | 02 04 | core instance section + 0x7c | 01 | 1 count + 0x7d | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } + 0x80 | 06 0f | component alias section + 0x82 | 02 | 2 count + 0x83 | 00 00 01 00 | alias [core func 1] CoreInstanceExport { kind: Func, instance_index: 0, name: "f3" } + | 02 66 33 + 0x8a | 00 00 01 00 | alias [core func 2] CoreInstanceExport { kind: Func, instance_index: 0, name: "f3" } + | 02 66 33 + 0x91 | 00 26 | custom section + 0x93 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0xa2 | 01 06 00 11 | core module name section + 0xa6 | 01 | 1 count + 0xa7 | 00 01 6d | Naming { index: 0, name: "m" } + 0xaa | 01 06 00 12 | core instance name section + 0xae | 01 | 1 count + 0xaf | 00 01 6d | Naming { index: 0, name: "m" } + 0xb2 | 01 05 05 | instance name section + 0xb5 | 01 | 1 count + 0xb6 | 00 01 69 | Naming { index: 0, name: "i" } diff --git a/tests/cli/dump/alias2.wat b/tests/cli/dump/alias2.wat new file mode 100644 index 0000000000..5d9d1c3c1d --- /dev/null +++ b/tests/cli/dump/alias2.wat @@ -0,0 +1,84 @@ +;; RUN: dump % + +(component + (type $t (instance + (export "a" (core module)) + (export "b" (func)) + (export "c" (value string)) + (export "d" (instance)) + (export "e" (component)) + )) + + (import "a" (instance $i (type $t))) + + (component $c + (import "a" (core module)) + (import "b" (func)) + (import "c" (value string)) + (import "d" (instance)) + (import "e" (component)) + ) + + (instance (instantiate $c + (with "a" (core module $i "a")) + (with "b" (func $i "b")) + (with "c" (value $i "c")) + (with "d" (instance $i "d")) + (with "e" (component $i "e")) + )) + + (component $c2 + (import "a" (instance (type $t))) + ) + + (alias export $i "a" (core module $m)) + (alias export $i "b" (func $f)) + (alias export $i "c" (value $v)) + (alias export $i "d" (instance $i2)) + (alias export $i "e" (component $c3)) + + (instance + (instantiate $c2 + (with "a" (instance + (export "a" (core module $m)) + (export "b" (func $f)) + (export "c" (value $v)) + (export "d" (instance $i2)) + (export "e" (component $c3)) + )) + ) + ) + + (core module $m1 + (func (export "1")) + (memory (export "2") 1) + (global (export "3") i32) + (table (export "4") 1 funcref) + ) + + (core module $m2 + (import "" "1" (func)) + (import "" "2" (memory 1)) + (import "" "3" (global i32)) + (import "" "4" (table 1 funcref)) + ) + + (core instance $i (instantiate $m1)) + (core instance (instantiate $m2 (with "" (instance $i)))) + + (alias core export $i "1" (core func $f)) + (alias core export $i "2" (core memory $m)) + (alias core export $i "3" (core global $g)) + (alias core export $i "4" (core table $t)) + + (core instance + (instantiate $m2 + (with "" (instance + (export "1" (func $f)) + (export "2" (memory $m)) + (export "3" (global $g)) + (export "4" (table $t)) + )) + ) + ) +) diff --git a/tests/cli/dump/alias2.wat.stdout b/tests/cli/dump/alias2.wat.stdout new file mode 100644 index 0000000000..b43761d624 --- /dev/null +++ b/tests/cli/dump/alias2.wat.stdout @@ -0,0 +1,247 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 30 | component type section + 0xa | 01 | 1 count + 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: Kebab("a"), ty: Module(0) }, Type(Func(ComponentFuncType { params: [], results: Named([]) })), Export { name: Kebab("b"), ty: Func(0) }, Export { name: Kebab("c"), ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: Kebab("d"), ty: Instance(1) }, Type(Component([])), Export { name: Kebab("e"), ty: Component(2) }]) + | 00 04 00 01 + | 61 00 11 00 + | 01 40 00 01 + | 00 04 00 01 + | 62 01 00 04 + | 00 01 63 02 + | 73 01 42 00 + | 04 00 01 64 + | 05 01 01 41 + | 00 04 00 01 + | 65 04 02 + 0x3a | 0a 06 | component import section + 0x3c | 01 | 1 count + 0x3d | 00 01 61 05 | [instance 0] ComponentImport { name: Kebab("a"), ty: Instance(0) } + | 00 + 0x42 | 04 59 | [component 0] inline size + 0x44 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x4c | 03 03 | core type section + 0x4e | 01 | 1 count + 0x4f | 50 00 | [core type 0] Module([]) + 0x51 | 0a 07 | component import section + 0x53 | 01 | 1 count + 0x54 | 00 01 61 00 | [module 0] ComponentImport { name: Kebab("a"), ty: Module(0) } + | 11 00 + 0x5a | 07 05 | component type section + 0x5c | 01 | 1 count + 0x5d | 40 00 01 00 | [type 0] Func(ComponentFuncType { params: [], results: Named([]) }) + 0x61 | 0a 0b | component import section + 0x63 | 02 | 2 count + 0x64 | 00 01 62 01 | [func 0] ComponentImport { name: Kebab("b"), ty: Func(0) } + | 00 + 0x69 | 00 01 63 02 | [value 0] ComponentImport { name: Kebab("c"), ty: Value(Primitive(String)) } + | 73 + 0x6e | 07 03 | component type section + 0x70 | 01 | 1 count + 0x71 | 42 00 | [type 1] Instance([]) + 0x73 | 0a 06 | component import section + 0x75 | 01 | 1 count + 0x76 | 00 01 64 05 | [instance 0] ComponentImport { name: Kebab("d"), ty: Instance(1) } + | 01 + 0x7b | 07 03 | component type section + 0x7d | 01 | 1 count + 0x7e | 41 00 | [type 2] Component([]) + 0x80 | 0a 06 | component import section + 0x82 | 01 | 1 count + 0x83 | 00 01 65 04 | [component 0] ComponentImport { name: Kebab("e"), ty: Component(2) } + | 02 + 0x88 | 00 13 | custom section + 0x8a | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x99 | 00 02 | component name + 0x9b | 01 63 | "c" + 0x9d | 06 1b | component alias section + 0x9f | 05 | 5 count + 0xa0 | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "a" } + | 01 61 + 0xa6 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "b" } + | 62 + 0xab | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "c" } + | 63 + 0xb0 | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "d" } + | 64 + 0xb5 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "e" } + | 65 + 0xba | 05 19 | component instance section + 0xbc | 01 | 1 count + 0xbd | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "a", kind: Module, index: 0 }, ComponentInstantiationArg { name: "b", kind: Func, index: 0 }, ComponentInstantiationArg { name: "c", kind: Value, index: 0 }, ComponentInstantiationArg { name: "d", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "e", kind: Component, index: 1 }] } + | 61 00 11 00 + | 01 62 01 00 + | 01 63 02 00 + | 01 64 05 01 + | 01 65 04 01 + 0xd5 | 04 34 | [component 2] inline size + 0xd7 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0xdf | 06 05 | component alias section + 0xe1 | 01 | 1 count + 0xe2 | 03 02 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0xe6 | 0a 06 | component import section + 0xe8 | 01 | 1 count + 0xe9 | 00 01 61 05 | [instance 0] ComponentImport { name: Kebab("a"), ty: Instance(0) } + | 00 + 0xee | 00 1b | custom section + 0xf0 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0xff | 00 03 | component name + 0x101 | 02 63 32 | "c2" + 0x104 | 01 05 03 | type name section + 0x107 | 01 | 1 count + 0x108 | 00 01 74 | Naming { index: 0, name: "t" } + 0x10b | 06 1b | component alias section + 0x10d | 05 | 5 count + 0x10e | 00 11 00 00 | alias [module 1] InstanceExport { kind: Module, instance_index: 0, name: "a" } + | 01 61 + 0x114 | 01 00 00 01 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "b" } + | 62 + 0x119 | 02 00 00 01 | alias [value 1] InstanceExport { kind: Value, instance_index: 0, name: "c" } + | 63 + 0x11e | 05 00 00 01 | alias [instance 3] InstanceExport { kind: Instance, instance_index: 0, name: "d" } + | 64 + 0x123 | 04 00 00 01 | alias [component 3] InstanceExport { kind: Component, instance_index: 0, name: "e" } + | 65 + 0x128 | 05 24 | component instance section + 0x12a | 02 | 2 count + 0x12b | 01 05 00 01 | [instance 4] FromExports([ComponentExport { name: Kebab("a"), kind: Module, index: 1, ty: None }, ComponentExport { name: Kebab("b"), kind: Func, index: 1, ty: None }, ComponentExport { name: Kebab("c"), kind: Value, index: 1, ty: None }, ComponentExport { name: Kebab("d"), kind: Instance, index: 3, ty: None }, ComponentExport { name: Kebab("e"), kind: Component, index: 3, ty: None }]) + | 61 00 11 01 + | 00 01 62 01 + | 01 00 01 63 + | 02 01 00 01 + | 64 05 03 00 + | 01 65 04 03 + 0x147 | 00 02 01 01 | [instance 5] Instantiate { component_index: 2, args: [ComponentInstantiationArg { name: "a", kind: Instance, index: 4 }] } + | 61 05 04 + 0x14e | 01 48 | [core module 2] inline size + 0x150 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x158 | 01 04 | type section + 0x15a | 01 | 1 count + 0x15b | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0x15e | 03 02 | func section + 0x160 | 01 | 1 count + 0x161 | 00 | [func 0] type 0 + 0x162 | 04 04 | table section + 0x164 | 01 | 1 count + 0x165 | 70 00 01 | [table 0] Table { ty: TableType { element_type: funcref, initial: 1, maximum: None }, init: RefNull } + 0x168 | 05 03 | memory section + 0x16a | 01 | 1 count + 0x16b | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None } + 0x16d | 06 04 | global section + 0x16f | 01 | 1 count + 0x170 | 7f 00 | [global 0] GlobalType { content_type: I32, mutable: false } + 0x172 | 0b | end + 0x173 | 07 11 | export section + 0x175 | 04 | 4 count + 0x176 | 01 31 00 00 | export Export { name: "1", kind: Func, index: 0 } + 0x17a | 01 32 02 00 | export Export { name: "2", kind: Memory, index: 0 } + 0x17e | 01 33 03 00 | export Export { name: "3", kind: Global, index: 0 } + 0x182 | 01 34 01 00 | export Export { name: "4", kind: Table, index: 0 } + 0x186 | 0a 04 | code section + 0x188 | 01 | 1 count +============== func 0 ==================== + 0x189 | 02 | size of function + 0x18a | 00 | 0 local blocks + 0x18b | 0b | end + 0x18c | 00 0a | custom section + 0x18e | 04 6e 61 6d | name: "name" + | 65 + 0x193 | 00 03 | module name + 0x195 | 02 6d 31 | "m1" + 0x198 | 01 35 | [core module 3] inline size + 0x19a | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x1a2 | 01 04 | type section + 0x1a4 | 01 | 1 count + 0x1a5 | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0x1a8 | 02 19 | import section + 0x1aa | 04 | 4 count + 0x1ab | 00 01 31 00 | import [func 0] Import { module: "", name: "1", ty: Func(0) } + | 00 + 0x1b0 | 00 01 32 02 | import [memory 0] Import { module: "", name: "2", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) } + | 00 01 + 0x1b6 | 00 01 33 03 | import [global 0] Import { module: "", name: "3", ty: Global(GlobalType { content_type: I32, mutable: false }) } + | 7f 00 + 0x1bc | 00 01 34 01 | import [table 0] Import { module: "", name: "4", ty: Table(TableType { element_type: funcref, initial: 1, maximum: None }) } + | 70 00 01 + 0x1c3 | 00 0a | custom section + 0x1c5 | 04 6e 61 6d | name: "name" + | 65 + 0x1ca | 00 03 | module name + 0x1cc | 02 6d 32 | "m2" + 0x1cf | 02 0a | core instance section + 0x1d1 | 02 | 2 count + 0x1d2 | 00 02 00 | [core instance 0] Instantiate { module_index: 2, args: [] } + 0x1d5 | 00 03 01 00 | [core instance 1] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 0 }] } + | 12 00 + 0x1db | 06 19 | component alias section + 0x1dd | 04 | 4 count + 0x1de | 00 00 01 00 | alias [core func 0] CoreInstanceExport { kind: Func, instance_index: 0, name: "1" } + | 01 31 + 0x1e4 | 00 02 01 00 | alias [core memory 0] CoreInstanceExport { kind: Memory, instance_index: 0, name: "2" } + | 01 32 + 0x1ea | 00 03 01 00 | alias [core global 0] CoreInstanceExport { kind: Global, instance_index: 0, name: "3" } + | 01 33 + 0x1f0 | 00 01 01 00 | alias [core table 0] CoreInstanceExport { kind: Table, instance_index: 0, name: "4" } + | 01 34 + 0x1f6 | 02 19 | core instance section + 0x1f8 | 02 | 2 count + 0x1f9 | 01 04 01 31 | [core instance 2] FromExports([Export { name: "1", kind: Func, index: 0 }, Export { name: "2", kind: Memory, index: 0 }, Export { name: "3", kind: Global, index: 0 }, Export { name: "4", kind: Table, index: 0 }]) + | 00 00 01 32 + | 02 00 01 33 + | 03 00 01 34 + | 01 00 + 0x20b | 00 03 01 00 | [core instance 3] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 2 }] } + | 12 02 + 0x211 | 00 76 | custom section + 0x213 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x222 | 01 06 00 00 | core func name section + 0x226 | 01 | 1 count + 0x227 | 00 01 66 | Naming { index: 0, name: "f" } + 0x22a | 01 06 00 01 | core table name section + 0x22e | 01 | 1 count + 0x22f | 00 01 74 | Naming { index: 0, name: "t" } + 0x232 | 01 06 00 02 | core memory name section + 0x236 | 01 | 1 count + 0x237 | 00 01 6d | Naming { index: 0, name: "m" } + 0x23a | 01 06 00 03 | core global name section + 0x23e | 01 | 1 count + 0x23f | 00 01 67 | Naming { index: 0, name: "g" } + 0x242 | 01 0e 00 11 | core module name section + 0x246 | 03 | 3 count + 0x247 | 01 01 6d | Naming { index: 1, name: "m" } + 0x24a | 02 02 6d 31 | Naming { index: 2, name: "m1" } + 0x24e | 03 02 6d 32 | Naming { index: 3, name: "m2" } + 0x252 | 01 06 00 12 | core instance name section + 0x256 | 01 | 1 count + 0x257 | 00 01 69 | Naming { index: 0, name: "i" } + 0x25a | 01 05 01 | func name section + 0x25d | 01 | 1 count + 0x25e | 01 01 66 | Naming { index: 1, name: "f" } + 0x261 | 01 05 02 | value name section + 0x264 | 01 | 1 count + 0x265 | 01 01 76 | Naming { index: 1, name: "v" } + 0x268 | 01 05 03 | type name section + 0x26b | 01 | 1 count + 0x26c | 00 01 74 | Naming { index: 0, name: "t" } + 0x26f | 01 0d 04 | component name section + 0x272 | 03 | 3 count + 0x273 | 00 01 63 | Naming { index: 0, name: "c" } + 0x276 | 02 02 63 32 | Naming { index: 2, name: "c2" } + 0x27a | 03 02 63 33 | Naming { index: 3, name: "c3" } + 0x27e | 01 09 05 | instance name section + 0x281 | 02 | 2 count + 0x282 | 00 01 69 | Naming { index: 0, name: "i" } + 0x285 | 03 02 69 32 | Naming { index: 3, name: "i2" } diff --git a/tests/cli/dump/blockty.wat b/tests/cli/dump/blockty.wat new file mode 100644 index 0000000000..321cba37e7 --- /dev/null +++ b/tests/cli/dump/blockty.wat @@ -0,0 +1,16 @@ +;; RUN: dump % + +(module + (type $empty (func)) + (type $t (func (result i32))) + (func + (block) + (block (result i32)) + (block (param i32)) + (block (param i32) (result i32)) + (block (param i32) (result i32 i32)) + (block (type $t)) + (block (type $t) (result i32)) + (block (type $empty)) + ) +) diff --git a/tests/cli/dump/blockty.wat.stdout b/tests/cli/dump/blockty.wat.stdout new file mode 100644 index 0000000000..9dc651ec29 --- /dev/null +++ b/tests/cli/dump/blockty.wat.stdout @@ -0,0 +1,44 @@ + 0x0 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x8 | 01 17 | type section + 0xa | 05 | 5 count + 0xb | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0xe | 60 00 01 7f | [type 1] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [I32] }) }) + 0x12 | 60 01 7f 00 | [type 2] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32], returns: [] }) }) + 0x16 | 60 01 7f 01 | [type 3] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32], returns: [I32] }) }) + | 7f + 0x1b | 60 01 7f 02 | [type 4] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32], returns: [I32, I32] }) }) + | 7f 7f + 0x21 | 03 02 | func section + 0x23 | 01 | 1 count + 0x24 | 00 | [func 0] type 0 + 0x25 | 0a 1c | code section + 0x27 | 01 | 1 count +============== func 0 ==================== + 0x28 | 1a | size of function + 0x29 | 00 | 0 local blocks + 0x2a | 02 40 | block blockty:Empty + 0x2c | 0b | end + 0x2d | 02 7f | block blockty:Type(I32) + 0x2f | 0b | end + 0x30 | 02 02 | block blockty:FuncType(2) + 0x32 | 0b | end + 0x33 | 02 03 | block blockty:FuncType(3) + 0x35 | 0b | end + 0x36 | 02 04 | block blockty:FuncType(4) + 0x38 | 0b | end + 0x39 | 02 01 | block blockty:FuncType(1) + 0x3b | 0b | end + 0x3c | 02 01 | block blockty:FuncType(1) + 0x3e | 0b | end + 0x3f | 02 00 | block blockty:FuncType(0) + 0x41 | 0b | end + 0x42 | 0b | end + 0x43 | 00 12 | custom section + 0x45 | 04 6e 61 6d | name: "name" + | 65 + 0x4a | 04 0b | type name section + 0x4c | 02 | 2 count + 0x4d | 00 05 65 6d | Naming { index: 0, name: "empty" } + | 70 74 79 + 0x54 | 01 01 74 | Naming { index: 1, name: "t" } diff --git a/tests/cli/dump/bundled.wat b/tests/cli/dump/bundled.wat new file mode 100644 index 0000000000..d42b366056 --- /dev/null +++ b/tests/cli/dump/bundled.wat @@ -0,0 +1,51 @@ +;; RUN: dump % + +(component + (type $WasiFile (instance + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) + + (core module $libc + (memory (export "mem") 0) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + ) + + (core instance $libc (instantiate $libc)) + + (core module $CHILD + (import "wasi-file" "read" (func $wasi-file (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core module $VIRTUALIZE + (import "wasi-file" "read" (func (param i32 i32))) + (func (export "read") (param i32 i32) + unreachable + ) + (func (export "write") (param i32 i32 i32) + unreachable + ) + ) + + (core func $real-wasi-read + (canon lower (func $real-wasi "read") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + + (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance (export "read" (func $real-wasi-read)))))) + (core instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) + (func (export "work") + (canon lift (core func $child "play") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) +) diff --git a/tests/cli/dump/bundled.wat.stdout b/tests/cli/dump/bundled.wat.stdout new file mode 100644 index 0000000000..51d4310870 --- /dev/null +++ b/tests/cli/dump/bundled.wat.stdout @@ -0,0 +1,233 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 30 | component type section + 0xa | 01 | 1 count + 0xb | 42 06 01 70 | [type 0] Instance([Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: [("len", Primitive(U32))], results: Unnamed(Type(0)) })), Export { name: Kebab("read"), ty: Func(1) }, Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: [("buf", Type(2))], results: Unnamed(Primitive(U32)) })), Export { name: Kebab("write"), ty: Func(3) }]) + | 7d 01 40 01 + | 03 6c 65 6e + | 79 00 00 04 + | 00 04 72 65 + | 61 64 01 01 + | 01 70 7d 01 + | 40 01 03 62 + | 75 66 02 00 + | 79 04 00 05 + | 77 72 69 74 + | 65 01 03 + 0x3a | 0a 0e | component import section + 0x3c | 01 | 1 count + 0x3d | 00 09 77 61 | [instance 0] ComponentImport { name: Kebab("wasi-file"), ty: Instance(0) } + | 73 69 2d 66 + | 69 6c 65 05 + | 00 + 0x4a | 01 44 | [core module 0] inline size + 0x4c | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x54 | 01 09 | type section + 0x56 | 01 | 1 count + 0x57 | 60 04 7f 7f | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32, I32, I32, I32], returns: [I32] }) }) + | 7f 7f 01 7f + 0x5f | 03 02 | func section + 0x61 | 01 | 1 count + 0x62 | 00 | [func 0] type 0 + 0x63 | 05 03 | memory section + 0x65 | 01 | 1 count + 0x66 | 00 00 | [memory 0] MemoryType { memory64: false, shared: false, initial: 0, maximum: None } + 0x68 | 07 11 | export section + 0x6a | 02 | 2 count + 0x6b | 03 6d 65 6d | export Export { name: "mem", kind: Memory, index: 0 } + | 02 00 + 0x71 | 07 72 65 61 | export Export { name: "realloc", kind: Func, index: 0 } + | 6c 6c 6f 63 + | 00 00 + 0x7b | 0a 05 | code section + 0x7d | 01 | 1 count +============== func 0 ==================== + 0x7e | 03 | size of function + 0x7f | 00 | 0 local blocks + 0x80 | 00 | unreachable + 0x81 | 0b | end + 0x82 | 00 0c | custom section + 0x84 | 04 6e 61 6d | name: "name" + | 65 + 0x89 | 00 05 | module name + 0x8b | 04 6c 69 62 | "libc" + | 63 + 0x90 | 02 04 | core instance section + 0x92 | 01 | 1 count + 0x93 | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } + 0x96 | 01 5f | [core module 1] inline size + 0x98 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0xa0 | 01 09 | type section + 0xa2 | 02 | 2 count + 0xa3 | 60 02 7f 7f | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32, I32], returns: [] }) }) + | 00 + 0xa8 | 60 00 00 | [type 1] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0xab | 02 12 | import section + 0xad | 01 | 1 count + 0xae | 09 77 61 73 | import [func 0] Import { module: "wasi-file", name: "read", ty: Func(0) } + | 69 2d 66 69 + | 6c 65 04 72 + | 65 61 64 00 + | 00 + 0xbf | 03 02 | func section + 0xc1 | 01 | 1 count + 0xc2 | 01 | [func 1] type 1 + 0xc3 | 07 08 | export section + 0xc5 | 01 | 1 count + 0xc6 | 04 70 6c 61 | export Export { name: "play", kind: Func, index: 1 } + | 79 00 01 + 0xcd | 0a 05 | code section + 0xcf | 01 | 1 count +============== func 1 ==================== + 0xd0 | 03 | size of function + 0xd1 | 00 | 0 local blocks + 0xd2 | 00 | unreachable + 0xd3 | 0b | end + 0xd4 | 00 21 | custom section + 0xd6 | 04 6e 61 6d | name: "name" + | 65 + 0xdb | 00 06 | module name + 0xdd | 05 43 48 49 | "CHILD" + | 4c 44 + 0xe3 | 01 12 | function name section + 0xe5 | 02 | 2 count + 0xe6 | 00 09 77 61 | Naming { index: 0, name: "wasi-file" } + | 73 69 2d 66 + | 69 6c 65 + 0xf1 | 01 04 70 6c | Naming { index: 1, name: "play" } + | 61 79 + 0xf7 | 01 60 | [core module 2] inline size + 0xf9 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x101 | 01 0c | type section + 0x103 | 02 | 2 count + 0x104 | 60 02 7f 7f | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32, I32], returns: [] }) }) + | 00 + 0x109 | 60 03 7f 7f | [type 1] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32, I32, I32], returns: [] }) }) + | 7f 00 + 0x10f | 02 12 | import section + 0x111 | 01 | 1 count + 0x112 | 09 77 61 73 | import [func 0] Import { module: "wasi-file", name: "read", ty: Func(0) } + | 69 2d 66 69 + | 6c 65 04 72 + | 65 61 64 00 + | 00 + 0x123 | 03 03 | func section + 0x125 | 02 | 2 count + 0x126 | 00 | [func 1] type 0 + 0x127 | 01 | [func 2] type 1 + 0x128 | 07 10 | export section + 0x12a | 02 | 2 count + 0x12b | 04 72 65 61 | export Export { name: "read", kind: Func, index: 1 } + | 64 00 01 + 0x132 | 05 77 72 69 | export Export { name: "write", kind: Func, index: 2 } + | 74 65 00 02 + 0x13a | 0a 09 | code section + 0x13c | 02 | 2 count +============== func 1 ==================== + 0x13d | 03 | size of function + 0x13e | 00 | 0 local blocks + 0x13f | 00 | unreachable + 0x140 | 0b | end +============== func 2 ==================== + 0x141 | 03 | size of function + 0x142 | 00 | 0 local blocks + 0x143 | 00 | unreachable + 0x144 | 0b | end + 0x145 | 00 12 | custom section + 0x147 | 04 6e 61 6d | name: "name" + | 65 + 0x14c | 00 0b | module name + 0x14e | 0a 56 49 52 | "VIRTUALIZE" + | 54 55 41 4c + | 49 5a 45 + 0x159 | 06 1d | component alias section + 0x15b | 03 | 3 count + 0x15c | 01 00 00 04 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "read" } + | 72 65 61 64 + 0x164 | 00 02 01 00 | alias [core memory 0] CoreInstanceExport { kind: Memory, instance_index: 0, name: "mem" } + | 03 6d 65 6d + 0x16c | 00 00 01 00 | alias [core func 0] CoreInstanceExport { kind: Func, instance_index: 0, name: "realloc" } + | 07 72 65 61 + | 6c 6c 6f 63 + 0x178 | 08 09 | canonical function section + 0x17a | 01 | 1 count + 0x17b | 01 00 00 02 | [core func 1] Lower { func_index: 0, options: [Memory(0), Realloc(0)] } + | 03 00 04 00 + 0x183 | 02 28 | core instance section + 0x185 | 03 | 3 count + 0x186 | 01 01 04 72 | [core instance 1] FromExports([Export { name: "read", kind: Func, index: 1 }]) + | 65 61 64 00 + | 01 + 0x18f | 00 02 01 09 | [core instance 2] Instantiate { module_index: 2, args: [InstantiationArg { name: "wasi-file", kind: Instance, index: 1 }] } + | 77 61 73 69 + | 2d 66 69 6c + | 65 12 01 + 0x19e | 00 01 01 09 | [core instance 3] Instantiate { module_index: 1, args: [InstantiationArg { name: "wasi-file", kind: Instance, index: 2 }] } + | 77 61 73 69 + | 2d 66 69 6c + | 65 12 02 + 0x1ad | 07 05 | component type section + 0x1af | 01 | 1 count + 0x1b0 | 40 00 01 00 | [type 1] Func(ComponentFuncType { params: [], results: Named([]) }) + 0x1b4 | 06 1e | component alias section + 0x1b6 | 03 | 3 count + 0x1b7 | 00 00 01 03 | alias [core func 2] CoreInstanceExport { kind: Func, instance_index: 3, name: "play" } + | 04 70 6c 61 + | 79 + 0x1c0 | 00 02 01 00 | alias [core memory 1] CoreInstanceExport { kind: Memory, instance_index: 0, name: "mem" } + | 03 6d 65 6d + 0x1c8 | 00 00 01 00 | alias [core func 3] CoreInstanceExport { kind: Func, instance_index: 0, name: "realloc" } + | 07 72 65 61 + | 6c 6c 6f 63 + 0x1d4 | 08 0a | canonical function section + 0x1d6 | 01 | 1 count + 0x1d7 | 00 00 02 02 | [func 1] Lift { core_func_index: 2, type_index: 1, options: [Memory(1), Realloc(3)] } + | 03 01 04 03 + | 01 + 0x1e0 | 0b 0a | component export section + 0x1e2 | 01 | 1 count + 0x1e3 | 00 04 77 6f | export ComponentExport { name: Kebab("work"), kind: Func, index: 1, ty: None } + | 72 6b 01 01 + | 00 + 0x1ec | 00 7c | custom section + 0x1ee | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x1fd | 01 13 00 00 | core func name section + 0x201 | 01 | 1 count + 0x202 | 01 0e 72 65 | Naming { index: 1, name: "real-wasi-read" } + | 61 6c 2d 77 + | 61 73 69 2d + | 72 65 61 64 + 0x212 | 01 1c 00 11 | core module name section + 0x216 | 03 | 3 count + 0x217 | 00 04 6c 69 | Naming { index: 0, name: "libc" } + | 62 63 + 0x21d | 01 05 43 48 | Naming { index: 1, name: "CHILD" } + | 49 4c 44 + 0x224 | 02 0a 56 49 | Naming { index: 2, name: "VIRTUALIZE" } + | 52 54 55 41 + | 4c 49 5a 45 + 0x230 | 01 1b 00 12 | core instance name section + 0x234 | 03 | 3 count + 0x235 | 00 04 6c 69 | Naming { index: 0, name: "libc" } + | 62 63 + 0x23b | 02 09 76 69 | Naming { index: 2, name: "virt-wasi" } + | 72 74 2d 77 + | 61 73 69 + 0x246 | 03 05 63 68 | Naming { index: 3, name: "child" } + | 69 6c 64 + 0x24d | 01 0c 03 | type name section + 0x250 | 01 | 1 count + 0x251 | 00 08 57 61 | Naming { index: 0, name: "WasiFile" } + | 73 69 46 69 + | 6c 65 + 0x25b | 01 0d 05 | instance name section + 0x25e | 01 | 1 count + 0x25f | 00 09 72 65 | Naming { index: 0, name: "real-wasi" } + | 61 6c 2d 77 + | 61 73 69 diff --git a/tests/dump/component-expand-bundle.wat b/tests/cli/dump/component-expand-bundle.wat similarity index 94% rename from tests/dump/component-expand-bundle.wat rename to tests/cli/dump/component-expand-bundle.wat index 3a6060aafa..aed8de5fb5 100644 --- a/tests/dump/component-expand-bundle.wat +++ b/tests/cli/dump/component-expand-bundle.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (component (core module $m (func (export "")) diff --git a/tests/cli/dump/component-expand-bundle.wat.stdout b/tests/cli/dump/component-expand-bundle.wat.stdout new file mode 100644 index 0000000000..a1a2b3f02f --- /dev/null +++ b/tests/cli/dump/component-expand-bundle.wat.stdout @@ -0,0 +1,68 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 01 29 | [core module 0] inline size + 0xa | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x12 | 01 04 | type section + 0x14 | 01 | 1 count + 0x15 | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0x18 | 03 02 | func section + 0x1a | 01 | 1 count + 0x1b | 00 | [func 0] type 0 + 0x1c | 07 04 | export section + 0x1e | 01 | 1 count + 0x1f | 00 00 00 | export Export { name: "", kind: Func, index: 0 } + 0x22 | 0a 04 | code section + 0x24 | 01 | 1 count +============== func 0 ==================== + 0x25 | 02 | size of function + 0x26 | 00 | 0 local blocks + 0x27 | 0b | end + 0x28 | 00 09 | custom section + 0x2a | 04 6e 61 6d | name: "name" + | 65 + 0x2f | 00 02 | module name + 0x31 | 01 6d | "m" + 0x33 | 01 22 | [core module 1] inline size + 0x35 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x3d | 01 04 | type section + 0x3f | 01 | 1 count + 0x40 | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0x43 | 02 06 | import section + 0x45 | 01 | 1 count + 0x46 | 00 01 61 00 | import [func 0] Import { module: "", name: "a", ty: Func(0) } + | 00 + 0x4b | 00 0a | custom section + 0x4d | 04 6e 61 6d | name: "name" + | 65 + 0x52 | 00 03 | module name + 0x54 | 02 6d 32 | "m2" + 0x57 | 02 04 | core instance section + 0x59 | 01 | 1 count + 0x5a | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } + 0x5d | 06 06 | component alias section + 0x5f | 01 | 1 count + 0x60 | 00 00 01 00 | alias [core func 0] CoreInstanceExport { kind: Func, instance_index: 0, name: "" } + | 00 + 0x65 | 02 0d | core instance section + 0x67 | 02 | 2 count + 0x68 | 01 01 01 61 | [core instance 1] FromExports([Export { name: "a", kind: Func, index: 0 }]) + | 00 00 + 0x6e | 00 01 01 00 | [core instance 2] Instantiate { module_index: 1, args: [InstantiationArg { name: "", kind: Instance, index: 1 }] } + | 12 01 + 0x74 | 00 2b | custom section + 0x76 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x85 | 01 06 00 00 | core func name section + 0x89 | 01 | 1 count + 0x8a | 00 01 66 | Naming { index: 0, name: "f" } + 0x8d | 01 0a 00 11 | core module name section + 0x91 | 02 | 2 count + 0x92 | 00 01 6d | Naming { index: 0, name: "m" } + 0x95 | 01 02 6d 32 | Naming { index: 1, name: "m2" } + 0x99 | 01 06 00 12 | core instance name section + 0x9d | 01 | 1 count + 0x9e | 00 01 4d | Naming { index: 0, name: "M" } diff --git a/tests/cli/dump/component-expand-bundle2.wat b/tests/cli/dump/component-expand-bundle2.wat new file mode 100644 index 0000000000..e5b5eb6205 --- /dev/null +++ b/tests/cli/dump/component-expand-bundle2.wat @@ -0,0 +1,13 @@ +;; RUN: dump % + +(component + (component $c + (core module (export "e")) + ) + (component $c2 (import "i" (component (import "i" (core module))))) + (instance $C (instantiate $c)) + (alias export $C "e" (core module $m)) + (instance (instantiate $c2 (with "i" (instance + (export "e" (core module $m)) + )))) +) diff --git a/tests/cli/dump/component-expand-bundle2.wat.stdout b/tests/cli/dump/component-expand-bundle2.wat.stdout new file mode 100644 index 0000000000..33d358ffa9 --- /dev/null +++ b/tests/cli/dump/component-expand-bundle2.wat.stdout @@ -0,0 +1,66 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 04 31 | [component 0] inline size + 0xa | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x12 | 01 08 | [core module 0] inline size + 0x14 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x1c | 0b 08 | component export section + 0x1e | 01 | 1 count + 0x1f | 00 01 65 00 | export ComponentExport { name: Kebab("e"), kind: Module, index: 0, ty: None } + | 11 00 00 + 0x26 | 00 13 | custom section + 0x28 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x37 | 00 02 | component name + 0x39 | 01 63 | "c" + 0x3b | 04 35 | [component 1] inline size + 0x3d | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x45 | 07 0d | component type section + 0x47 | 01 | 1 count + 0x48 | 41 02 00 50 | [type 0] Component([CoreType(Module([])), Import(ComponentImport { name: Kebab("i"), ty: Module(0) })]) + | 00 03 00 01 + | 69 00 11 00 + 0x54 | 0a 06 | component import section + 0x56 | 01 | 1 count + 0x57 | 00 01 69 04 | [component 0] ComponentImport { name: Kebab("i"), ty: Component(0) } + | 00 + 0x5c | 00 14 | custom section + 0x5e | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x6d | 00 03 | component name + 0x6f | 02 63 32 | "c2" + 0x72 | 05 04 | component instance section + 0x74 | 01 | 1 count + 0x75 | 00 00 00 | [instance 0] Instantiate { component_index: 0, args: [] } + 0x78 | 06 07 | component alias section + 0x7a | 01 | 1 count + 0x7b | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "e" } + | 01 65 + 0x81 | 05 10 | component instance section + 0x83 | 02 | 2 count + 0x84 | 01 01 00 01 | [instance 1] FromExports([ComponentExport { name: Kebab("e"), kind: Module, index: 0, ty: None }]) + | 65 00 11 00 + 0x8c | 00 01 01 01 | [instance 2] Instantiate { component_index: 1, args: [ComponentInstantiationArg { name: "i", kind: Instance, index: 1 }] } + | 69 05 01 + 0x93 | 00 29 | custom section + 0x95 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0xa4 | 01 06 00 11 | core module name section + 0xa8 | 01 | 1 count + 0xa9 | 00 01 6d | Naming { index: 0, name: "m" } + 0xac | 01 09 04 | component name section + 0xaf | 02 | 2 count + 0xb0 | 00 01 63 | Naming { index: 0, name: "c" } + 0xb3 | 01 02 63 32 | Naming { index: 1, name: "c2" } + 0xb7 | 01 05 05 | instance name section + 0xba | 01 | 1 count + 0xbb | 00 01 43 | Naming { index: 0, name: "C" } diff --git a/tests/dump/component-inline-export-import.wat b/tests/cli/dump/component-inline-export-import.wat similarity index 87% rename from tests/dump/component-inline-export-import.wat rename to tests/cli/dump/component-inline-export-import.wat index 542a5c5072..7a50540c72 100644 --- a/tests/dump/component-inline-export-import.wat +++ b/tests/cli/dump/component-inline-export-import.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (component (component (export "") diff --git a/tests/cli/dump/component-inline-export-import.wat.stdout b/tests/cli/dump/component-inline-export-import.wat.stdout new file mode 100644 index 0000000000..8ac44f5c23 --- /dev/null +++ b/tests/cli/dump/component-inline-export-import.wat.stdout @@ -0,0 +1,21 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 03 | component type section + 0xa | 01 | 1 count + 0xb | 41 00 | [type 0] Component([]) + 0xd | 0a 05 | component import section + 0xf | 01 | 1 count + 0x10 | 00 00 04 00 | [component 0] ComponentImport { name: Kebab(""), ty: Component(0) } + 0x14 | 03 03 | core type section + 0x16 | 01 | 1 count + 0x17 | 50 00 | [core type 0] Module([]) + 0x19 | 0a 07 | component import section + 0x1b | 01 | 1 count + 0x1c | 00 01 61 00 | [module 0] ComponentImport { name: Kebab("a"), ty: Module(0) } + | 11 00 + 0x22 | 0b 0d | component export section + 0x24 | 02 | 2 count + 0x25 | 00 00 04 00 | export ComponentExport { name: Kebab(""), kind: Component, index: 0, ty: None } + | 00 + 0x2a | 00 01 61 00 | export ComponentExport { name: Kebab("a"), kind: Module, index: 0, ty: None } + | 11 00 00 diff --git a/tests/cli/dump/component-inline-type.wat b/tests/cli/dump/component-inline-type.wat new file mode 100644 index 0000000000..f1d07350c5 --- /dev/null +++ b/tests/cli/dump/component-inline-type.wat @@ -0,0 +1,8 @@ +;; RUN: dump % + +(component + (import "a" (component)) + (import "b" (core module)) + (import "c" (instance)) + (import "d" (func)) +) diff --git a/tests/cli/dump/component-inline-type.wat.stdout b/tests/cli/dump/component-inline-type.wat.stdout new file mode 100644 index 0000000000..d6d55e5de9 --- /dev/null +++ b/tests/cli/dump/component-inline-type.wat.stdout @@ -0,0 +1,30 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 03 | component type section + 0xa | 01 | 1 count + 0xb | 41 00 | [type 0] Component([]) + 0xd | 0a 06 | component import section + 0xf | 01 | 1 count + 0x10 | 00 01 61 04 | [component 0] ComponentImport { name: Kebab("a"), ty: Component(0) } + | 00 + 0x15 | 03 03 | core type section + 0x17 | 01 | 1 count + 0x18 | 50 00 | [core type 0] Module([]) + 0x1a | 0a 07 | component import section + 0x1c | 01 | 1 count + 0x1d | 00 01 62 00 | [module 0] ComponentImport { name: Kebab("b"), ty: Module(0) } + | 11 00 + 0x23 | 07 03 | component type section + 0x25 | 01 | 1 count + 0x26 | 42 00 | [type 1] Instance([]) + 0x28 | 0a 06 | component import section + 0x2a | 01 | 1 count + 0x2b | 00 01 63 05 | [instance 0] ComponentImport { name: Kebab("c"), ty: Instance(1) } + | 01 + 0x30 | 07 05 | component type section + 0x32 | 01 | 1 count + 0x33 | 40 00 01 00 | [type 2] Func(ComponentFuncType { params: [], results: Named([]) }) + 0x37 | 0a 06 | component import section + 0x39 | 01 | 1 count + 0x3a | 00 01 64 01 | [func 0] ComponentImport { name: Kebab("d"), ty: Func(2) } + | 02 diff --git a/tests/dump/component-instance-type.wat b/tests/cli/dump/component-instance-type.wat similarity index 95% rename from tests/dump/component-instance-type.wat rename to tests/cli/dump/component-instance-type.wat index 01701ee1c5..26a4b20a20 100644 --- a/tests/dump/component-instance-type.wat +++ b/tests/cli/dump/component-instance-type.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + ;; instances (component (type $outer (instance diff --git a/tests/cli/dump/component-instance-type.wat.stdout b/tests/cli/dump/component-instance-type.wat.stdout new file mode 100644 index 0000000000..384d8f18be --- /dev/null +++ b/tests/cli/dump/component-instance-type.wat.stdout @@ -0,0 +1,23 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 28 | component type section + 0xa | 01 | 1 count + 0xb | 42 03 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], results: Named([]) })), Type(Component([Type(Func(ComponentFuncType { params: [], results: Named([]) })), Alias(Outer { kind: Type, count: 1, index: 0 }), Import(ComponentImport { name: Kebab("1"), ty: Func(0) }), Export { name: Kebab("1"), ty: Func(1) }])), Export { name: Kebab("c5"), ty: Component(1) }]) + | 00 01 00 01 + | 41 04 01 40 + | 00 01 00 02 + | 03 02 01 00 + | 03 00 01 31 + | 01 00 04 00 + | 01 31 01 01 + | 04 00 02 63 + | 35 04 01 + 0x32 | 00 1a | custom section + 0x34 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x43 | 01 09 03 | type name section + 0x46 | 01 | 1 count + 0x47 | 00 05 6f 75 | Naming { index: 0, name: "outer" } + | 74 65 72 diff --git a/tests/cli/dump/component-linking.wat b/tests/cli/dump/component-linking.wat new file mode 100644 index 0000000000..04376ef146 --- /dev/null +++ b/tests/cli/dump/component-linking.wat @@ -0,0 +1,27 @@ +;; RUN: dump % + +(component + (import "a" (instance $i + (export "a" (core module)) + (export "b" (func)) + (export "c" (value string)) + (export "d" (instance)) + (export "e" (component)) + )) + + (component $c + (import "a" (core module)) + (import "b" (func)) + (import "c" (value string)) + (import "d" (instance)) + (import "e" (component)) + ) + + (instance (instantiate $c + (with "a" (core module $i "a")) + (with "b" (func $i "b")) + (with "c" (value $i "c")) + (with "d" (instance $i "d")) + (with "e" (component $i "e")) + )) +) diff --git a/tests/cli/dump/component-linking.wat.stdout b/tests/cli/dump/component-linking.wat.stdout new file mode 100644 index 0000000000..70d09f8f0e --- /dev/null +++ b/tests/cli/dump/component-linking.wat.stdout @@ -0,0 +1,91 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 30 | component type section + 0xa | 01 | 1 count + 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: Kebab("a"), ty: Module(0) }, Type(Func(ComponentFuncType { params: [], results: Named([]) })), Export { name: Kebab("b"), ty: Func(0) }, Export { name: Kebab("c"), ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: Kebab("d"), ty: Instance(1) }, Type(Component([])), Export { name: Kebab("e"), ty: Component(2) }]) + | 00 04 00 01 + | 61 00 11 00 + | 01 40 00 01 + | 00 04 00 01 + | 62 01 00 04 + | 00 01 63 02 + | 73 01 42 00 + | 04 00 01 64 + | 05 01 01 41 + | 00 04 00 01 + | 65 04 02 + 0x3a | 0a 06 | component import section + 0x3c | 01 | 1 count + 0x3d | 00 01 61 05 | [instance 0] ComponentImport { name: Kebab("a"), ty: Instance(0) } + | 00 + 0x42 | 04 59 | [component 0] inline size + 0x44 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x4c | 03 03 | core type section + 0x4e | 01 | 1 count + 0x4f | 50 00 | [core type 0] Module([]) + 0x51 | 0a 07 | component import section + 0x53 | 01 | 1 count + 0x54 | 00 01 61 00 | [module 0] ComponentImport { name: Kebab("a"), ty: Module(0) } + | 11 00 + 0x5a | 07 05 | component type section + 0x5c | 01 | 1 count + 0x5d | 40 00 01 00 | [type 0] Func(ComponentFuncType { params: [], results: Named([]) }) + 0x61 | 0a 0b | component import section + 0x63 | 02 | 2 count + 0x64 | 00 01 62 01 | [func 0] ComponentImport { name: Kebab("b"), ty: Func(0) } + | 00 + 0x69 | 00 01 63 02 | [value 0] ComponentImport { name: Kebab("c"), ty: Value(Primitive(String)) } + | 73 + 0x6e | 07 03 | component type section + 0x70 | 01 | 1 count + 0x71 | 42 00 | [type 1] Instance([]) + 0x73 | 0a 06 | component import section + 0x75 | 01 | 1 count + 0x76 | 00 01 64 05 | [instance 0] ComponentImport { name: Kebab("d"), ty: Instance(1) } + | 01 + 0x7b | 07 03 | component type section + 0x7d | 01 | 1 count + 0x7e | 41 00 | [type 2] Component([]) + 0x80 | 0a 06 | component import section + 0x82 | 01 | 1 count + 0x83 | 00 01 65 04 | [component 0] ComponentImport { name: Kebab("e"), ty: Component(2) } + | 02 + 0x88 | 00 13 | custom section + 0x8a | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x99 | 00 02 | component name + 0x9b | 01 63 | "c" + 0x9d | 06 1b | component alias section + 0x9f | 05 | 5 count + 0xa0 | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "a" } + | 01 61 + 0xa6 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "b" } + | 62 + 0xab | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "c" } + | 63 + 0xb0 | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "d" } + | 64 + 0xb5 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "e" } + | 65 + 0xba | 05 19 | component instance section + 0xbc | 01 | 1 count + 0xbd | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "a", kind: Module, index: 0 }, ComponentInstantiationArg { name: "b", kind: Func, index: 0 }, ComponentInstantiationArg { name: "c", kind: Value, index: 0 }, ComponentInstantiationArg { name: "d", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "e", kind: Component, index: 1 }] } + | 61 00 11 00 + | 01 62 01 00 + | 01 63 02 00 + | 01 64 05 01 + | 01 65 04 01 + 0xd5 | 00 1d | custom section + 0xd7 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0xe6 | 01 05 04 | component name section + 0xe9 | 01 | 1 count + 0xea | 00 01 63 | Naming { index: 0, name: "c" } + 0xed | 01 05 05 | instance name section + 0xf0 | 01 | 1 count + 0xf1 | 00 01 69 | Naming { index: 0, name: "i" } diff --git a/tests/dump/component-outer-alias.wat b/tests/cli/dump/component-outer-alias.wat similarity index 95% rename from tests/dump/component-outer-alias.wat rename to tests/cli/dump/component-outer-alias.wat index 05bdf845fb..1097d878e2 100644 --- a/tests/dump/component-outer-alias.wat +++ b/tests/cli/dump/component-outer-alias.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (component (type $t string) diff --git a/tests/cli/dump/component-outer-alias.wat.stdout b/tests/cli/dump/component-outer-alias.wat.stdout new file mode 100644 index 0000000000..d78a1e984e --- /dev/null +++ b/tests/cli/dump/component-outer-alias.wat.stdout @@ -0,0 +1,73 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 0e | component type section + 0xa | 02 | 2 count + 0xb | 73 | [type 0] Defined(Primitive(String)) + 0xc | 41 02 02 03 | [type 1] Component([Alias(Outer { kind: Type, count: 1, index: 0 }), Type(Func(ComponentFuncType { params: [], results: Unnamed(Type(0)) }))]) + | 02 01 00 01 + | 40 00 00 00 + 0x18 | 04 2e | [component 0] inline size + 0x1a | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x22 | 06 05 | component alias section + 0x24 | 01 | 1 count + 0x25 | 03 02 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0x29 | 07 05 | component type section + 0x2b | 01 | 1 count + 0x2c | 40 00 00 00 | [type 1] Func(ComponentFuncType { params: [], results: Unnamed(Type(0)) }) + 0x30 | 00 16 | custom section + 0x32 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x41 | 01 05 03 | type name section + 0x44 | 01 | 1 count + 0x45 | 00 01 74 | Naming { index: 0, name: "t" } + 0x48 | 04 32 | [component 1] inline size + 0x4a | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x52 | 06 05 | component alias section + 0x54 | 01 | 1 count + 0x55 | 03 02 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0x59 | 07 09 | component type section + 0x5b | 02 | 2 count + 0x5c | 40 00 00 00 | [type 1] Func(ComponentFuncType { params: [], results: Unnamed(Type(0)) }) + 0x60 | 40 00 00 00 | [type 2] Func(ComponentFuncType { params: [], results: Unnamed(Type(0)) }) + 0x64 | 00 16 | custom section + 0x66 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x75 | 01 05 03 | type name section + 0x78 | 01 | 1 count + 0x79 | 00 01 74 | Naming { index: 0, name: "t" } + 0x7c | 07 02 | component type section + 0x7e | 01 | 1 count + 0x7f | 7d | [type 2] Defined(Primitive(U8)) + 0x80 | 04 33 | [component 2] inline size + 0x82 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8a | 06 05 | component alias section + 0x8c | 01 | 1 count + 0x8d | 03 02 01 02 | alias [type 0] Outer { kind: Type, count: 1, index: 2 } + 0x91 | 07 09 | component type section + 0x93 | 02 | 2 count + 0x94 | 40 00 00 00 | [type 1] Func(ComponentFuncType { params: [], results: Unnamed(Type(0)) }) + 0x98 | 40 00 00 00 | [type 2] Func(ComponentFuncType { params: [], results: Unnamed(Type(0)) }) + 0x9c | 00 17 | custom section + 0x9e | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0xad | 01 06 03 | type name section + 0xb0 | 01 | 1 count + 0xb1 | 00 02 74 32 | Naming { index: 0, name: "t2" } + 0xb5 | 00 1a | custom section + 0xb7 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0xc6 | 01 09 03 | type name section + 0xc9 | 02 | 2 count + 0xca | 00 01 74 | Naming { index: 0, name: "t" } + 0xcd | 02 02 74 32 | Naming { index: 2, name: "t2" } diff --git a/tests/cli/dump/import-modules.wat b/tests/cli/dump/import-modules.wat new file mode 100644 index 0000000000..3ea1175fbb --- /dev/null +++ b/tests/cli/dump/import-modules.wat @@ -0,0 +1,12 @@ +;; RUN: dump % + +(component + (import "a" (core module $m1 + (import "" "f" (func)) + )) + (core module $m2 + (func (export "f")) + ) + (core instance $i1 (instantiate $m2)) + (core instance $i2 (instantiate $m1 (with "a" (instance $i1)))) +) diff --git a/tests/cli/dump/import-modules.wat.stdout b/tests/cli/dump/import-modules.wat.stdout new file mode 100644 index 0000000000..7609dbc7db --- /dev/null +++ b/tests/cli/dump/import-modules.wat.stdout @@ -0,0 +1,52 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 03 0d | core type section + 0xa | 01 | 1 count + 0xb | 50 02 01 60 | [core type 0] Module([Type(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }), Import(Import { module: "", name: "f", ty: Func(0) })]) + | 00 00 00 00 + | 01 66 00 00 + 0x17 | 0a 07 | component import section + 0x19 | 01 | 1 count + 0x1a | 00 01 61 00 | [module 0] ComponentImport { name: Kebab("a"), ty: Module(0) } + | 11 00 + 0x20 | 01 2b | [core module 1] inline size + 0x22 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x2a | 01 04 | type section + 0x2c | 01 | 1 count + 0x2d | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0x30 | 03 02 | func section + 0x32 | 01 | 1 count + 0x33 | 00 | [func 0] type 0 + 0x34 | 07 05 | export section + 0x36 | 01 | 1 count + 0x37 | 01 66 00 00 | export Export { name: "f", kind: Func, index: 0 } + 0x3b | 0a 04 | code section + 0x3d | 01 | 1 count +============== func 0 ==================== + 0x3e | 02 | size of function + 0x3f | 00 | 0 local blocks + 0x40 | 0b | end + 0x41 | 00 0a | custom section + 0x43 | 04 6e 61 6d | name: "name" + | 65 + 0x48 | 00 03 | module name + 0x4a | 02 6d 32 | "m2" + 0x4d | 02 0b | core instance section + 0x4f | 02 | 2 count + 0x50 | 00 01 00 | [core instance 0] Instantiate { module_index: 1, args: [] } + 0x53 | 00 00 01 01 | [core instance 1] Instantiate { module_index: 0, args: [InstantiationArg { name: "a", kind: Instance, index: 0 }] } + | 61 12 00 + 0x5a | 00 29 | custom section + 0x5c | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x6b | 01 0b 00 11 | core module name section + 0x6f | 02 | 2 count + 0x70 | 00 02 6d 31 | Naming { index: 0, name: "m1" } + 0x74 | 01 02 6d 32 | Naming { index: 1, name: "m2" } + 0x78 | 01 0b 00 12 | core instance name section + 0x7c | 02 | 2 count + 0x7d | 00 02 69 31 | Naming { index: 0, name: "i1" } + 0x81 | 01 02 69 32 | Naming { index: 1, name: "i2" } diff --git a/tests/cli/dump/instance-expand.wat b/tests/cli/dump/instance-expand.wat new file mode 100644 index 0000000000..2402fc3967 --- /dev/null +++ b/tests/cli/dump/instance-expand.wat @@ -0,0 +1,9 @@ +;; RUN: dump % + +(component + (type $i (instance + (export "" (func)) + )) + + (import "a" (instance (type $i))) +) diff --git a/tests/cli/dump/instance-expand.wat.stdout b/tests/cli/dump/instance-expand.wat.stdout new file mode 100644 index 0000000000..eccb9aad13 --- /dev/null +++ b/tests/cli/dump/instance-expand.wat.stdout @@ -0,0 +1,19 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 0d | component type section + 0xa | 01 | 1 count + 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], results: Named([]) })), Export { name: Kebab(""), ty: Func(0) }]) + | 00 01 00 04 + | 00 00 01 00 + 0x17 | 0a 06 | component import section + 0x19 | 01 | 1 count + 0x1a | 00 01 61 05 | [instance 0] ComponentImport { name: Kebab("a"), ty: Instance(0) } + | 00 + 0x1f | 00 16 | custom section + 0x21 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x30 | 01 05 03 | type name section + 0x33 | 01 | 1 count + 0x34 | 00 01 69 | Naming { index: 0, name: "i" } diff --git a/tests/dump/instance-type.wat b/tests/cli/dump/instance-type.wat similarity index 86% rename from tests/dump/instance-type.wat rename to tests/cli/dump/instance-type.wat index 20b7c334a5..881a0ecc75 100644 --- a/tests/dump/instance-type.wat +++ b/tests/cli/dump/instance-type.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (component (type (instance (export "" (func)) diff --git a/tests/cli/dump/instance-type.wat.stdout b/tests/cli/dump/instance-type.wat.stdout new file mode 100644 index 0000000000..98c33d3fe7 --- /dev/null +++ b/tests/cli/dump/instance-type.wat.stdout @@ -0,0 +1,10 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 17 | component type section + 0xa | 02 | 2 count + 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], results: Named([]) })), Export { name: Kebab(""), ty: Func(0) }]) + | 00 01 00 04 + | 00 00 01 00 + 0x17 | 42 02 01 42 | [type 1] Instance([Type(Instance([])), Export { name: Kebab(""), ty: Instance(0) }]) + | 00 04 00 00 + | 05 00 diff --git a/tests/dump/instance-type2.wat b/tests/cli/dump/instance-type2.wat similarity index 90% rename from tests/dump/instance-type2.wat rename to tests/cli/dump/instance-type2.wat index 53a3b338f7..eaf1731fb1 100644 --- a/tests/dump/instance-type2.wat +++ b/tests/cli/dump/instance-type2.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (component (type (instance)) (type (instance (export "" (instance (type 0))))) diff --git a/tests/cli/dump/instance-type2.wat.stdout b/tests/cli/dump/instance-type2.wat.stdout new file mode 100644 index 0000000000..6504991acc --- /dev/null +++ b/tests/cli/dump/instance-type2.wat.stdout @@ -0,0 +1,19 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 18 | component type section + 0xa | 04 | 4 count + 0xb | 42 00 | [type 0] Instance([]) + 0xd | 42 01 04 00 | [type 1] Instance([Export { name: Kebab(""), ty: Instance(0) }]) + | 00 05 00 + 0x14 | 42 00 | [type 2] Instance([]) + 0x16 | 42 02 02 03 | [type 3] Instance([Alias(Outer { kind: Type, count: 1, index: 2 }), Export { name: Kebab(""), ty: Instance(0) }]) + | 02 01 02 04 + | 00 00 05 00 + 0x22 | 00 16 | custom section + 0x24 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x33 | 01 05 03 | type name section + 0x36 | 01 | 1 count + 0x37 | 02 01 78 | Naming { index: 2, name: "x" } diff --git a/tests/dump/instantiate.wat b/tests/cli/dump/instantiate.wat similarity index 90% rename from tests/dump/instantiate.wat rename to tests/cli/dump/instantiate.wat index 89bb92cf3a..a6ccfbd53b 100644 --- a/tests/dump/instantiate.wat +++ b/tests/cli/dump/instantiate.wat @@ -1,3 +1,4 @@ +;; RUN: dump % (component (import "a" (component $c)) diff --git a/tests/cli/dump/instantiate.wat.stdout b/tests/cli/dump/instantiate.wat.stdout new file mode 100644 index 0000000000..c72f083c45 --- /dev/null +++ b/tests/cli/dump/instantiate.wat.stdout @@ -0,0 +1,34 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 03 | component type section + 0xa | 01 | 1 count + 0xb | 41 00 | [type 0] Component([]) + 0xd | 0a 06 | component import section + 0xf | 01 | 1 count + 0x10 | 00 01 61 04 | [component 0] ComponentImport { name: Kebab("a"), ty: Component(0) } + | 00 + 0x15 | 07 05 | component type section + 0x17 | 01 | 1 count + 0x18 | 40 00 01 00 | [type 1] Func(ComponentFuncType { params: [], results: Named([]) }) + 0x1c | 0a 06 | component import section + 0x1e | 01 | 1 count + 0x1f | 00 01 66 01 | [func 0] ComponentImport { name: Kebab("f"), ty: Func(1) } + | 01 + 0x24 | 05 08 | component instance section + 0x26 | 01 | 1 count + 0x27 | 00 00 01 01 | [instance 0] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "a", kind: Func, index: 0 }] } + | 61 01 00 + 0x2e | 00 24 | custom section + 0x30 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x3f | 01 05 01 | func name section + 0x42 | 01 | 1 count + 0x43 | 00 01 66 | Naming { index: 0, name: "f" } + 0x46 | 01 05 04 | component name section + 0x49 | 01 | 1 count + 0x4a | 00 01 63 | Naming { index: 0, name: "c" } + 0x4d | 01 05 05 | instance name section + 0x50 | 01 | 1 count + 0x51 | 00 01 61 | Naming { index: 0, name: "a" } diff --git a/tests/cli/dump/instantiate2.wat b/tests/cli/dump/instantiate2.wat new file mode 100644 index 0000000000..177798cc6d --- /dev/null +++ b/tests/cli/dump/instantiate2.wat @@ -0,0 +1,6 @@ +;; RUN: dump % + +(component + (import "a" (component $c (import "a" (func)))) + (instance (instantiate $c)) +) diff --git a/tests/cli/dump/instantiate2.wat.stdout b/tests/cli/dump/instantiate2.wat.stdout new file mode 100644 index 0000000000..7f0462c152 --- /dev/null +++ b/tests/cli/dump/instantiate2.wat.stdout @@ -0,0 +1,23 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 0e | component type section + 0xa | 01 | 1 count + 0xb | 41 02 01 40 | [type 0] Component([Type(Func(ComponentFuncType { params: [], results: Named([]) })), Import(ComponentImport { name: Kebab("a"), ty: Func(0) })]) + | 00 01 00 03 + | 00 01 61 01 + | 00 + 0x18 | 0a 06 | component import section + 0x1a | 01 | 1 count + 0x1b | 00 01 61 04 | [component 0] ComponentImport { name: Kebab("a"), ty: Component(0) } + | 00 + 0x20 | 05 04 | component instance section + 0x22 | 01 | 1 count + 0x23 | 00 00 00 | [instance 0] Instantiate { component_index: 0, args: [] } + 0x26 | 00 16 | custom section + 0x28 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x37 | 01 05 04 | component name section + 0x3a | 01 | 1 count + 0x3b | 00 01 63 | Naming { index: 0, name: "c" } diff --git a/tests/dump/module-types.wat b/tests/cli/dump/module-types.wat similarity index 79% rename from tests/dump/module-types.wat rename to tests/cli/dump/module-types.wat index e16c11a3a8..a25b69e312 100644 --- a/tests/dump/module-types.wat +++ b/tests/cli/dump/module-types.wat @@ -1,5 +1,7 @@ +;; RUN: dump % + (component - (import "" (core module $m + (import "a" (core module $m (import "" "f" (func)) (import "" "g" (global i32)) (import "" "t" (table 1 funcref)) diff --git a/tests/cli/dump/module-types.wat.stdout b/tests/cli/dump/module-types.wat.stdout new file mode 100644 index 0000000000..e4fbcbe681 --- /dev/null +++ b/tests/cli/dump/module-types.wat.stdout @@ -0,0 +1,32 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 03 23 | core type section + 0xa | 01 | 1 count + 0xb | 50 05 01 60 | [core type 0] Module([Type(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }), Import(Import { module: "", name: "f", ty: Func(0) }), Import(Import { module: "", name: "g", ty: Global(GlobalType { content_type: I32, mutable: false }) }), Import(Import { module: "", name: "t", ty: Table(TableType { element_type: funcref, initial: 1, maximum: None }) }), Import(Import { module: "", name: "m", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) })]) + | 00 00 00 00 + | 01 66 00 00 + | 00 00 01 67 + | 03 7f 00 00 + | 00 01 74 01 + | 70 00 01 00 + | 00 01 6d 02 + | 00 01 + 0x2d | 0a 07 | component import section + 0x2f | 01 | 1 count + 0x30 | 00 01 61 00 | [module 0] ComponentImport { name: Kebab("a"), ty: Module(0) } + | 11 00 + 0x36 | 07 03 | component type section + 0x38 | 01 | 1 count + 0x39 | 42 00 | [type 0] Instance([]) + 0x3b | 00 22 | custom section + 0x3d | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0x4c | 01 06 00 11 | core module name section + 0x50 | 01 | 1 count + 0x51 | 00 01 6d | Naming { index: 0, name: "m" } + 0x54 | 01 09 03 | type name section + 0x57 | 01 | 1 count + 0x58 | 00 05 65 6d | Naming { index: 0, name: "empty" } + | 70 74 79 diff --git a/tests/dump/names.wat b/tests/cli/dump/names.wat similarity index 79% rename from tests/dump/names.wat rename to tests/cli/dump/names.wat index 64fc40dd5f..147dd58017 100644 --- a/tests/dump/names.wat +++ b/tests/cli/dump/names.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (module $foo (func $f (param $x i32) (local $y f64))) diff --git a/tests/cli/dump/names.wat.stdout b/tests/cli/dump/names.wat.stdout new file mode 100644 index 0000000000..35981448f4 --- /dev/null +++ b/tests/cli/dump/names.wat.stdout @@ -0,0 +1,29 @@ + 0x0 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x8 | 01 05 | type section + 0xa | 01 | 1 count + 0xb | 60 01 7f 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32], returns: [] }) }) + 0xf | 03 02 | func section + 0x11 | 01 | 1 count + 0x12 | 00 | [func 0] type 0 + 0x13 | 0a 06 | code section + 0x15 | 01 | 1 count +============== func 0 ==================== + 0x16 | 04 | size of function + 0x17 | 01 | 1 local blocks + 0x18 | 01 7c | 1 locals of type F64 + 0x1a | 0b | end + 0x1b | 00 1c | custom section + 0x1d | 04 6e 61 6d | name: "name" + | 65 + 0x22 | 00 04 | module name + 0x24 | 03 66 6f 6f | "foo" + 0x28 | 01 04 | function name section + 0x2a | 01 | 1 count + 0x2b | 00 01 66 | Naming { index: 0, name: "f" } + 0x2e | 02 09 | local section + 0x30 | 01 | 1 count + 0x31 | 00 | function 0 local name section + 0x32 | 02 | 2 count + 0x33 | 00 01 78 | Naming { index: 0, name: "x" } + 0x36 | 01 01 79 | Naming { index: 1, name: "y" } diff --git a/tests/cli/dump/nested-component.wat b/tests/cli/dump/nested-component.wat new file mode 100644 index 0000000000..3df4d9c518 --- /dev/null +++ b/tests/cli/dump/nested-component.wat @@ -0,0 +1,24 @@ +;; RUN: dump % + +(component + (component (import "a")) + + (component) + (component) + + (component (export "a")) + + (component + (component) + ) + + (component + (core module $m) + (import "a" (func (param "p" string))) + (export "a" (core module $m)) + + (instance (export "b") (import "b") + (export "a" (func)) + ) + ) +) diff --git a/tests/cli/dump/nested-component.wat.stdout b/tests/cli/dump/nested-component.wat.stdout new file mode 100644 index 0000000000..f06093dbca --- /dev/null +++ b/tests/cli/dump/nested-component.wat.stdout @@ -0,0 +1,73 @@ + 0x0 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x8 | 07 03 | component type section + 0xa | 01 | 1 count + 0xb | 41 00 | [type 0] Component([]) + 0xd | 0a 06 | component import section + 0xf | 01 | 1 count + 0x10 | 00 01 61 04 | [component 0] ComponentImport { name: Kebab("a"), ty: Component(0) } + | 00 + 0x15 | 04 08 | [component 1] inline size + 0x17 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x1f | 04 08 | [component 2] inline size + 0x21 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x29 | 04 08 | [component 3] inline size + 0x2b | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x33 | 04 12 | [component 4] inline size + 0x35 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x3d | 04 08 | [component 0] inline size + 0x3f | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x47 | 04 73 | [component 5] inline size + 0x49 | 00 61 73 6d | version 13 (Component) + | 0d 00 01 00 + 0x51 | 01 13 | [core module 0] inline size + 0x53 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x5b | 00 09 | custom section + 0x5d | 04 6e 61 6d | name: "name" + | 65 + 0x62 | 00 02 | module name + 0x64 | 01 6d | "m" + 0x66 | 07 08 | component type section + 0x68 | 01 | 1 count + 0x69 | 40 01 01 70 | [type 0] Func(ComponentFuncType { params: [("p", Primitive(String))], results: Named([]) }) + | 73 01 00 + 0x70 | 0a 06 | component import section + 0x72 | 01 | 1 count + 0x73 | 00 01 61 01 | [func 0] ComponentImport { name: Kebab("a"), ty: Func(0) } + | 00 + 0x78 | 0b 08 | component export section + 0x7a | 01 | 1 count + 0x7b | 00 01 61 00 | export ComponentExport { name: Kebab("a"), kind: Module, index: 0, ty: None } + | 11 00 00 + 0x82 | 07 0e | component type section + 0x84 | 01 | 1 count + 0x85 | 42 02 01 40 | [type 1] Instance([Type(Func(ComponentFuncType { params: [], results: Named([]) })), Export { name: Kebab("a"), ty: Func(0) }]) + | 00 01 00 04 + | 00 01 61 01 + | 00 + 0x92 | 0a 06 | component import section + 0x94 | 01 | 1 count + 0x95 | 00 01 62 05 | [instance 0] ComponentImport { name: Kebab("b"), ty: Instance(1) } + | 01 + 0x9a | 0b 07 | component export section + 0x9c | 01 | 1 count + 0x9d | 00 01 62 05 | export ComponentExport { name: Kebab("b"), kind: Instance, index: 0, ty: None } + | 00 00 + 0xa3 | 00 17 | custom section + 0xa5 | 0e 63 6f 6d | name: "component-name" + | 70 6f 6e 65 + | 6e 74 2d 6e + | 61 6d 65 + 0xb4 | 01 06 00 11 | core module name section + 0xb8 | 01 | 1 count + 0xb9 | 00 01 6d | Naming { index: 0, name: "m" } + 0xbc | 0b 07 | component export section + 0xbe | 01 | 1 count + 0xbf | 00 01 61 04 | export ComponentExport { name: Kebab("a"), kind: Component, index: 3, ty: None } + | 03 00 diff --git a/tests/dump/select.wat b/tests/cli/dump/select.wat similarity index 88% rename from tests/dump/select.wat rename to tests/cli/dump/select.wat index b18a2b47af..c72d8625c7 100644 --- a/tests/dump/select.wat +++ b/tests/cli/dump/select.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (module (func select diff --git a/tests/cli/dump/select.wat.stdout b/tests/cli/dump/select.wat.stdout new file mode 100644 index 0000000000..07d338db27 --- /dev/null +++ b/tests/cli/dump/select.wat.stdout @@ -0,0 +1,20 @@ + 0x0 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x8 | 01 04 | type section + 0xa | 01 | 1 count + 0xb | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0xe | 03 02 | func section + 0x10 | 01 | 1 count + 0x11 | 00 | [func 0] type 0 + 0x12 | 0a 0e | code section + 0x14 | 01 | 1 count +============== func 0 ==================== + 0x15 | 0c | size of function + 0x16 | 00 | 0 local blocks + 0x17 | 1b | select + 0x18 | 1c 00 | ?? + 0x1a | 1c 01 7f | typed_select ty:I32 + 0x1d | 1c 02 | ?? + 0x1f | 7f | i64_div_s + 0x20 | 7f | i64_div_s + 0x21 | 0b | end diff --git a/tests/dump/simple.wat b/tests/cli/dump/simple.wat similarity index 82% rename from tests/dump/simple.wat rename to tests/cli/dump/simple.wat index 2145dd0418..a4906efd27 100644 --- a/tests/dump/simple.wat +++ b/tests/cli/dump/simple.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (module (import "m" "n" (func (param i32))) (table 1 funcref) @@ -5,8 +7,8 @@ (start 0) (global i32 (i32.const 0)) (elem (i32.const 3) 0) - (elem funcref 0) - (elem declare funcref 0) + (elem funcref (ref.null func)) + (elem declare funcref (ref.null func)) ;;(elem (i32.const 3) (ref.null func)) ;;(elem funcref (ref.null func)) ;;(elem declare funcref (ref.null func) (ref.func 0)) diff --git a/tests/cli/dump/simple.wat.stdout b/tests/cli/dump/simple.wat.stdout new file mode 100644 index 0000000000..12c36351a4 --- /dev/null +++ b/tests/cli/dump/simple.wat.stdout @@ -0,0 +1,73 @@ + 0x0 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x8 | 01 08 | type section + 0xa | 02 | 2 count + 0xb | 60 01 7f 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [I32], returns: [] }) }) + 0xf | 60 00 00 | [type 1] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0x12 | 02 07 | import section + 0x14 | 01 | 1 count + 0x15 | 01 6d 01 6e | import [func 0] Import { module: "m", name: "n", ty: Func(0) } + | 00 00 + 0x1b | 03 04 | func section + 0x1d | 03 | 3 count + 0x1e | 01 | [func 1] type 1 + 0x1f | 01 | [func 2] type 1 + 0x20 | 01 | [func 3] type 1 + 0x21 | 04 04 | table section + 0x23 | 01 | 1 count + 0x24 | 70 00 01 | [table 0] Table { ty: TableType { element_type: funcref, initial: 1, maximum: None }, init: RefNull } + 0x27 | 05 03 | memory section + 0x29 | 01 | 1 count + 0x2a | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None } + 0x2c | 06 06 | global section + 0x2e | 01 | 1 count + 0x2f | 7f 00 | [global 0] GlobalType { content_type: I32, mutable: false } + 0x31 | 41 00 | i32_const value:0 + 0x33 | 0b | end + 0x34 | 07 05 | export section + 0x36 | 01 | 1 count + 0x37 | 01 6d 02 00 | export Export { name: "m", kind: Memory, index: 0 } + 0x3b | 08 01 | start section + 0x3d | 00 | start function 0 + 0x3e | 09 13 | element section + 0x40 | 03 | 3 count + 0x41 | 00 | element table[None] + 0x42 | 41 03 | i32_const value:3 + 0x44 | 0b | end + 0x45 | 01 | 1 items [indices] + 0x46 | 00 | item 0 + 0x47 | 05 70 01 | element passive, 1 items [exprs funcref] + 0x4a | d0 70 0b | item ConstExpr { offset: 74, data: [208, 112, 11] } + 0x4d | 07 70 01 | element declared 1 items [exprs funcref] + 0x50 | d0 70 0b | item ConstExpr { offset: 80, data: [208, 112, 11] } + 0x53 | 0a 10 | code section + 0x55 | 03 | 3 count +============== func 1 ==================== + 0x56 | 02 | size of function + 0x57 | 00 | 0 local blocks + 0x58 | 0b | end +============== func 2 ==================== + 0x59 | 04 | size of function + 0x5a | 01 | 1 local blocks + 0x5b | 01 7f | 1 locals of type I32 + 0x5d | 0b | end +============== func 3 ==================== + 0x5e | 06 | size of function + 0x5f | 01 | 1 local blocks + 0x60 | 01 7f | 1 locals of type I32 + 0x62 | 41 00 | i32_const value:0 + 0x64 | 0b | end + 0x65 | 0b 0a | data section + 0x67 | 02 | 2 count + 0x68 | 00 | data memory[0] + 0x69 | 41 08 | i32_const value:8 + 0x6b | 0b | end + 0x6c |-------------| ... 1 bytes of data + 0x6e | 01 01 | data passive + 0x70 |-------------| ... 1 bytes of data + 0x71 | 00 17 | custom section + 0x73 | 0f 6e 61 6d | name: "name-of-section" + | 65 2d 6f 66 + | 2d 73 65 63 + | 74 69 6f 6e + 0x83 |-------------| ... 7 bytes of data diff --git a/tests/dump/try-delegate.wat b/tests/cli/dump/try-delegate.wat similarity index 81% rename from tests/dump/try-delegate.wat rename to tests/cli/dump/try-delegate.wat index 9b8c7f89c8..85738bafb8 100644 --- a/tests/dump/try-delegate.wat +++ b/tests/cli/dump/try-delegate.wat @@ -1,3 +1,5 @@ +;; RUN: dump % + (module (func try $l diff --git a/tests/cli/dump/try-delegate.wat.stdout b/tests/cli/dump/try-delegate.wat.stdout new file mode 100644 index 0000000000..bb0255f19d --- /dev/null +++ b/tests/cli/dump/try-delegate.wat.stdout @@ -0,0 +1,26 @@ + 0x0 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x8 | 01 04 | type section + 0xa | 01 | 1 count + 0xb | 60 00 00 | [type 0] Single(SubType { is_final: true, supertype_idx: None, structural_type: Func(FuncType { params: [], returns: [] }) }) + 0xe | 03 02 | func section + 0x10 | 01 | 1 count + 0x11 | 00 | [func 0] type 0 + 0x12 | 0a 0b | code section + 0x14 | 01 | 1 count +============== func 0 ==================== + 0x15 | 09 | size of function + 0x16 | 00 | 0 local blocks + 0x17 | 06 40 | try blockty:Empty + 0x19 | 06 40 | try blockty:Empty + 0x1b | 18 00 | delegate relative_depth:0 + 0x1d | 0b | end + 0x1e | 0b | end + 0x1f | 00 0d | custom section + 0x21 | 04 6e 61 6d | name: "name" + | 65 + 0x26 | 03 06 | label section + 0x28 | 01 | 1 count + 0x29 | 00 | function 0 label name section + 0x2a | 01 | 1 count + 0x2b | 00 01 6c | Naming { index: 0, name: "l" } diff --git a/tests/cli/metadata-add-component.wat b/tests/cli/metadata-add-component.wat new file mode 100644 index 0000000000..b7ba818bc4 --- /dev/null +++ b/tests/cli/metadata-add-component.wat @@ -0,0 +1,6 @@ +;; RUN: metadata add --language foo % | metadata show +(component $foo + (core module + (func $foo) + ) +) diff --git a/tests/cli/metadata-add-component.wat.stdout b/tests/cli/metadata-add-component.wat.stdout new file mode 100644 index 0000000000..d98df53e54 --- /dev/null +++ b/tests/cli/metadata-add-component.wat.stdout @@ -0,0 +1,4 @@ +component foo: + language: + foo + module: diff --git a/tests/cli/metadata-component.wat b/tests/cli/metadata-component.wat new file mode 100644 index 0000000000..fafc84fd04 --- /dev/null +++ b/tests/cli/metadata-component.wat @@ -0,0 +1,6 @@ +;; RUN: metadata show % +(component $my-name + (core module $submodule) + + (core module (@name "another submodule")) +) diff --git a/tests/cli/metadata-component.wat.stdout b/tests/cli/metadata-component.wat.stdout new file mode 100644 index 0000000000..b96562a443 --- /dev/null +++ b/tests/cli/metadata-component.wat.stdout @@ -0,0 +1,3 @@ +component my-name: + module submodule: + module another submodule: diff --git a/tests/cli/metadata.wat b/tests/cli/metadata.wat new file mode 100644 index 0000000000..a979f4b0f6 --- /dev/null +++ b/tests/cli/metadata.wat @@ -0,0 +1,2 @@ +;; RUN: metadata show % +(module) diff --git a/tests/cli/metadata.wat.stdout b/tests/cli/metadata.wat.stdout new file mode 100644 index 0000000000..71d91c1359 --- /dev/null +++ b/tests/cli/metadata.wat.stdout @@ -0,0 +1 @@ +module: diff --git a/tests/cli/objdump-simple.wat b/tests/cli/objdump-simple.wat new file mode 100644 index 0000000000..3217793658 --- /dev/null +++ b/tests/cli/objdump-simple.wat @@ -0,0 +1,7 @@ +;; RUN: objdump % + +(module + (func) + + (@custom "x" "....") +) diff --git a/tests/cli/objdump-simple.wat.stdout b/tests/cli/objdump-simple.wat.stdout new file mode 100644 index 0000000000..f8efbd63e6 --- /dev/null +++ b/tests/cli/objdump-simple.wat.stdout @@ -0,0 +1,4 @@ + types | 0xa - 0xe | 4 bytes | 1 count + functions | 0x10 - 0x12 | 2 bytes | 1 count + code | 0x14 - 0x18 | 4 bytes | 1 count + custom "x" | 0x1c - 0x20 | 4 bytes | 1 count diff --git a/tests/cli/print-core-wasm-wit.wit b/tests/cli/print-core-wasm-wit.wit new file mode 100644 index 0000000000..54953e49f7 --- /dev/null +++ b/tests/cli/print-core-wasm-wit.wit @@ -0,0 +1,11 @@ +// RUN: component embed --dummy % | component wit + +package foo:foo; + +interface my-interface { + foo: func(); +} + +world my-world { + import my-interface; +} diff --git a/tests/cli/print-core-wasm-wit.wit.stdout b/tests/cli/print-core-wasm-wit.wit.stdout new file mode 100644 index 0000000000..e5a97071d8 --- /dev/null +++ b/tests/cli/print-core-wasm-wit.wit.stdout @@ -0,0 +1,5 @@ +package root:root + +world root { + import foo:foo/my-interface +} diff --git a/tests/cli/print-skeleton.wat b/tests/cli/print-skeleton.wat new file mode 100644 index 0000000000..809615cf76 --- /dev/null +++ b/tests/cli/print-skeleton.wat @@ -0,0 +1,9 @@ +;; RUN: print --skeleton % + +(module + (memory 0) + (func $f unreachable) + (data (i32.const 0) "1234") + (table 1 funcref) + (elem (i32.const 0) func $f) +) diff --git a/tests/cli/print-skeleton.wat.stdout b/tests/cli/print-skeleton.wat.stdout new file mode 100644 index 0000000000..2f1da14a33 --- /dev/null +++ b/tests/cli/print-skeleton.wat.stdout @@ -0,0 +1,8 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0) ...) + (table (;0;) 1 funcref) + (memory (;0;) 0) + (elem (;0;) (i32.const 0) ...) + (data (;0;) (i32.const 0) ...) +) \ No newline at end of file diff --git a/tests/cli/strip-component.wat b/tests/cli/strip-component.wat new file mode 100644 index 0000000000..5846000591 --- /dev/null +++ b/tests/cli/strip-component.wat @@ -0,0 +1,6 @@ +;; RUN: strip % -t -a +(component $the-component + (core module + (func $foo) + ) +) diff --git a/tests/cli/strip-component.wat.stdout b/tests/cli/strip-component.wat.stdout new file mode 100644 index 0000000000..75039da663 --- /dev/null +++ b/tests/cli/strip-component.wat.stdout @@ -0,0 +1,6 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (func (;0;) (type 0)) + ) +) \ No newline at end of file diff --git a/tests/cli/strip-simple.wat b/tests/cli/strip-simple.wat new file mode 100644 index 0000000000..77feda29bc --- /dev/null +++ b/tests/cli/strip-simple.wat @@ -0,0 +1,5 @@ +;; RUN: strip -a % -t + +(module + (func $foo) +) diff --git a/tests/cli/strip-simple.wat.stdout b/tests/cli/strip-simple.wat.stdout new file mode 100644 index 0000000000..f81d636a1b --- /dev/null +++ b/tests/cli/strip-simple.wat.stdout @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/cli/strip-simple2.wat b/tests/cli/strip-simple2.wat new file mode 100644 index 0000000000..dd685e9392 --- /dev/null +++ b/tests/cli/strip-simple2.wat @@ -0,0 +1,7 @@ +;; RUN: strip % -t + +(module + (func $foo) + + (@custom "foo" "...") +) diff --git a/tests/cli/strip-simple2.wat.stdout b/tests/cli/strip-simple2.wat.stdout new file mode 100644 index 0000000000..cef3e38f90 --- /dev/null +++ b/tests/cli/strip-simple2.wat.stdout @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func $foo (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/cli/strip-then-objdump.wat b/tests/cli/strip-then-objdump.wat new file mode 100644 index 0000000000..af9af0a455 --- /dev/null +++ b/tests/cli/strip-then-objdump.wat @@ -0,0 +1,7 @@ +;; RUN: strip % | objdump + +(module + (func $name) + + (@custom "some-custom" "hello") +) diff --git a/tests/cli/strip-then-objdump.wat.stdout b/tests/cli/strip-then-objdump.wat.stdout new file mode 100644 index 0000000000..d5df8f3fc0 --- /dev/null +++ b/tests/cli/strip-then-objdump.wat.stdout @@ -0,0 +1,4 @@ + types | 0xa - 0xe | 4 bytes | 1 count + functions | 0x10 - 0x12 | 2 bytes | 1 count + code | 0x14 - 0x18 | 4 bytes | 1 count + custom "name" | 0x1f - 0x28 | 9 bytes | 1 count diff --git a/tests/dump.rs b/tests/dump.rs deleted file mode 100644 index 2136cef34e..0000000000 --- a/tests/dump.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! A test suite to parse everything in `dump` and assert that it matches -//! the `*.dump` file it generates. -//! -//! Use `BLESS=1` in the environment to auto-update `*.err` files. Be sure to -//! look at the diff! - -use anyhow::{bail, Context, Result}; -use rayon::prelude::*; -use std::env; -use std::path::{Path, PathBuf}; - -fn main() { - let mut tests = Vec::new(); - find_tests("tests/dump".as_ref(), &mut tests); - let filter = std::env::args().nth(1); - - let bless = env::var("BLESS").is_ok(); - let tests = tests - .iter() - .filter(|test| { - if let Some(filter) = &filter { - if let Some(s) = test.file_name().and_then(|s| s.to_str()) { - if !s.contains(filter) { - return false; - } - } - } - true - }) - .collect::>(); - - println!("running {} tests\n", tests.len()); - - let errors = tests - .par_iter() - .filter_map(|test| run_test(test, bless).err()) - .collect::>(); - - if !errors.is_empty() { - for msg in errors.iter() { - eprintln!("{:?}", msg); - } - - panic!("{} tests failed", errors.len()) - } - - println!("test result: ok. {} passed\n", tests.len()); -} - -fn run_test(test: &Path, bless: bool) -> Result<()> { - let wasm = wat::parse_file(test)?; - let assert = test.with_extension("wat.dump"); - let dump = - wasmparser_dump::dump_wasm(&wasm).with_context(|| format!("failed to dump {:?}", test))?; - if bless { - std::fs::write(assert, &dump)?; - return Ok(()); - } - - // Ignore CRLF line ending and force always `\n` - let assert = std::fs::read_to_string(assert) - .unwrap_or(String::new()) - .replace("\r\n", "\n"); - - let mut bad = false; - let mut result = String::new(); - for diff in diff::lines(&assert, &dump) { - match diff { - diff::Result::Left(s) => { - bad = true; - result.push_str("-"); - result.push_str(s); - } - diff::Result::Right(s) => { - bad = true; - result.push_str("+"); - result.push_str(s); - } - diff::Result::Both(s, _) => { - result.push_str(" "); - result.push_str(s); - } - } - result.push_str("\n"); - } - if bad { - bail!( - "expected != actual for test `{}`\n\n{}", - test.display(), - result - ); - } else { - Ok(()) - } -} - -fn find_tests(path: &Path, tests: &mut Vec) { - for f in path.read_dir().unwrap() { - let f = f.unwrap(); - if f.file_type().unwrap().is_dir() { - find_tests(&f.path(), tests); - continue; - } - match f.path().extension().and_then(|s| s.to_str()) { - Some("wat") => {} - _ => continue, - } - tests.push(f.path()); - } -} diff --git a/tests/dump/alias.wat b/tests/dump/alias.wat deleted file mode 100644 index 7a79f26ebb..0000000000 --- a/tests/dump/alias.wat +++ /dev/null @@ -1,19 +0,0 @@ -(component - (import "i" (instance $i - (export "f1" (func $f1)) - (export "f2" (func $f2 (param string))) - )) - - (func (alias export $i "f1")) - (alias export $i "f2" (func)) - - (core func (canon lower (func $i "f1"))) - - (core module $m - (func (export "f3")) - ) - - (core instance $m (instantiate $m)) - (core func (alias export $m "f3")) - (alias core export $m "f3" (core func)) -) diff --git a/tests/dump/alias.wat.dump b/tests/dump/alias.wat.dump deleted file mode 100644 index 47855ce37d..0000000000 --- a/tests/dump/alias.wat.dump +++ /dev/null @@ -1,58 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 1b | component type section - 0xa | 01 | 1 count - 0xb | 42 04 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "f1", ty: Func(0) }, Type(Func(ComponentFuncType { params: Unnamed(Primitive(String)), results: Named([]) })), Export { name: "f2", ty: Func(1) }]) - | 01 00 01 00 - | 04 02 66 31 - | 01 00 01 40 - | 00 73 01 00 - | 04 02 66 32 - | 01 01 - 0x25 | 0a 05 | component import section - 0x27 | 01 | 1 count - 0x28 | 01 69 05 00 | [instance 0] ComponentImport { name: "i", ty: Instance(0) } - 0x2c | 06 13 | component alias section - 0x2e | 03 | 3 count - 0x2f | 01 00 00 02 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "f1" } - | 66 31 - 0x35 | 01 00 00 02 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "f2" } - | 66 32 - 0x3b | 01 00 00 02 | alias [func 2] InstanceExport { kind: Func, instance_index: 0, name: "f1" } - | 66 31 - 0x41 | 08 05 | canonical function section - 0x43 | 01 | 1 count - 0x44 | 01 00 02 00 | [core func 0] Lower { func_index: 2, options: [] } - 0x48 | 01 2b | [core module 0] inline size - 0x4a | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x52 | 01 04 | type section - 0x54 | 01 | 1 count - 0x55 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x58 | 03 02 | func section - 0x5a | 01 | 1 count - 0x5b | 00 | [func 0] type 0 - 0x5c | 07 06 | export section - 0x5e | 01 | 1 count - 0x5f | 02 66 33 00 | export Export { name: "f3", kind: Func, index: 0 } - | 00 - 0x64 | 0a 04 | code section - 0x66 | 01 | 1 count -============== func 0 ==================== - 0x67 | 02 | size of function - 0x68 | 00 | 0 local blocks - 0x69 | 0b | end - 0x6a | 00 09 | custom section - 0x6c | 04 6e 61 6d | name: "name" - | 65 - 0x71 | 00 02 | module name - 0x73 | 01 6d | "m" - 0x75 | 02 04 | core instance section - 0x77 | 01 | 1 count - 0x78 | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } - 0x7b | 06 0f | component alias section - 0x7d | 02 | 2 count - 0x7e | 00 00 01 00 | alias [core func 1] CoreInstanceExport { kind: Func, instance_index: 0, name: "f3" } - | 02 66 33 - 0x85 | 00 00 01 00 | alias [core func 2] CoreInstanceExport { kind: Func, instance_index: 0, name: "f3" } - | 02 66 33 diff --git a/tests/dump/alias2.wat b/tests/dump/alias2.wat deleted file mode 100644 index 7487c0fa30..0000000000 --- a/tests/dump/alias2.wat +++ /dev/null @@ -1,82 +0,0 @@ -(component - (type $t (instance - (export "1" (core module)) - (export "2" (func)) - (export "3" (value string)) - (export "4" (instance)) - (export "5" (component)) - )) - - (import "" (instance $i (type $t))) - - (component $c - (import "1" (core module)) - (import "2" (func)) - (import "3" (value string)) - (import "4" (instance)) - (import "5" (component)) - ) - - (instance (instantiate $c - (with "1" (core module $i "1")) - (with "2" (func $i "2")) - (with "3" (value $i "4")) - (with "4" (instance $i "3")) - (with "5" (component $i "5")) - )) - - (component $c2 - (import "" (instance (type $t))) - ) - - (alias export $i "1" (core module $m)) - (alias export $i "2" (func $f)) - (alias export $i "3" (value $v)) - (alias export $i "4" (instance $i2)) - (alias export $i "5" (component $c3)) - - (instance - (instantiate $c2 - (with "" (instance - (export "1" (core module $m)) - (export "2" (func $f)) - (export "3" (value $v)) - (export "4" (instance $i2)) - (export "5" (component $c3)) - )) - ) - ) - - (core module $m1 - (func (export "1")) - (memory (export "2") 1) - (global (export "3") i32) - (table (export "4") 1 funcref) - ) - - (core module $m2 - (import "" "1" (func)) - (import "" "2" (memory 1)) - (import "" "3" (global i32)) - (import "" "4" (table 1 funcref)) - ) - - (core instance $i (instantiate $m1)) - (core instance (instantiate $m2 (with "" (instance $i)))) - - (alias core export $i "1" (core func $f)) - (alias core export $i "2" (core memory $m)) - (alias core export $i "3" (core global $g)) - (alias core export $i "4" (core table $t)) - - (core instance - (instantiate $m2 - (with "" (instance - (export "1" (func $f)) - (export "2" (memory $m)) - (export "3" (global $g)) - (export "4" (table $t)) - )) - ) - ) -) diff --git a/tests/dump/alias2.wat.dump b/tests/dump/alias2.wat.dump deleted file mode 100644 index 0eff6b92ef..0000000000 --- a/tests/dump/alias2.wat.dump +++ /dev/null @@ -1,180 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 2c | component type section - 0xa | 01 | 1 count - 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "1", ty: Module(0) }, Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "2", ty: Func(0) }, Export { name: "3", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "4", ty: Instance(1) }, Type(Component([])), Export { name: "5", ty: Component(2) }]) - | 00 04 01 31 - | 00 11 00 01 - | 40 01 00 01 - | 00 04 01 32 - | 01 00 04 01 - | 33 02 73 01 - | 42 00 04 01 - | 34 05 01 01 - | 41 00 04 01 - | 35 04 02 - 0x36 | 0a 04 | component import section - 0x38 | 01 | 1 count - 0x39 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } - 0x3c | 04 40 | [component 0] inline size - 0x3e | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x46 | 03 03 | core type section - 0x48 | 01 | 1 count - 0x49 | 50 00 | [core type 0] Module([]) - 0x4b | 0a 06 | component import section - 0x4d | 01 | 1 count - 0x4e | 01 31 00 11 | [module 0] ComponentImport { name: "1", ty: Module(0) } - | 00 - 0x53 | 07 06 | component type section - 0x55 | 01 | 1 count - 0x56 | 40 01 00 01 | [type 0] Func(ComponentFuncType { params: Named([]), results: Named([]) }) - | 00 - 0x5b | 0a 09 | component import section - 0x5d | 02 | 2 count - 0x5e | 01 32 01 00 | [func 0] ComponentImport { name: "2", ty: Func(0) } - 0x62 | 01 33 02 73 | [value 0] ComponentImport { name: "3", ty: Value(Primitive(String)) } - 0x66 | 07 03 | component type section - 0x68 | 01 | 1 count - 0x69 | 42 00 | [type 1] Instance([]) - 0x6b | 0a 05 | component import section - 0x6d | 01 | 1 count - 0x6e | 01 34 05 01 | [instance 0] ComponentImport { name: "4", ty: Instance(1) } - 0x72 | 07 03 | component type section - 0x74 | 01 | 1 count - 0x75 | 41 00 | [type 2] Component([]) - 0x77 | 0a 05 | component import section - 0x79 | 01 | 1 count - 0x7a | 01 35 04 02 | [component 0] ComponentImport { name: "5", ty: Component(2) } - 0x7e | 06 1b | component alias section - 0x80 | 05 | 5 count - 0x81 | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "1" } - | 01 31 - 0x87 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "2" } - | 32 - 0x8c | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "4" } - | 34 - 0x91 | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "3" } - | 33 - 0x96 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "5" } - | 35 - 0x9b | 05 19 | component instance section - 0x9d | 01 | 1 count - 0x9e | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "1", kind: Module, index: 0 }, ComponentInstantiationArg { name: "2", kind: Func, index: 0 }, ComponentInstantiationArg { name: "3", kind: Value, index: 0 }, ComponentInstantiationArg { name: "4", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "5", kind: Component, index: 1 }] } - | 31 00 11 00 - | 01 32 01 00 - | 01 33 02 00 - | 01 34 05 01 - | 01 35 04 01 - 0xb6 | 04 15 | [component 2] inline size - 0xb8 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0xc0 | 06 05 | component alias section - 0xc2 | 01 | 1 count - 0xc3 | 03 02 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } - 0xc7 | 0a 04 | component import section - 0xc9 | 01 | 1 count - 0xca | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } - 0xcd | 06 1b | component alias section - 0xcf | 05 | 5 count - 0xd0 | 00 11 00 00 | alias [module 1] InstanceExport { kind: Module, instance_index: 0, name: "1" } - | 01 31 - 0xd6 | 01 00 00 01 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "2" } - | 32 - 0xdb | 02 00 00 01 | alias [value 1] InstanceExport { kind: Value, instance_index: 0, name: "3" } - | 33 - 0xe0 | 05 00 00 01 | alias [instance 3] InstanceExport { kind: Instance, instance_index: 0, name: "4" } - | 34 - 0xe5 | 04 00 00 01 | alias [component 3] InstanceExport { kind: Component, instance_index: 0, name: "5" } - | 35 - 0xea | 05 1e | component instance section - 0xec | 02 | 2 count - 0xed | 01 05 01 31 | [instance 4] FromExports([ComponentExport { name: "1", kind: Module, index: 1 }, ComponentExport { name: "2", kind: Func, index: 1 }, ComponentExport { name: "3", kind: Value, index: 1 }, ComponentExport { name: "4", kind: Instance, index: 3 }, ComponentExport { name: "5", kind: Component, index: 3 }]) - | 00 11 01 01 - | 32 01 01 01 - | 33 02 01 01 - | 34 05 03 01 - | 35 04 03 - 0x104 | 00 02 01 00 | [instance 5] Instantiate { component_index: 2, args: [ComponentInstantiationArg { name: "", kind: Instance, index: 4 }] } - | 05 04 - 0x10a | 01 48 | [core module 2] inline size - 0x10c | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x114 | 01 04 | type section - 0x116 | 01 | 1 count - 0x117 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x11a | 03 02 | func section - 0x11c | 01 | 1 count - 0x11d | 00 | [func 0] type 0 - 0x11e | 04 04 | table section - 0x120 | 01 | 1 count - 0x121 | 70 00 01 | [table 0] TableType { element_type: FuncRef, initial: 1, maximum: None } - 0x124 | 05 03 | memory section - 0x126 | 01 | 1 count - 0x127 | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None } - 0x129 | 06 04 | global section - 0x12b | 01 | 1 count - 0x12c | 7f 00 | [global 0] GlobalType { content_type: I32, mutable: false } - 0x12e | 0b | end - 0x12f | 07 11 | export section - 0x131 | 04 | 4 count - 0x132 | 01 31 00 00 | export Export { name: "1", kind: Func, index: 0 } - 0x136 | 01 32 02 00 | export Export { name: "2", kind: Memory, index: 0 } - 0x13a | 01 33 03 00 | export Export { name: "3", kind: Global, index: 0 } - 0x13e | 01 34 01 00 | export Export { name: "4", kind: Table, index: 0 } - 0x142 | 0a 04 | code section - 0x144 | 01 | 1 count -============== func 0 ==================== - 0x145 | 02 | size of function - 0x146 | 00 | 0 local blocks - 0x147 | 0b | end - 0x148 | 00 0a | custom section - 0x14a | 04 6e 61 6d | name: "name" - | 65 - 0x14f | 00 03 | module name - 0x151 | 02 6d 31 | "m1" - 0x154 | 01 35 | [core module 3] inline size - 0x156 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x15e | 01 04 | type section - 0x160 | 01 | 1 count - 0x161 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x164 | 02 19 | import section - 0x166 | 04 | 4 count - 0x167 | 00 01 31 00 | import [func 0] Import { module: "", name: "1", ty: Func(0) } - | 00 - 0x16c | 00 01 32 02 | import [memory 0] Import { module: "", name: "2", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) } - | 00 01 - 0x172 | 00 01 33 03 | import [global 0] Import { module: "", name: "3", ty: Global(GlobalType { content_type: I32, mutable: false }) } - | 7f 00 - 0x178 | 00 01 34 01 | import [table 0] Import { module: "", name: "4", ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) } - | 70 00 01 - 0x17f | 00 0a | custom section - 0x181 | 04 6e 61 6d | name: "name" - | 65 - 0x186 | 00 03 | module name - 0x188 | 02 6d 32 | "m2" - 0x18b | 02 0a | core instance section - 0x18d | 02 | 2 count - 0x18e | 00 02 00 | [core instance 0] Instantiate { module_index: 2, args: [] } - 0x191 | 00 03 01 00 | [core instance 1] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 0 }] } - | 12 00 - 0x197 | 06 19 | component alias section - 0x199 | 04 | 4 count - 0x19a | 00 00 01 00 | alias [core func 0] CoreInstanceExport { kind: Func, instance_index: 0, name: "1" } - | 01 31 - 0x1a0 | 00 02 01 00 | alias [core memory 0] CoreInstanceExport { kind: Memory, instance_index: 0, name: "2" } - | 01 32 - 0x1a6 | 00 03 01 00 | alias [core global 0] CoreInstanceExport { kind: Global, instance_index: 0, name: "3" } - | 01 33 - 0x1ac | 00 01 01 00 | alias [core table 0] CoreInstanceExport { kind: Table, instance_index: 0, name: "4" } - | 01 34 - 0x1b2 | 02 19 | core instance section - 0x1b4 | 02 | 2 count - 0x1b5 | 01 04 01 31 | [core instance 2] FromExports([Export { name: "1", kind: Func, index: 0 }, Export { name: "2", kind: Memory, index: 0 }, Export { name: "3", kind: Global, index: 0 }, Export { name: "4", kind: Table, index: 0 }]) - | 00 00 01 32 - | 02 00 01 33 - | 03 00 01 34 - | 01 00 - 0x1c7 | 00 03 01 00 | [core instance 3] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 2 }] } - | 12 02 diff --git a/tests/dump/bundled.wat b/tests/dump/bundled.wat deleted file mode 100644 index 4e17eac4d7..0000000000 --- a/tests/dump/bundled.wat +++ /dev/null @@ -1,49 +0,0 @@ -(component - (type $WasiFile (instance - (export "read" (func $read (param u32) (result (list u8)))) - (export "write" (func $write (param (list u8)) (result u32))) - )) - (import "wasi_file" (instance $real-wasi (type $WasiFile))) - - (core module $libc - (memory (export "mem") 0) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable - ) - ) - - (core instance $libc (instantiate $libc)) - - (core module $CHILD - (import "wasi_file" "read" (func $wasi-file (param i32 i32))) - (func $play (export "play") - unreachable - ) - ) - - (core module $VIRTUALIZE - (import "wasi_file" "read" (func (param i32 i32))) - (func (export "read") (param i32 i32) - unreachable - ) - (func (export "write") (param i32 i32 i32) - unreachable - ) - ) - - (core func $real-wasi-read - (canon lower (func $real-wasi "read") - (memory $libc "mem") - (realloc (func $libc "realloc")) - ) - ) - - (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi_file" (instance (export "read" (func $real-wasi-read)))))) - (core instance $child (instantiate $CHILD (with "wasi_file" (instance $virt-wasi)))) - (func (export "work") - (canon lift (core func $child "play") - (memory $libc "mem") - (realloc (func $libc "realloc")) - ) - ) -) diff --git a/tests/dump/bundled.wat.dump b/tests/dump/bundled.wat.dump deleted file mode 100644 index 84fbc810ae..0000000000 --- a/tests/dump/bundled.wat.dump +++ /dev/null @@ -1,191 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 26 | component type section - 0xa | 01 | 1 count - 0xb | 42 06 01 70 | [type 0] Instance([Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: Unnamed(Primitive(U32)), results: Unnamed(Type(0)) })), Export { name: "read", ty: Func(1) }, Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: Unnamed(Type(2)), results: Unnamed(Primitive(U32)) })), Export { name: "write", ty: Func(3) }]) - | 7d 01 40 00 - | 79 00 00 04 - | 04 72 65 61 - | 64 01 01 01 - | 70 7d 01 40 - | 00 02 00 79 - | 04 05 77 72 - | 69 74 65 01 - | 03 - 0x30 | 0a 0d | component import section - 0x32 | 01 | 1 count - 0x33 | 09 77 61 73 | [instance 0] ComponentImport { name: "wasi_file", ty: Instance(0) } - | 69 5f 66 69 - | 6c 65 05 00 - 0x3f | 01 44 | [core module 0] inline size - 0x41 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x49 | 01 09 | type section - 0x4b | 01 | 1 count - 0x4c | 60 04 7f 7f | [type 0] Func(FuncType { params: [I32, I32, I32, I32], returns: [I32] }) - | 7f 7f 01 7f - 0x54 | 03 02 | func section - 0x56 | 01 | 1 count - 0x57 | 00 | [func 0] type 0 - 0x58 | 05 03 | memory section - 0x5a | 01 | 1 count - 0x5b | 00 00 | [memory 0] MemoryType { memory64: false, shared: false, initial: 0, maximum: None } - 0x5d | 07 11 | export section - 0x5f | 02 | 2 count - 0x60 | 03 6d 65 6d | export Export { name: "mem", kind: Memory, index: 0 } - | 02 00 - 0x66 | 07 72 65 61 | export Export { name: "realloc", kind: Func, index: 0 } - | 6c 6c 6f 63 - | 00 00 - 0x70 | 0a 05 | code section - 0x72 | 01 | 1 count -============== func 0 ==================== - 0x73 | 03 | size of function - 0x74 | 00 | 0 local blocks - 0x75 | 00 | unreachable - 0x76 | 0b | end - 0x77 | 00 0c | custom section - 0x79 | 04 6e 61 6d | name: "name" - | 65 - 0x7e | 00 05 | module name - 0x80 | 04 6c 69 62 | "libc" - | 63 - 0x85 | 02 04 | core instance section - 0x87 | 01 | 1 count - 0x88 | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } - 0x8b | 01 5f | [core module 1] inline size - 0x8d | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x95 | 01 09 | type section - 0x97 | 02 | 2 count - 0x98 | 60 02 7f 7f | [type 0] Func(FuncType { params: [I32, I32], returns: [] }) - | 00 - 0x9d | 60 00 00 | [type 1] Func(FuncType { params: [], returns: [] }) - 0xa0 | 02 12 | import section - 0xa2 | 01 | 1 count - 0xa3 | 09 77 61 73 | import [func 0] Import { module: "wasi_file", name: "read", ty: Func(0) } - | 69 5f 66 69 - | 6c 65 04 72 - | 65 61 64 00 - | 00 - 0xb4 | 03 02 | func section - 0xb6 | 01 | 1 count - 0xb7 | 01 | [func 1] type 1 - 0xb8 | 07 08 | export section - 0xba | 01 | 1 count - 0xbb | 04 70 6c 61 | export Export { name: "play", kind: Func, index: 1 } - | 79 00 01 - 0xc2 | 0a 05 | code section - 0xc4 | 01 | 1 count -============== func 1 ==================== - 0xc5 | 03 | size of function - 0xc6 | 00 | 0 local blocks - 0xc7 | 00 | unreachable - 0xc8 | 0b | end - 0xc9 | 00 21 | custom section - 0xcb | 04 6e 61 6d | name: "name" - | 65 - 0xd0 | 00 06 | module name - 0xd2 | 05 43 48 49 | "CHILD" - | 4c 44 - 0xd8 | 01 12 | function names - 0xda | 02 | 2 count - 0xdb | 00 09 77 61 | Naming { index: 0, name: "wasi-file" } - | 73 69 2d 66 - | 69 6c 65 - 0xe6 | 01 04 70 6c | Naming { index: 1, name: "play" } - | 61 79 - 0xec | 01 60 | [core module 2] inline size - 0xee | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0xf6 | 01 0c | type section - 0xf8 | 02 | 2 count - 0xf9 | 60 02 7f 7f | [type 0] Func(FuncType { params: [I32, I32], returns: [] }) - | 00 - 0xfe | 60 03 7f 7f | [type 1] Func(FuncType { params: [I32, I32, I32], returns: [] }) - | 7f 00 - 0x104 | 02 12 | import section - 0x106 | 01 | 1 count - 0x107 | 09 77 61 73 | import [func 0] Import { module: "wasi_file", name: "read", ty: Func(0) } - | 69 5f 66 69 - | 6c 65 04 72 - | 65 61 64 00 - | 00 - 0x118 | 03 03 | func section - 0x11a | 02 | 2 count - 0x11b | 00 | [func 1] type 0 - 0x11c | 01 | [func 2] type 1 - 0x11d | 07 10 | export section - 0x11f | 02 | 2 count - 0x120 | 04 72 65 61 | export Export { name: "read", kind: Func, index: 1 } - | 64 00 01 - 0x127 | 05 77 72 69 | export Export { name: "write", kind: Func, index: 2 } - | 74 65 00 02 - 0x12f | 0a 09 | code section - 0x131 | 02 | 2 count -============== func 1 ==================== - 0x132 | 03 | size of function - 0x133 | 00 | 0 local blocks - 0x134 | 00 | unreachable - 0x135 | 0b | end -============== func 2 ==================== - 0x136 | 03 | size of function - 0x137 | 00 | 0 local blocks - 0x138 | 00 | unreachable - 0x139 | 0b | end - 0x13a | 00 12 | custom section - 0x13c | 04 6e 61 6d | name: "name" - | 65 - 0x141 | 00 0b | module name - 0x143 | 0a 56 49 52 | "VIRTUALIZE" - | 54 55 41 4c - | 49 5a 45 - 0x14e | 06 1d | component alias section - 0x150 | 03 | 3 count - 0x151 | 01 00 00 04 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "read" } - | 72 65 61 64 - 0x159 | 00 02 01 00 | alias [core memory 0] CoreInstanceExport { kind: Memory, instance_index: 0, name: "mem" } - | 03 6d 65 6d - 0x161 | 00 00 01 00 | alias [core func 0] CoreInstanceExport { kind: Func, instance_index: 0, name: "realloc" } - | 07 72 65 61 - | 6c 6c 6f 63 - 0x16d | 08 09 | canonical function section - 0x16f | 01 | 1 count - 0x170 | 01 00 00 02 | [core func 1] Lower { func_index: 0, options: [Memory(0), Realloc(0)] } - | 03 00 04 00 - 0x178 | 02 28 | core instance section - 0x17a | 03 | 3 count - 0x17b | 01 01 04 72 | [core instance 1] FromExports([Export { name: "read", kind: Func, index: 1 }]) - | 65 61 64 00 - | 01 - 0x184 | 00 02 01 09 | [core instance 2] Instantiate { module_index: 2, args: [InstantiationArg { name: "wasi_file", kind: Instance, index: 1 }] } - | 77 61 73 69 - | 5f 66 69 6c - | 65 12 01 - 0x193 | 00 01 01 09 | [core instance 3] Instantiate { module_index: 1, args: [InstantiationArg { name: "wasi_file", kind: Instance, index: 2 }] } - | 77 61 73 69 - | 5f 66 69 6c - | 65 12 02 - 0x1a2 | 07 06 | component type section - 0x1a4 | 01 | 1 count - 0x1a5 | 40 01 00 01 | [type 1] Func(ComponentFuncType { params: Named([]), results: Named([]) }) - | 00 - 0x1aa | 06 1e | component alias section - 0x1ac | 03 | 3 count - 0x1ad | 00 00 01 03 | alias [core func 2] CoreInstanceExport { kind: Func, instance_index: 3, name: "play" } - | 04 70 6c 61 - | 79 - 0x1b6 | 00 02 01 00 | alias [core memory 1] CoreInstanceExport { kind: Memory, instance_index: 0, name: "mem" } - | 03 6d 65 6d - 0x1be | 00 00 01 00 | alias [core func 3] CoreInstanceExport { kind: Func, instance_index: 0, name: "realloc" } - | 07 72 65 61 - | 6c 6c 6f 63 - 0x1ca | 08 0a | canonical function section - 0x1cc | 01 | 1 count - 0x1cd | 00 00 02 02 | [func 1] Lift { core_func_index: 2, type_index: 1, options: [Memory(1), Realloc(3)] } - | 03 01 04 03 - | 01 - 0x1d6 | 0b 08 | component export section - 0x1d8 | 01 | 1 count - 0x1d9 | 04 77 6f 72 | export ComponentExport { name: "work", kind: Func, index: 1 } - | 6b 01 01 diff --git a/tests/dump/component-expand-bundle.wat.dump b/tests/dump/component-expand-bundle.wat.dump deleted file mode 100644 index 92b109983a..0000000000 --- a/tests/dump/component-expand-bundle.wat.dump +++ /dev/null @@ -1,53 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 01 29 | [core module 0] inline size - 0xa | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x12 | 01 04 | type section - 0x14 | 01 | 1 count - 0x15 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x18 | 03 02 | func section - 0x1a | 01 | 1 count - 0x1b | 00 | [func 0] type 0 - 0x1c | 07 04 | export section - 0x1e | 01 | 1 count - 0x1f | 00 00 00 | export Export { name: "", kind: Func, index: 0 } - 0x22 | 0a 04 | code section - 0x24 | 01 | 1 count -============== func 0 ==================== - 0x25 | 02 | size of function - 0x26 | 00 | 0 local blocks - 0x27 | 0b | end - 0x28 | 00 09 | custom section - 0x2a | 04 6e 61 6d | name: "name" - | 65 - 0x2f | 00 02 | module name - 0x31 | 01 6d | "m" - 0x33 | 01 22 | [core module 1] inline size - 0x35 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x3d | 01 04 | type section - 0x3f | 01 | 1 count - 0x40 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x43 | 02 06 | import section - 0x45 | 01 | 1 count - 0x46 | 00 01 61 00 | import [func 0] Import { module: "", name: "a", ty: Func(0) } - | 00 - 0x4b | 00 0a | custom section - 0x4d | 04 6e 61 6d | name: "name" - | 65 - 0x52 | 00 03 | module name - 0x54 | 02 6d 32 | "m2" - 0x57 | 02 04 | core instance section - 0x59 | 01 | 1 count - 0x5a | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } - 0x5d | 06 06 | component alias section - 0x5f | 01 | 1 count - 0x60 | 00 00 01 00 | alias [core func 0] CoreInstanceExport { kind: Func, instance_index: 0, name: "" } - | 00 - 0x65 | 02 0d | core instance section - 0x67 | 02 | 2 count - 0x68 | 01 01 01 61 | [core instance 1] FromExports([Export { name: "a", kind: Func, index: 0 }]) - | 00 00 - 0x6e | 00 01 01 00 | [core instance 2] Instantiate { module_index: 1, args: [InstantiationArg { name: "", kind: Instance, index: 1 }] } - | 12 01 diff --git a/tests/dump/component-expand-bundle2.wat b/tests/dump/component-expand-bundle2.wat deleted file mode 100644 index 4b09abe45a..0000000000 --- a/tests/dump/component-expand-bundle2.wat +++ /dev/null @@ -1,11 +0,0 @@ -(component - (component $c - (core module (export "")) - ) - (component $c2 (import "" (component (import "" (core module))))) - (instance $C (instantiate $c)) - (alias export $C "" (core module $m)) - (instance (instantiate $c2 (with "" (instance - (export "" (core module $m)) - )))) -) diff --git a/tests/dump/component-expand-bundle2.wat.dump b/tests/dump/component-expand-bundle2.wat.dump deleted file mode 100644 index e558d3e2aa..0000000000 --- a/tests/dump/component-expand-bundle2.wat.dump +++ /dev/null @@ -1,35 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 04 19 | [component 0] inline size - 0xa | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x12 | 01 08 | [core module 0] inline size - 0x14 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x1c | 0b 05 | component export section - 0x1e | 01 | 1 count - 0x1f | 00 00 11 00 | export ComponentExport { name: "", kind: Module, index: 0 } - 0x23 | 04 1b | [component 1] inline size - 0x25 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x2d | 07 0b | component type section - 0x2f | 01 | 1 count - 0x30 | 41 02 00 50 | [type 0] Component([CoreType(Module([])), Import(ComponentImport { name: "", ty: Module(0) })]) - | 00 03 00 00 - | 11 00 - 0x3a | 0a 04 | component import section - 0x3c | 01 | 1 count - 0x3d | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } - 0x40 | 05 04 | component instance section - 0x42 | 01 | 1 count - 0x43 | 00 00 00 | [instance 0] Instantiate { component_index: 0, args: [] } - 0x46 | 06 06 | component alias section - 0x48 | 01 | 1 count - 0x49 | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "" } - | 00 - 0x4e | 05 0d | component instance section - 0x50 | 02 | 2 count - 0x51 | 01 01 00 00 | [instance 1] FromExports([ComponentExport { name: "", kind: Module, index: 0 }]) - | 11 00 - 0x57 | 00 01 01 00 | [instance 2] Instantiate { component_index: 1, args: [ComponentInstantiationArg { name: "", kind: Instance, index: 1 }] } - | 05 01 diff --git a/tests/dump/component-inline-export-import.wat.dump b/tests/dump/component-inline-export-import.wat.dump deleted file mode 100644 index 0fb522cbc0..0000000000 --- a/tests/dump/component-inline-export-import.wat.dump +++ /dev/null @@ -1,20 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 03 | component type section - 0xa | 01 | 1 count - 0xb | 41 00 | [type 0] Component([]) - 0xd | 0a 04 | component import section - 0xf | 01 | 1 count - 0x10 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } - 0x13 | 03 03 | core type section - 0x15 | 01 | 1 count - 0x16 | 50 00 | [core type 0] Module([]) - 0x18 | 0a 06 | component import section - 0x1a | 01 | 1 count - 0x1b | 01 61 00 11 | [module 0] ComponentImport { name: "a", ty: Module(0) } - | 00 - 0x20 | 0b 09 | component export section - 0x22 | 02 | 2 count - 0x23 | 00 04 00 | export ComponentExport { name: "", kind: Component, index: 0 } - 0x26 | 01 61 00 11 | export ComponentExport { name: "a", kind: Module, index: 0 } - | 00 diff --git a/tests/dump/component-inline-type.wat b/tests/dump/component-inline-type.wat deleted file mode 100644 index 4a1128f5e3..0000000000 --- a/tests/dump/component-inline-type.wat +++ /dev/null @@ -1,6 +0,0 @@ -(component - (import "" (component)) - (import "" (core module)) - (import "" (instance)) - (import "" (func)) -) diff --git a/tests/dump/component-inline-type.wat.dump b/tests/dump/component-inline-type.wat.dump deleted file mode 100644 index 1cab3fbc71..0000000000 --- a/tests/dump/component-inline-type.wat.dump +++ /dev/null @@ -1,27 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 03 | component type section - 0xa | 01 | 1 count - 0xb | 41 00 | [type 0] Component([]) - 0xd | 0a 04 | component import section - 0xf | 01 | 1 count - 0x10 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } - 0x13 | 03 03 | core type section - 0x15 | 01 | 1 count - 0x16 | 50 00 | [core type 0] Module([]) - 0x18 | 0a 05 | component import section - 0x1a | 01 | 1 count - 0x1b | 00 00 11 00 | [module 0] ComponentImport { name: "", ty: Module(0) } - 0x1f | 07 03 | component type section - 0x21 | 01 | 1 count - 0x22 | 42 00 | [type 1] Instance([]) - 0x24 | 0a 04 | component import section - 0x26 | 01 | 1 count - 0x27 | 00 05 01 | [instance 0] ComponentImport { name: "", ty: Instance(1) } - 0x2a | 07 06 | component type section - 0x2c | 01 | 1 count - 0x2d | 40 01 00 01 | [type 2] Func(ComponentFuncType { params: Named([]), results: Named([]) }) - | 00 - 0x32 | 0a 04 | component import section - 0x34 | 01 | 1 count - 0x35 | 00 01 02 | [func 0] ComponentImport { name: "", ty: Func(2) } diff --git a/tests/dump/component-instance-type.wat.dump b/tests/dump/component-instance-type.wat.dump deleted file mode 100644 index f8e09afc41..0000000000 --- a/tests/dump/component-instance-type.wat.dump +++ /dev/null @@ -1,14 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 27 | component type section - 0xa | 01 | 1 count - 0xb | 42 03 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Type(Component([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Alias(Outer { kind: Type, count: 1, index: 0 }), Import(ComponentImport { name: "1", ty: Func(0) }), Export { name: "1", ty: Func(1) }])), Export { name: "c5", ty: Component(1) }]) - | 01 00 01 00 - | 01 41 04 01 - | 40 01 00 01 - | 00 02 03 02 - | 01 00 03 01 - | 31 01 00 04 - | 01 31 01 01 - | 04 02 63 35 - | 04 01 diff --git a/tests/dump/component-linking.wat b/tests/dump/component-linking.wat deleted file mode 100644 index bcdabbf8fb..0000000000 --- a/tests/dump/component-linking.wat +++ /dev/null @@ -1,25 +0,0 @@ -(component - (import "" (instance $i - (export "1" (core module)) - (export "2" (func)) - (export "3" (value string)) - (export "4" (instance)) - (export "5" (component)) - )) - - (component $c - (import "1" (core module)) - (import "2" (func)) - (import "3" (value string)) - (import "4" (instance)) - (import "5" (component)) - ) - - (instance (instantiate $c - (with "1" (core module $i "1")) - (with "2" (func $i "2")) - (with "3" (value $i "4")) - (with "4" (instance $i "3")) - (with "5" (component $i "5")) - )) -) diff --git a/tests/dump/component-linking.wat.dump b/tests/dump/component-linking.wat.dump deleted file mode 100644 index d24e1629cf..0000000000 --- a/tests/dump/component-linking.wat.dump +++ /dev/null @@ -1,68 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 2c | component type section - 0xa | 01 | 1 count - 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "1", ty: Module(0) }, Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "2", ty: Func(0) }, Export { name: "3", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "4", ty: Instance(1) }, Type(Component([])), Export { name: "5", ty: Component(2) }]) - | 00 04 01 31 - | 00 11 00 01 - | 40 01 00 01 - | 00 04 01 32 - | 01 00 04 01 - | 33 02 73 01 - | 42 00 04 01 - | 34 05 01 01 - | 41 00 04 01 - | 35 04 02 - 0x36 | 0a 04 | component import section - 0x38 | 01 | 1 count - 0x39 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } - 0x3c | 04 40 | [component 0] inline size - 0x3e | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x46 | 03 03 | core type section - 0x48 | 01 | 1 count - 0x49 | 50 00 | [core type 0] Module([]) - 0x4b | 0a 06 | component import section - 0x4d | 01 | 1 count - 0x4e | 01 31 00 11 | [module 0] ComponentImport { name: "1", ty: Module(0) } - | 00 - 0x53 | 07 06 | component type section - 0x55 | 01 | 1 count - 0x56 | 40 01 00 01 | [type 0] Func(ComponentFuncType { params: Named([]), results: Named([]) }) - | 00 - 0x5b | 0a 09 | component import section - 0x5d | 02 | 2 count - 0x5e | 01 32 01 00 | [func 0] ComponentImport { name: "2", ty: Func(0) } - 0x62 | 01 33 02 73 | [value 0] ComponentImport { name: "3", ty: Value(Primitive(String)) } - 0x66 | 07 03 | component type section - 0x68 | 01 | 1 count - 0x69 | 42 00 | [type 1] Instance([]) - 0x6b | 0a 05 | component import section - 0x6d | 01 | 1 count - 0x6e | 01 34 05 01 | [instance 0] ComponentImport { name: "4", ty: Instance(1) } - 0x72 | 07 03 | component type section - 0x74 | 01 | 1 count - 0x75 | 41 00 | [type 2] Component([]) - 0x77 | 0a 05 | component import section - 0x79 | 01 | 1 count - 0x7a | 01 35 04 02 | [component 0] ComponentImport { name: "5", ty: Component(2) } - 0x7e | 06 1b | component alias section - 0x80 | 05 | 5 count - 0x81 | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "1" } - | 01 31 - 0x87 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "2" } - | 32 - 0x8c | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "4" } - | 34 - 0x91 | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "3" } - | 33 - 0x96 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "5" } - | 35 - 0x9b | 05 19 | component instance section - 0x9d | 01 | 1 count - 0x9e | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "1", kind: Module, index: 0 }, ComponentInstantiationArg { name: "2", kind: Func, index: 0 }, ComponentInstantiationArg { name: "3", kind: Value, index: 0 }, ComponentInstantiationArg { name: "4", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "5", kind: Component, index: 1 }] } - | 31 00 11 00 - | 01 32 01 00 - | 01 33 02 00 - | 01 34 05 01 - | 01 35 04 01 diff --git a/tests/dump/component-outer-alias.wat.dump b/tests/dump/component-outer-alias.wat.dump deleted file mode 100644 index 50909df8cd..0000000000 --- a/tests/dump/component-outer-alias.wat.dump +++ /dev/null @@ -1,46 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 0f | component type section - 0xa | 02 | 2 count - 0xb | 73 | [type 0] Defined(Primitive(String)) - 0xc | 41 02 02 03 | [type 1] Component([Alias(Outer { kind: Type, count: 1, index: 0 }), Type(Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }))]) - | 02 01 00 01 - | 40 01 00 00 - | 00 - 0x19 | 04 17 | [component 0] inline size - 0x1b | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x23 | 06 05 | component alias section - 0x25 | 01 | 1 count - 0x26 | 03 02 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } - 0x2a | 07 06 | component type section - 0x2c | 01 | 1 count - 0x2d | 40 01 00 00 | [type 1] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) - | 00 - 0x32 | 04 1c | [component 1] inline size - 0x34 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x3c | 06 05 | component alias section - 0x3e | 01 | 1 count - 0x3f | 03 02 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } - 0x43 | 07 0b | component type section - 0x45 | 02 | 2 count - 0x46 | 40 01 00 00 | [type 1] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) - | 00 - 0x4b | 40 01 00 00 | [type 2] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) - | 00 - 0x50 | 07 02 | component type section - 0x52 | 01 | 1 count - 0x53 | 7d | [type 2] Defined(Primitive(U8)) - 0x54 | 04 1c | [component 2] inline size - 0x56 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x5e | 06 05 | component alias section - 0x60 | 01 | 1 count - 0x61 | 03 02 01 02 | alias [type 0] Outer { kind: Type, count: 1, index: 2 } - 0x65 | 07 0b | component type section - 0x67 | 02 | 2 count - 0x68 | 40 01 00 00 | [type 1] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) - | 00 - 0x6d | 40 01 00 00 | [type 2] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) - | 00 diff --git a/tests/dump/import-modules.wat b/tests/dump/import-modules.wat deleted file mode 100644 index 5a28f05d23..0000000000 --- a/tests/dump/import-modules.wat +++ /dev/null @@ -1,10 +0,0 @@ -(component - (import "" (core module $m1 - (import "" "f" (func)) - )) - (core module $m2 - (func (export "f")) - ) - (core instance $i1 (instantiate $m2)) - (core instance $i2 (instantiate $m1 (with "" (instance $i1)))) -) diff --git a/tests/dump/import-modules.wat.dump b/tests/dump/import-modules.wat.dump deleted file mode 100644 index 024378c2d6..0000000000 --- a/tests/dump/import-modules.wat.dump +++ /dev/null @@ -1,38 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 03 0d | core type section - 0xa | 01 | 1 count - 0xb | 50 02 01 60 | [core type 0] Module([Type(Func(FuncType { params: [], returns: [] })), Import(Import { module: "", name: "f", ty: Func(0) })]) - | 00 00 00 00 - | 01 66 00 00 - 0x17 | 0a 05 | component import section - 0x19 | 01 | 1 count - 0x1a | 00 00 11 00 | [module 0] ComponentImport { name: "", ty: Module(0) } - 0x1e | 01 2b | [core module 1] inline size - 0x20 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x28 | 01 04 | type section - 0x2a | 01 | 1 count - 0x2b | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x2e | 03 02 | func section - 0x30 | 01 | 1 count - 0x31 | 00 | [func 0] type 0 - 0x32 | 07 05 | export section - 0x34 | 01 | 1 count - 0x35 | 01 66 00 00 | export Export { name: "f", kind: Func, index: 0 } - 0x39 | 0a 04 | code section - 0x3b | 01 | 1 count -============== func 0 ==================== - 0x3c | 02 | size of function - 0x3d | 00 | 0 local blocks - 0x3e | 0b | end - 0x3f | 00 0a | custom section - 0x41 | 04 6e 61 6d | name: "name" - | 65 - 0x46 | 00 03 | module name - 0x48 | 02 6d 32 | "m2" - 0x4b | 02 0a | core instance section - 0x4d | 02 | 2 count - 0x4e | 00 01 00 | [core instance 0] Instantiate { module_index: 1, args: [] } - 0x51 | 00 00 01 00 | [core instance 1] Instantiate { module_index: 0, args: [InstantiationArg { name: "", kind: Instance, index: 0 }] } - | 12 00 diff --git a/tests/dump/instance-expand.wat b/tests/dump/instance-expand.wat deleted file mode 100644 index 86d4db9843..0000000000 --- a/tests/dump/instance-expand.wat +++ /dev/null @@ -1,7 +0,0 @@ -(component - (type $i (instance - (export "" (func)) - )) - - (import "" (instance (type $i))) -) diff --git a/tests/dump/instance-expand.wat.dump b/tests/dump/instance-expand.wat.dump deleted file mode 100644 index 8ae675bee4..0000000000 --- a/tests/dump/instance-expand.wat.dump +++ /dev/null @@ -1,10 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 0d | component type section - 0xa | 01 | 1 count - 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "", ty: Func(0) }]) - | 01 00 01 00 - | 04 00 01 00 - 0x17 | 0a 04 | component import section - 0x19 | 01 | 1 count - 0x1a | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } diff --git a/tests/dump/instance-type.wat.dump b/tests/dump/instance-type.wat.dump deleted file mode 100644 index 245d86504d..0000000000 --- a/tests/dump/instance-type.wat.dump +++ /dev/null @@ -1,10 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 16 | component type section - 0xa | 02 | 2 count - 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "", ty: Func(0) }]) - | 01 00 01 00 - | 04 00 01 00 - 0x17 | 42 02 01 42 | [type 1] Instance([Type(Instance([])), Export { name: "", ty: Instance(0) }]) - | 00 04 00 05 - | 00 diff --git a/tests/dump/instance-type2.wat.dump b/tests/dump/instance-type2.wat.dump deleted file mode 100644 index 97890d5427..0000000000 --- a/tests/dump/instance-type2.wat.dump +++ /dev/null @@ -1,11 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 16 | component type section - 0xa | 04 | 4 count - 0xb | 42 00 | [type 0] Instance([]) - 0xd | 42 01 04 00 | [type 1] Instance([Export { name: "", ty: Instance(0) }]) - | 05 00 - 0x13 | 42 00 | [type 2] Instance([]) - 0x15 | 42 02 02 03 | [type 3] Instance([Alias(Outer { kind: Type, count: 1, index: 2 }), Export { name: "", ty: Instance(0) }]) - | 02 01 02 04 - | 00 05 00 diff --git a/tests/dump/instantiate.wat.dump b/tests/dump/instantiate.wat.dump deleted file mode 100644 index 816e976439..0000000000 --- a/tests/dump/instantiate.wat.dump +++ /dev/null @@ -1,19 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 03 | component type section - 0xa | 01 | 1 count - 0xb | 41 00 | [type 0] Component([]) - 0xd | 0a 05 | component import section - 0xf | 01 | 1 count - 0x10 | 01 61 04 00 | [component 0] ComponentImport { name: "a", ty: Component(0) } - 0x14 | 07 06 | component type section - 0x16 | 01 | 1 count - 0x17 | 40 01 00 01 | [type 1] Func(ComponentFuncType { params: Named([]), results: Named([]) }) - | 00 - 0x1c | 0a 05 | component import section - 0x1e | 01 | 1 count - 0x1f | 01 66 01 01 | [func 0] ComponentImport { name: "f", ty: Func(1) } - 0x23 | 05 08 | component instance section - 0x25 | 01 | 1 count - 0x26 | 00 00 01 01 | [instance 0] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "a", kind: Func, index: 0 }] } - | 61 01 00 diff --git a/tests/dump/instantiate2.wat b/tests/dump/instantiate2.wat deleted file mode 100644 index 99b04ee104..0000000000 --- a/tests/dump/instantiate2.wat +++ /dev/null @@ -1,4 +0,0 @@ -(component - (import "" (component $c (import "" (func)))) - (instance (instantiate $c)) -) diff --git a/tests/dump/instantiate2.wat.dump b/tests/dump/instantiate2.wat.dump deleted file mode 100644 index 7cd6cb2c52..0000000000 --- a/tests/dump/instantiate2.wat.dump +++ /dev/null @@ -1,13 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 0d | component type section - 0xa | 01 | 1 count - 0xb | 41 02 01 40 | [type 0] Component([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Import(ComponentImport { name: "", ty: Func(0) })]) - | 01 00 01 00 - | 03 00 01 00 - 0x17 | 0a 04 | component import section - 0x19 | 01 | 1 count - 0x1a | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } - 0x1d | 05 04 | component instance section - 0x1f | 01 | 1 count - 0x20 | 00 00 00 | [instance 0] Instantiate { component_index: 0, args: [] } diff --git a/tests/dump/module-types.wat.dump b/tests/dump/module-types.wat.dump deleted file mode 100644 index e2c1d896a8..0000000000 --- a/tests/dump/module-types.wat.dump +++ /dev/null @@ -1,19 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 03 23 | core type section - 0xa | 01 | 1 count - 0xb | 50 05 01 60 | [core type 0] Module([Type(Func(FuncType { params: [], returns: [] })), Import(Import { module: "", name: "f", ty: Func(0) }), Import(Import { module: "", name: "g", ty: Global(GlobalType { content_type: I32, mutable: false }) }), Import(Import { module: "", name: "t", ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) }), Import(Import { module: "", name: "m", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) })]) - | 00 00 00 00 - | 01 66 00 00 - | 00 00 01 67 - | 03 7f 00 00 - | 00 01 74 01 - | 70 00 01 00 - | 00 01 6d 02 - | 00 01 - 0x2d | 0a 05 | component import section - 0x2f | 01 | 1 count - 0x30 | 00 00 11 00 | [module 0] ComponentImport { name: "", ty: Module(0) } - 0x34 | 07 03 | component type section - 0x36 | 01 | 1 count - 0x37 | 42 00 | [type 0] Instance([]) diff --git a/tests/dump/names.wat.dump b/tests/dump/names.wat.dump deleted file mode 100644 index e74dc77d79..0000000000 --- a/tests/dump/names.wat.dump +++ /dev/null @@ -1,29 +0,0 @@ - 0x0 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x8 | 01 05 | type section - 0xa | 01 | 1 count - 0xb | 60 01 7f 00 | [type 0] Func(FuncType { params: [I32], returns: [] }) - 0xf | 03 02 | func section - 0x11 | 01 | 1 count - 0x12 | 00 | [func 0] type 0 - 0x13 | 0a 06 | code section - 0x15 | 01 | 1 count -============== func 0 ==================== - 0x16 | 04 | size of function - 0x17 | 01 | 1 local blocks - 0x18 | 01 7c | 1 locals of type F64 - 0x1a | 0b | end - 0x1b | 00 1c | custom section - 0x1d | 04 6e 61 6d | name: "name" - | 65 - 0x22 | 00 04 | module name - 0x24 | 03 66 6f 6f | "foo" - 0x28 | 01 04 | function names - 0x2a | 01 | 1 count - 0x2b | 00 01 66 | Naming { index: 0, name: "f" } - 0x2e | 02 09 | local names - 0x30 | 01 | 1 count - 0x31 | 00 | function 0 locals - 0x32 | 02 | 2 count - 0x33 | 00 01 78 | Naming { index: 0, name: "x" } - 0x36 | 01 01 79 | Naming { index: 1, name: "y" } diff --git a/tests/dump/nested-component.wat b/tests/dump/nested-component.wat deleted file mode 100644 index 714e77328d..0000000000 --- a/tests/dump/nested-component.wat +++ /dev/null @@ -1,23 +0,0 @@ - -(component - (component (import "")) - - (component) - (component) - - (component (export "x")) - - (component - (component) - ) - - (component - (core module $m) - (import "" (func (param string))) - (export "a" (core module $m)) - - (instance (export "b") (import "") - (export "b" (func)) - ) - ) -) diff --git a/tests/dump/nested-component.wat.dump b/tests/dump/nested-component.wat.dump deleted file mode 100644 index ecf043b61f..0000000000 --- a/tests/dump/nested-component.wat.dump +++ /dev/null @@ -1,60 +0,0 @@ - 0x0 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x8 | 07 03 | component type section - 0xa | 01 | 1 count - 0xb | 41 00 | [type 0] Component([]) - 0xd | 0a 04 | component import section - 0xf | 01 | 1 count - 0x10 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } - 0x13 | 04 08 | [component 1] inline size - 0x15 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x1d | 04 08 | [component 2] inline size - 0x1f | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x27 | 04 08 | [component 3] inline size - 0x29 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x31 | 04 12 | [component 4] inline size - 0x33 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x3b | 04 08 | [component 0] inline size - 0x3d | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x45 | 04 50 | [component 5] inline size - 0x47 | 00 61 73 6d | version 65546 (Component) - | 0a 00 01 00 - 0x4f | 01 13 | [core module 0] inline size - 0x51 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x59 | 00 09 | custom section - 0x5b | 04 6e 61 6d | name: "name" - | 65 - 0x60 | 00 02 | module name - 0x62 | 01 6d | "m" - 0x64 | 07 06 | component type section - 0x66 | 01 | 1 count - 0x67 | 40 00 73 01 | [type 0] Func(ComponentFuncType { params: Unnamed(Primitive(String)), results: Named([]) }) - | 00 - 0x6c | 0a 04 | component import section - 0x6e | 01 | 1 count - 0x6f | 00 01 00 | [func 0] ComponentImport { name: "", ty: Func(0) } - 0x72 | 0b 06 | component export section - 0x74 | 01 | 1 count - 0x75 | 01 61 00 11 | export ComponentExport { name: "a", kind: Module, index: 0 } - | 00 - 0x7a | 07 0e | component type section - 0x7c | 01 | 1 count - 0x7d | 42 02 01 40 | [type 1] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "b", ty: Func(0) }]) - | 01 00 01 00 - | 04 01 62 01 - | 00 - 0x8a | 0a 04 | component import section - 0x8c | 01 | 1 count - 0x8d | 00 05 01 | [instance 0] ComponentImport { name: "", ty: Instance(1) } - 0x90 | 0b 05 | component export section - 0x92 | 01 | 1 count - 0x93 | 01 62 05 00 | export ComponentExport { name: "b", kind: Instance, index: 0 } - 0x97 | 0b 05 | component export section - 0x99 | 01 | 1 count - 0x9a | 01 78 04 03 | export ComponentExport { name: "x", kind: Component, index: 3 } diff --git a/tests/dump/select.wat.dump b/tests/dump/select.wat.dump deleted file mode 100644 index 7b650d2628..0000000000 --- a/tests/dump/select.wat.dump +++ /dev/null @@ -1,20 +0,0 @@ - 0x0 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x8 | 01 04 | type section - 0xa | 01 | 1 count - 0xb | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0xe | 03 02 | func section - 0x10 | 01 | 1 count - 0x11 | 00 | [func 0] type 0 - 0x12 | 0a 0e | code section - 0x14 | 01 | 1 count -============== func 0 ==================== - 0x15 | 0c | size of function - 0x16 | 00 | 0 local blocks - 0x17 | 1b | select - 0x18 | 1c 00 | ?? - 0x1a | 1c 01 7f | typed_select ty:I32 - 0x1d | 1c 02 | ?? - 0x1f | 7f | i64_div_s - 0x20 | 7f | i64_div_s - 0x21 | 0b | end diff --git a/tests/dump/simple.wat.dump b/tests/dump/simple.wat.dump deleted file mode 100644 index 769e4ad54e..0000000000 --- a/tests/dump/simple.wat.dump +++ /dev/null @@ -1,73 +0,0 @@ - 0x0 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x8 | 01 08 | type section - 0xa | 02 | 2 count - 0xb | 60 01 7f 00 | [type 0] Func(FuncType { params: [I32], returns: [] }) - 0xf | 60 00 00 | [type 1] Func(FuncType { params: [], returns: [] }) - 0x12 | 02 07 | import section - 0x14 | 01 | 1 count - 0x15 | 01 6d 01 6e | import [func 0] Import { module: "m", name: "n", ty: Func(0) } - | 00 00 - 0x1b | 03 04 | func section - 0x1d | 03 | 3 count - 0x1e | 01 | [func 1] type 1 - 0x1f | 01 | [func 2] type 1 - 0x20 | 01 | [func 3] type 1 - 0x21 | 04 04 | table section - 0x23 | 01 | 1 count - 0x24 | 70 00 01 | [table 0] TableType { element_type: FuncRef, initial: 1, maximum: None } - 0x27 | 05 03 | memory section - 0x29 | 01 | 1 count - 0x2a | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None } - 0x2c | 06 06 | global section - 0x2e | 01 | 1 count - 0x2f | 7f 00 | [global 0] GlobalType { content_type: I32, mutable: false } - 0x31 | 41 00 | i32_const value:0 - 0x33 | 0b | end - 0x34 | 07 05 | export section - 0x36 | 01 | 1 count - 0x37 | 01 6d 02 00 | export Export { name: "m", kind: Memory, index: 0 } - 0x3b | 08 01 | start section - 0x3d | 00 | start function 0 - 0x3e | 09 0f | element section - 0x40 | 03 | 3 count - 0x41 | 00 | element FuncRef table[0] - 0x42 | 41 03 | i32_const value:3 - 0x44 | 0b | end - 0x45 | 01 | 1 items - 0x46 | 00 | item Func(0) - 0x47 | 01 00 01 | element FuncRef passive, 1 items - 0x4a | 00 | item Func(0) - 0x4b | 03 00 01 | element FuncRef declared 1 items - 0x4e | 00 | item Func(0) - 0x4f | 0a 10 | code section - 0x51 | 03 | 3 count -============== func 1 ==================== - 0x52 | 02 | size of function - 0x53 | 00 | 0 local blocks - 0x54 | 0b | end -============== func 2 ==================== - 0x55 | 04 | size of function - 0x56 | 01 | 1 local blocks - 0x57 | 01 7f | 1 locals of type I32 - 0x59 | 0b | end -============== func 3 ==================== - 0x5a | 06 | size of function - 0x5b | 01 | 1 local blocks - 0x5c | 01 7f | 1 locals of type I32 - 0x5e | 41 00 | i32_const value:0 - 0x60 | 0b | end - 0x61 | 0b 0a | data section - 0x63 | 02 | 2 count - 0x64 | 00 | data memory[0] - 0x65 | 41 08 | i32_const value:8 - 0x67 | 0b | end - 0x68 |-------------| ... 1 bytes of data - 0x6a | 01 01 | data passive - 0x6c |-------------| ... 1 bytes of data - 0x6d | 00 17 | custom section - 0x6f | 0f 6e 61 6d | name: "name-of-section" - | 65 2d 6f 66 - | 2d 73 65 63 - | 74 69 6f 6e - 0x7f |-------------| ... 7 bytes of data diff --git a/tests/dump/try-delegate.wat.dump b/tests/dump/try-delegate.wat.dump deleted file mode 100644 index 039f6cea8c..0000000000 --- a/tests/dump/try-delegate.wat.dump +++ /dev/null @@ -1,26 +0,0 @@ - 0x0 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x8 | 01 04 | type section - 0xa | 01 | 1 count - 0xb | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0xe | 03 02 | func section - 0x10 | 01 | 1 count - 0x11 | 00 | [func 0] type 0 - 0x12 | 0a 0b | code section - 0x14 | 01 | 1 count -============== func 0 ==================== - 0x15 | 09 | size of function - 0x16 | 00 | 0 local blocks - 0x17 | 06 40 | try ty:Empty - 0x19 | 06 40 | try ty:Empty - 0x1b | 18 00 | delegate relative_depth:0 - 0x1d | 0b | end - 0x1e | 0b | end - 0x1f | 00 0d | custom section - 0x21 | 04 6e 61 6d | name: "name" - | 65 - 0x26 | 03 06 | label names - 0x28 | 01 | 1 count - 0x29 | 00 | function 0 labels - 0x2a | 01 | 1 count - 0x2b | 00 01 6c | Naming { index: 0, name: "l" } diff --git a/tests/local/bad-nan.wast b/tests/local/bad-nan.wast new file mode 100644 index 0000000000..dc532723c6 --- /dev/null +++ b/tests/local/bad-nan.wast @@ -0,0 +1,11 @@ +(assert_malformed + (module quote "(func (result f64) (f64.const nan:0x11111111800800080))") + "constant out of range") + +(assert_malformed + (module quote "(func (result f64) (f64.const nan:0xffffffffffffffff0))") + "constant out of range") + +(assert_malformed + (module quote "(func (result f32) (f32.const nan:0xffffffff0))") + "constant out of range") diff --git a/tests/local/component-model/a.wast b/tests/local/component-model/a.wast index 6246ec2130..2527222d29 100644 --- a/tests/local/component-model/a.wast +++ b/tests/local/component-model/a.wast @@ -14,6 +14,6 @@ )) )) - (export "one" (value $v)) + (export "four" (value $v)) ;; ... ) diff --git a/tests/local/component-model/adapt.wast b/tests/local/component-model/adapt.wast index 51a0fc8a2d..7c5cb9ebda 100644 --- a/tests/local/component-model/adapt.wast +++ b/tests/local/component-model/adapt.wast @@ -1,5 +1,5 @@ (component - (import "log" (func $log (param string))) + (import "log" (func $log (param "msg" string))) (core module $libc (memory (export "memory") 1) (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) @@ -45,7 +45,7 @@ )) )) - (func (export "log1") (param string) + (func (export "log1") (param "msg" string) (canon lift (core func $my_instance "log-utf8") string-encoding=utf8 @@ -53,7 +53,7 @@ (realloc $realloc) ) ) - (func (export "log2") (param string) + (func (export "log2") (param "msg" string) (canon lift (core func $my_instance "log-utf16") string-encoding=utf16 @@ -61,7 +61,7 @@ (realloc $realloc) ) ) - (func (export "log3") (param string) + (func (export "log3") (param "msg" string) (canon lift (core func $my_instance "log-compact-utf16") string-encoding=latin1+utf16 @@ -73,35 +73,35 @@ (assert_invalid (component - (import "" (func $f)) + (import "i" (func $f)) (core func (canon lower (func $f) string-encoding=utf8 string-encoding=utf16)) ) "canonical encoding option `utf8` conflicts with option `utf16`") (assert_invalid (component - (import "" (func $f)) + (import "i" (func $f)) (core func (canon lower (func $f) string-encoding=utf8 string-encoding=latin1+utf16)) ) "canonical encoding option `utf8` conflicts with option `latin1-utf16`") (assert_invalid (component - (import "" (func $f)) + (import "i" (func $f)) (core func (canon lower (func $f) string-encoding=utf16 string-encoding=latin1+utf16)) ) "canonical encoding option `utf16` conflicts with option `latin1-utf16`") (assert_invalid (component - (import "" (func $f)) + (import "i" (func $f)) (core func (canon lower (func $f) (memory 0))) ) "memory index out of bounds") (assert_invalid (component - (import "" (func $f)) + (import "i" (func $f)) (core module $m (memory (export "memory") 1)) (core instance $i (instantiate $m)) (core func (canon lower (func $f) (memory $i "memory") (memory $i "memory"))) @@ -114,7 +114,7 @@ (func (export "f") (param i32 i32)) ) (core instance $i (instantiate $m)) - (func (param (list u8)) (canon lift (core func $i "f"))) + (func (param "p1" (list u8)) (canon lift (core func $i "f"))) ) "canonical option `memory` is required") @@ -125,7 +125,7 @@ (func (export "f") (param i32 i32)) ) (core instance $i (instantiate $m)) - (func (param (list u8)) + (func (param "p1" (list u8)) (canon lift (core func $i "f") (memory $i "m") ) @@ -141,7 +141,7 @@ (func (export "r") (param i32 i32 i32 i32) (result i32)) ) (core instance $i (instantiate $m)) - (func (param (list u8)) + (func (param "p1" (list u8)) (canon lift (core func $i "f") (memory $i "m") (realloc (func $i "r")) @@ -159,7 +159,7 @@ (func (export "r")) ) (core instance $i (instantiate $m)) - (func (param (list u8)) + (func (param "p1" (list u8)) (canon lift (core func $i "f") (memory $i "m") (realloc (func $i "r")) @@ -209,7 +209,7 @@ (assert_invalid (component - (import "" (func $f (param string))) + (import "i" (func $f (param "p1" string))) (core module $m (memory (export "m") 1) (func (export "f") (result i32)) @@ -252,7 +252,7 @@ (core instance $i (instantiate $m)) (core func (canon lower (func $i ""))) ) - "failed to find instance named `$i`") + "unknown instance: failed to find name `$i`") (assert_invalid (component @@ -281,7 +281,7 @@ (assert_invalid (component - (import "" (func $f)) + (import "a" (func $f)) (func (export "foo") (canon lift (core func $f))) ) - "failed to find core func named `$f`") + "unknown core func: failed to find name `$f`") diff --git a/tests/local/component-model/alias.wast b/tests/local/component-model/alias.wast index 61541abddb..bd4eb915e5 100644 --- a/tests/local/component-model/alias.wast +++ b/tests/local/component-model/alias.wast @@ -1,15 +1,15 @@ (component (import "i" (instance $i - (export "f1" (func $f1)) - (export "f2" (func $f2 (param string))) + (export "f1" (func)) + (export "f2" (func (param "p1" string))) )) (export "run" (func $i "f1")) ) (component (import "i" (component $c - (export "f1" (func $f1)) - (export "f2" (func $f2 (param string))) + (export "f1" (func)) + (export "f2" (func (param "p1" string))) )) (instance $i (instantiate $c)) (export "run" (func $i "f1")) @@ -28,7 +28,7 @@ ) (component - (import "" (core module $libc + (import "a" (core module $libc (export "memory" (memory 1)) (export "table" (table 0 funcref)) (export "func" (func)) @@ -60,18 +60,18 @@ ) (component - (import "" (instance $i - (export "1" (func)) - (export "2" (core module)) - (export "3" (instance)) + (import "a" (instance $i + (export "a" (func)) + (export "b" (core module)) + (export "c" (instance)) )) - (export "1" (func $i "1")) - (export "2" (core module $i "2")) - (export "3" (instance $i "3")) + (export "b" (func $i "a")) + (export "c" (core module $i "b")) + (export "d" (instance $i "c")) ) (component - (import "" (core module $libc + (import "a" (core module $libc (export "memory" (memory 1)) (export "table" (table 0 funcref)) (export "func" (func)) @@ -79,7 +79,7 @@ (export "global mut" (global (mut i64))) )) - (import "x" (core module $needs_libc + (import "b" (core module $needs_libc (import "" "memory" (memory 1)) (import "" "table" (table 0 funcref)) (import "" "func" (func)) @@ -99,44 +99,44 @@ (assert_invalid (component - (import "" (instance (export "" (func)))) - (export "" (core module 0 "")) + (import "a" (instance (export "a" (func)))) + (export "a" (core module 0 "a")) ) - "export `` for instance 0 is not a module") + "export `a` for instance 0 is not a module") (assert_invalid (component (component - (component (export "")) + (component (export "a")) ) (instance (instantiate 0)) - (export "" (core module 0 "")) + (export "a" (core module 0 "a")) ) - "export `` for instance 0 is not a module") + "export `a` for instance 0 is not a module") (assert_invalid (component - (import "" (core module)) + (import "a" (core module)) (core instance (instantiate 0)) - (alias core export 0 "" (core func)) + (alias core export 0 "a" (core func)) ) - "core instance 0 has no export named ``") + "core instance 0 has no export named `a`") (assert_invalid (component (core module) (core instance (instantiate 0)) - (alias core export 0 "" (core func)) + (alias core export 0 "a" (core func)) ) - "core instance 0 has no export named ``") + "core instance 0 has no export named `a`") (assert_invalid (component - (import "" (component)) + (import "a" (component)) (instance (instantiate 0)) - (alias export 0 "" (func)) + (alias export 0 "a" (func)) ) - "instance 0 has no export named ``") + "instance 0 has no export named `a`") (assert_invalid (component @@ -153,12 +153,12 @@ (component $PARENT (type $t (func (result string))) (component - (import "" (func (type $t))) + (import "a" (func (type $t))) ) (component (alias outer $PARENT $t (type $my_type)) (alias outer 0 $my_type (type $my_type_again)) - (import "" (func (type $my_type_again))) + (import "a" (func (type $my_type_again))) ) ) @@ -174,7 +174,7 @@ (import "b" (func $b (type $b))) (import "c" (func $c (type $c))) - (import "" (component $C + (import "d" (component $C (import "a" (func (result string))) (import "b" (func (result u32))) (import "c" (func (result s32))) @@ -192,36 +192,36 @@ ;; multiple projections in alias sugar (component $a - (import "" (instance $a - (export "b" (instance - (export "c" (instance - (export "d" (instance - (export "f" (func)) + (import "a" (instance $a + (export "a" (instance + (export "a" (instance + (export "a" (instance + (export "a" (func)) )) )) )) )) - (import "b" (component $b (import "" (func)))) + (import "b" (component $b (import "a" (func)))) (instance (instantiate $b - (with "" (func $a "b" "c" "d" "f")) + (with "a" (func $a "a" "a" "a" "a")) )) ) ;; alias some constructs (component - (import "" (instance $foo (export "v" (value s32)))) + (import "a" (instance $foo (export "v" (value s32)))) (export "v" (value $foo "v")) ) (component - (import "" (instance $foo (export "v" (component)))) + (import "a" (instance $foo (export "v" (component)))) (export "v" (component $foo "v")) ) (component - (import "" (instance $foo (export "v" (core module)))) + (import "a" (instance $foo (export "v" (core module)))) (export "v" (core module $foo "v")) ) @@ -273,7 +273,7 @@ "index out of bounds") (component - (import "" (instance $i + (import "a" (instance $i (export "x" (core module)) )) ;; inline alias injection sugar works for module references @@ -281,7 +281,7 @@ ) (component - (import "" (instance $i + (import "a" (instance $i (export "x" (component)) )) ;; inline alias injection sugar works for component references diff --git a/tests/local/component-model/big.wast b/tests/local/component-model/big.wast index 846f468b3e..367fdc9cc0 100644 --- a/tests/local/component-model/big.wast +++ b/tests/local/component-model/big.wast @@ -1,6 +1,6 @@ (component - (import "wasi:logging" (instance $logging - (export "log" (func (param string))) + (import "wasi-logging" (instance $logging + (export "log" (func (param "msg" string))) )) (import "libc" (core module $Libc (export "memory" (memory 1)) @@ -14,7 +14,7 @@ (core module $Main (import "libc" "memory" (memory 1)) (import "libc" "realloc" (func (param i32 i32 i32 i32) (result i32))) - (import "wasi:logging" "log" (func $log (param i32 i32))) + (import "wasi-logging" "log" (func $log (param i32 i32))) (func (export "run") (param i32 i32) (result i32) (local.get 0) (local.get 1) @@ -24,9 +24,9 @@ ) (core instance $main (instantiate $Main (with "libc" (instance $libc)) - (with "wasi:logging" (instance (export "log" (func $log)))) + (with "wasi-logging" (instance (export "log" (func $log)))) )) - (func $run (param string) (result string) (canon lift + (func $run (param "in" string) (result string) (canon lift (core func $main "run") (memory $libc "memory") (realloc (func $libc "realloc")) )) diff --git a/tests/local/component-model/definedtypes.wast b/tests/local/component-model/definedtypes.wast index 0f6e1f3984..76fb5bf684 100644 --- a/tests/local/component-model/definedtypes.wast +++ b/tests/local/component-model/definedtypes.wast @@ -13,8 +13,7 @@ (type $A12 char) (type $A13 string) - (type $A14a (record)) - (type $A14b (record (field "x" (tuple)))) + (type $A14b (record (field "x" (tuple char)))) (type $A14c (record (field "x" $A1))) (type $A15a (variant (case "x"))) @@ -22,22 +21,17 @@ (type $A15c (variant (case $x "x") (case $y "y" string (refines $x)) (case "z" string (refines $y)))) (type $A15d (variant (case "x") (case "y" string (refines 0)) (case "z" string (refines 1)))) - (type $A16a (list (tuple))) + (type $A16a (list (tuple u8))) (type $A16b (list $A3)) - (type $A17a (tuple)) + (type $A17a (tuple u8)) (type $A17b (tuple $A4)) - (type $A18a (flags)) (type $A18b (flags "x")) - (type $A19a (enum)) (type $A19b (enum "x")) - (type $A20a (union)) - (type $A20b (union $A5)) - - (type $A21a (option (tuple))) + (type $A21a (option (tuple u32))) (type $A21b (option $A6)) (type $A22a (result)) @@ -57,7 +51,7 @@ (component (type $t (variant (case "x" (refines $y)) (case $y "y" string))) ) - "failed to find variant case named `$y`" + "unknown variant case" ) (assert_invalid @@ -65,9 +59,10 @@ (type $t string) (type $v (variant (case "x" $t (refines $z)))) ) - "failed to find variant case named `$z`" + "unknown variant case" ) + (assert_invalid (component (type $t string) @@ -95,7 +90,7 @@ (assert_invalid (component (type $t (func)) - (type (func (param $t))) + (type (func (param "t" $t))) ) "type index 0 is not a defined type") @@ -125,9 +120,6 @@ (assert_invalid (component (type (variant (case "x" 0)))) "index out of bounds") -(assert_invalid - (component (type (union 0))) - "index out of bounds") (assert_invalid (component (type (result 0 (error 1)))) "index out of bounds") @@ -136,17 +128,17 @@ "index out of bounds") (assert_invalid - (component (type (record (field "x" string) (field "x" u8)))) - "duplicate field named `x` in record type") + (component (type (record (field "a-B-c-D" string) (field "A-b-C-d" u8)))) + "record field name `A-b-C-d` conflicts with previous field name `a-B-c-D`") (assert_invalid (component (type (variant (case "x" s64) (case "x" s64)))) - "duplicate case named `x` in variant type") + "variant case name `x` conflicts with previous case name `x`") (assert_invalid - (component (type (flags "x" "y" "x"))) - "duplicate flag named `x`") + (component (type (flags "x" "y" "X"))) + "flag name `X` conflicts with previous flag name `x`") (assert_invalid - (component (type (enum "x" "y" "x"))) - "duplicate enum tag named `x`") + (component (type (enum "x" "y" "X"))) + "enum tag name `X` conflicts with previous tag name `x`") (assert_invalid (component (type (record (field "" s32)))) diff --git a/tests/local/component-model/export-ascription.wast b/tests/local/component-model/export-ascription.wast new file mode 100644 index 0000000000..f44d9d248b --- /dev/null +++ b/tests/local/component-model/export-ascription.wast @@ -0,0 +1,38 @@ +(component + (import "f" (func $f)) + (export "f2" (func $f) (func)) +) + +;; subtyping works +(component + (import "f" (instance $i (export "f" (func)))) + (export "f2" (instance $i) (instance)) +) + +;; make sure subtyping works in the right direction +(assert_invalid + (component + (import "f" (instance $i)) + (export "f2" (instance $i) (instance (export "f" (func)))) + ) + "ascribed type of export is not compatible") + +;; make sure the type is actually changed +(assert_invalid + (component + (import "f" (func $f)) + + (component $c + (import "f" (instance $i (export "f" (func)))) + (export "f2" (instance $i) (instance)) + ) + + (instance $c (instantiate $c (with "f" (instance (export "f" (func $f)))))) + + (component $consume + (import "arg" (instance $i (export "f" (func)))) + ) + + (instance (instantiate $consume (with "arg" (instance $c "f2")))) + ) + "missing expected export `f`") diff --git a/tests/local/component-model/export-introduces-alias.wast b/tests/local/component-model/export-introduces-alias.wast new file mode 100644 index 0000000000..4a0f602153 --- /dev/null +++ b/tests/local/component-model/export-introduces-alias.wast @@ -0,0 +1,44 @@ +(component + (import "x" (func $f)) + + (export $g "g" (func $f)) + (export $g2 "g2" (func $g)) +) + +(component + (type (component + (type $t u8) + (import "x" (instance $i (export "t" (type (eq $t))))) + (alias export $i "t" (type $my-t)) + )) +) + +(component + (type (component + (type $t u8) + (import "x" (instance $i + (export "i" (instance + (export "t" (type (eq $t))) + )) + )) + (alias export $i "i" (instance $my-i)) + (alias export $my-i "t" (type $my-t)) + )) +) + +(assert_invalid + (component + (type (instance + (type $t u8) + (export $t "t" (type (eq $t))) + )) + ) + "duplicate type identifier") + +(component + (type (instance + (type $t u8) + (export $t2 "t" (type (eq $t))) + (export $t3 "t2" (type (eq $t2))) + )) +) diff --git a/tests/local/component-model/export.wast b/tests/local/component-model/export.wast index 2cb0238dd9..e9d6146b4b 100644 --- a/tests/local/component-model/export.wast +++ b/tests/local/component-model/export.wast @@ -19,23 +19,35 @@ "index out of bounds") (component - (import "1" (instance $i)) - (import "2" (core module $m)) - (import "3" (component $c)) - (import "4" (value $v string)) - (import "5" (func $f)) - - (export "1" (instance $i)) - (export "2" (core module $m)) - (export "3" (component $c)) - (export "4" (value $v)) - (export "5" (func $f)) + (import "a" (instance $i)) + (import "b" (core module $m)) + (import "c" (component $c)) + (import "d" (value $v string)) + (import "e" (func $f)) + + (export "f" (instance $i)) + (export "g" (core module $m)) + (export "h" (component $c)) + (export "i" (value $v)) + (export "j" (func $f)) ) (assert_invalid (component - (import "" (value $v string)) - (export "1" (value $v)) - (export "2" (value $v)) + (import "a" (value $v string)) + (export "b" (value $v)) + (export "c" (value $v)) ) "cannot be used more than once") + + +(component + (import "a" (func)) + (export (interface "wasi:http/types@2.0.0") (func 0)) +) + +;; import/exports can overlap on ids +(component + (import (interface "wasi:http/types@2.0.0") (func)) + (export (interface "wasi:http/types@2.0.0") (func 0)) +) diff --git a/tests/local/component-model/func.wast b/tests/local/component-model/func.wast index c9c63c0e47..0dceec979b 100644 --- a/tests/local/component-model/func.wast +++ b/tests/local/component-model/func.wast @@ -1,22 +1,15 @@ (component - (import "" (func (param "foo" string))) - (import "a" (func (param "foo" string) (param "bar" s32) (param "baz" u32))) - (import "b" (func (result "foo" (tuple)))) - (import "c" (func (result "foo" string) (result "bar" s32) (result "baz" u32))) + (import "a" (func (param "foo" string))) + (import "b" (func (param "foo" string) (param "bar" s32) (param "baz" u32))) + (import "c" (func (result "foo" (tuple u8)))) + (import "d" (func (result "foo" string) (result "bar" s32) (result "baz" u32))) ) (component - (import "" (func)) - (import "a" (func (param string))) - (import "b" (func (result u32))) - (import "c" (func (param bool) (result string))) -) - -(assert_invalid - (component - (import "a" (func (param "foo" string) (param s32) (param "bar" u32))) - ) - "function parameter name cannot be empty" + (import "a" (func)) + (import "b" (func (param "p1" string))) + (import "c" (func (result u32))) + (import "d" (func (param "p1" bool) (result string))) ) (assert_invalid @@ -28,16 +21,16 @@ (assert_invalid (component - (type (func (param "foo" string) (param "foo" u32))) + (type (func (param "foo" string) (param "FOO" u32))) ) - "duplicate parameter name" + "function parameter name `FOO` conflicts with previous parameter name `foo`" ) (assert_invalid (component - (type (func (result "foo" string) (result "foo" u32))) + (type (func (result "FOO" string) (result "foo" u32))) ) - "duplicate result name" + "function result name `foo` conflicts with previous result name `FOO`" ) (assert_invalid @@ -56,7 +49,7 @@ ) (component - (import "" (func $log (param string))) + (import "a" (func $log (param "msg" string))) (core module $libc (memory (export "memory") 1) ) @@ -78,10 +71,10 @@ (component (type $big (func - (param "1" u32) (param "2" u32) (param "3" u32) (param "4" u32) (param "5" u32) - (param "6" u32) (param "7" u32) (param "8" u32) (param "9" u32) (param "10" u32) - (param "11" u32) (param "12" u32) (param "13" u32) (param "14" u32) (param "15" u32) - (param "16" u32) (param "17" u32) (param "18" u32) (param "19" u32) (param "20" u32) + (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) + (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) + (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) + (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) )) (component $c @@ -101,10 +94,10 @@ (core instance $m (instantiate $m)) (type $roundtrip (func - (param "1" u32) (param "2" u32) (param "3" u32) (param "4" u32) (param "5" u32) - (param "6" u32) (param "7" u32) (param "8" u32) (param "9" u32) (param "10" u32) - (param "11" u32) (param "12" u32) (param "13" u32) (param "14" u32) (param "15" u32) - (param "16" u32) (param "17" u32) (param "18" u32) (param "19" u32) (param "20" u32) + (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) + (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) + (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) + (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) )) (func $roundtrip (type $roundtrip) @@ -117,7 +110,7 @@ (assert_invalid (component - (import "" (func $log (result string))) + (import "a" (func $log (result string))) (core module $libc (memory (export "memory") 1) ) @@ -135,7 +128,7 @@ ) (core instance $i (instantiate $m)) - (func (export "param-list") (param (list u8)) + (func (export "param-list") (param "bytes" (list u8)) (canon lift (core func $i "param-list") (memory $i "memory")) ) ) diff --git a/tests/local/component-model/import.wast b/tests/local/component-model/import.wast index 1dd9de2afe..f5509298a8 100644 --- a/tests/local/component-model/import.wast +++ b/tests/local/component-model/import.wast @@ -2,11 +2,11 @@ (import "a" (func)) (import "b" (instance)) (import "c" (instance - (export "" (func)) + (export "a" (func)) )) (import "d" (component - (import "" (core module)) - (export "" (func)) + (import "a" (core module)) + (export "b" (func)) )) (type $t (func)) (import "e" (type (eq $t))) @@ -15,21 +15,21 @@ (assert_invalid (component (type $f (func)) - (import "" (instance (type $f))) + (import "a" (instance (type $f))) ) "type index 0 is not an instance type") (assert_invalid (component (core type $f (func)) - (import "" (core module (type $f))) + (import "a" (core module (type $f))) ) "core type index 0 is not a module type") (assert_invalid (component (type $f string) - (import "" (func (type $f))) + (import "a" (func (type $f))) ) "type index 0 is not a function type") @@ -69,23 +69,23 @@ (assert_malformed (component quote - "(import \"\" (func))" - "(import \"\" (func))" + "(import \"a\" (func))" + "(import \"a\" (func))" ) - "duplicate import name `` already defined") + "import name `a` conflicts with previous name `a`") (assert_malformed (component quote "(type (component" - "(import \"\" (func))" - "(import \"\" (func))" + "(import \"a\" (func))" + "(import \"a\" (func))" "))" ) - "duplicate import name `` already defined") + "import name `a` conflicts with previous name `a`") (assert_invalid (component - (import "" (func (type 100))) + (import "a" (func (type 100))) ) "type index out of bounds") @@ -99,11 +99,90 @@ (assert_invalid (component - (import "" (value string)) + (import "a" (value string)) ) "value index 0 was not used as part of an instantiation, start function, or export") (component - (import "" (value string)) - (export "" (value 0)) + (import "a" (value string)) + (export "b" (value 0)) ) + +(component + (import (interface "wasi:http/types") (func)) + (import (interface "wasi:http/types@1.0.0") (func)) + (import (interface "wasi:http/types@2.0.0") (func)) + (import (interface "a-b:c-d/e-f@123456.7890.488") (func)) + (import (interface "a:b/c@1.2.3") (func)) + (import (interface "a:b/c@0.0.0") (func)) + (import (interface "a:b/c@0.0.0+abcd") (func)) + (import (interface "a:b/c@0.0.0+abcd-efg") (func)) + (import (interface "a:b/c@0.0.0-abcd+efg") (func)) + (import (interface "a:b/c@0.0.0-abcd.1.2+efg.4.ee.5") (func)) +) + +(assert_invalid + (component + (import (interface "wasi:http/types") (func)) + (import (interface "wasi:http/types") (func)) + ) + "conflicts with previous name") + +(assert_invalid + (component (import (interface "") (func))) + "failed to find `:` character") +(assert_invalid + (component (import (interface "wasi") (func))) + "failed to find `:` character") +(assert_invalid + (component (import (interface "wasi:") (func))) + "failed to find `/` character") +(assert_invalid + (component (import (interface "wasi:/") (func))) + "not in kebab case") +(assert_invalid + (component (import (interface ":/") (func))) + "not in kebab case") +(assert_invalid + (component (import (interface "wasi/http") (func))) + "failed to find `:` character") +(assert_invalid + (component (import (interface "wasi:http/TyPeS") (func))) + "`TyPeS` is not in kebab case") +(assert_invalid + (component (import (interface "WaSi:http/types") (func))) + "`WaSi` is not in kebab case") +(assert_invalid + (component (import (interface "wasi:HtTp/types") (func))) + "`HtTp` is not in kebab case") +(assert_invalid + (component (import (interface "wasi:http/types@") (func))) + "empty string") +(assert_invalid + (component (import (interface "wasi:http/types@.") (func))) + "unexpected character '.'") +(assert_invalid + (component (import (interface "wasi:http/types@1.") (func))) + "unexpected end of input") +(assert_invalid + (component (import (interface "wasi:http/types@a.2") (func))) + "unexpected character 'a'") +(assert_invalid + (component (import (interface "wasi:http/types@2.b") (func))) + "unexpected character 'b'") +(assert_invalid + (component (import (interface "wasi:http/types@2.0x0") (func))) + "unexpected character 'x'") +(assert_invalid + (component (import (interface "wasi:http/types@2.0.0+") (func))) + "empty identifier segment") +(assert_invalid + (component (import (interface "wasi:http/types@2.0.0-") (func))) + "empty identifier segment") + +(assert_invalid + (component + (import "a" (func $a)) + (export "a" (func $a)) + ) + "export name `a` conflicts with previous name `a`") diff --git a/tests/local/component-model/inline-exports.wast b/tests/local/component-model/inline-exports.wast new file mode 100644 index 0000000000..649c30c9e1 --- /dev/null +++ b/tests/local/component-model/inline-exports.wast @@ -0,0 +1,7 @@ +(component + (type (export "foo") u8) +) + +(assert_malformed + (component quote "(type (component (type (export \"\") (func))))") + "unexpected token") diff --git a/tests/local/component-model/instance-type.wast b/tests/local/component-model/instance-type.wast index dd597dacc2..5cdfbbf6ce 100644 --- a/tests/local/component-model/instance-type.wast +++ b/tests/local/component-model/instance-type.wast @@ -11,8 +11,8 @@ ;; functions (export "a" (func)) (export "b" (func $foo)) - (export "c" (func (@name "bar"))) - (export "d" (func $foo (@name "bar"))) + (export "c" (func)) + (export "d" (func $foo)) (export "e" (func (type $local_type))) (export "f" (func (param i32))) (export "g" (func (param i32) (result i32 i64))) @@ -39,49 +39,49 @@ ;; functions (export "a" (func)) (export "a2" (func (type $local_type))) - (export "b" (func $foo)) - (export "c" (func (@name "bar"))) - (export "d" (func $foo (@name "bar"))) + (export "b" (func)) + (export "c" (func)) + (export "d" (func)) (export "e" (func (type $t))) - (export "f" (func (param string))) - (export "g" (func (param s32) (result u32))) + (export "f" (func (param "f" string))) + (export "g" (func (param "g" s32) (result u32))) (export "h" (func (type $t))) ;; components (type $component_type (component)) (export "c1" (component)) - (export "c2" (component (import "" (func)))) - (export "c3" (component (export "" (func)))) + (export "c2" (component (import "i1" (func)))) + (export "c3" (component (export "e1" (func)))) (export "c4" (component (type $component_type))) (export "c5" (component (type $nested_func_type (func)) (alias outer $outer $local_type (type $my_type)) - (import "1" (func (type $nested_func_type))) - (import "2" (component)) - (export "1" (func (type $my_type))) - (export "2" (component)) + (import "i1" (func (type $nested_func_type))) + (import "i2" (component)) + (export "e1" (func (type $my_type))) + (export "e2" (component)) )) )) ) ;; expand inline types (component - (type (instance (export "" (instance)))) + (type (instance (export "a" (instance)))) ) ;; reference outer types (component (type (instance (type $t (instance)) - (export "" (instance (type $t))) + (export "a" (instance (type $t))) )) (type $x (instance)) - (type (instance (export "" (instance (type $x))))) + (type (instance (export "a" (instance (type $x))))) ) ;; recursive (component - (type (instance (export "" (core module + (type (instance (export "a" (core module (type $functype (func)) (export "a" (func)) @@ -135,15 +135,15 @@ (type (component (import "a" (func)) (import "b" (func (type $empty))) - (import "c" (func (param s32))) - (import "d" (func (param s32) (result s32))) + (import "c" (func (param "c" s32))) + (import "d" (func (param "d" s32) (result s32))) (import "h" (instance)) (import "i" (instance (type $i))) (import "j" (instance (export "a" (func)) (export "b" (func (type $empty))) - (export "c" (func (param s32))) + (export "c" (func (param "c" s32))) )) (import "k" (core module)) @@ -155,17 +155,17 @@ (export "b" (func (param i32))) )) - (export "a" (func)) - (export "e" (func (type $empty))) - (export "f" (func (param s32))) + (export "m" (func)) + (export "n" (func (type $empty))) + (export "o" (func (param "f" s32))) - (export "g" (instance + (export "p" (instance (export "a" (func)) (export "b" (func (type $empty))) - (export "c" (func (param s32))) + (export "c" (func (param "c" s32))) )) - (export "h" (core module + (export "q" (core module (type $empty (func)) (import "" "a" (func (type $empty))) (import "" "b" (func (param i32))) @@ -178,15 +178,15 @@ (assert_invalid (component (type (instance - (export "" (func)) - (export "" (func))))) - "duplicate export name") + (export "a" (func)) + (export "a" (func))))) + "export name `a` conflicts with previous name `a`") (assert_invalid (component (type $t (func)) (type (instance - (export "" (instance (type $t))) + (export "a" (instance (type $t))) ))) "type index 0 is not an instance type") @@ -194,7 +194,7 @@ (component (core type $t (func)) (type (instance - (export "" (core module (type $t))) + (export "a" (core module (type $t))) ))) "core type index 0 is not a module type") @@ -202,15 +202,15 @@ (component (type $t (func)) (type (instance - (export "" (core module (type $t))) + (export "a" (core module (type $t))) ))) - "failed to find core type named `$t`") + "unknown core type") (assert_invalid (component (type $t (record (field "a" string))) (type (instance - (export "" (func (type $t))) + (export "a" (func (type $t))) ))) "type index 0 is not a function type") @@ -218,7 +218,7 @@ (component (type $t (instance)) (type (instance - (export "" (func (type $t))) + (export "a" (func (type $t))) ))) "type index 0 is not a function type") @@ -226,8 +226,8 @@ (component (type $t (instance)) (type (instance - (export "" (instance - (export "" (func (type $t))) + (export "a" (instance + (export "a" (func (type $t))) )) ))) "type index 0 is not a function type") diff --git a/tests/local/component-model/instantiate.wast b/tests/local/component-model/instantiate.wast index 66cd4cfcc7..15ea7ef371 100644 --- a/tests/local/component-model/instantiate.wast +++ b/tests/local/component-model/instantiate.wast @@ -1,35 +1,35 @@ (component - (import "" (core module $m)) + (import "a" (core module $m)) (core instance $a (instantiate $m)) ) (component (import "a" (func $i)) - (import "" (component $c (import "a" (func)))) + (import "b" (component $c (import "a" (func)))) (instance (instantiate $c (with "a" (func $i)))) ) (component (import "a" (value $i string)) - (import "" (component $c (import "a" (value string)))) + (import "b" (component $c (import "a" (value string)))) (instance (instantiate $c (with "a" (value $i)))) ) (component (import "a" (component $i)) - (import "" (component $c (import "a" (component)))) + (import "b" (component $c (import "a" (component)))) (instance (instantiate $c (with "a" (component $i)))) ) (component (import "a" (core module $i)) - (import "" (component $c (import "a" (core module)))) + (import "b" (component $c (import "a" (core module)))) (instance (instantiate $c (with "a" (core module $i)))) ) (component (import "a" (instance $i)) - (import "" (component $c (import "a" (instance)))) + (import "b" (component $c (import "a" (instance)))) (instance (instantiate $c (with "a" (instance $i)))) ) @@ -76,13 +76,13 @@ (component (type $t string) (import "a" (value (type $t))) - (component $c (import "a" (value string)) (export "a" (value 0))) + (component $c (import "a" (value string)) (export "b" (value 0))) (instance (instantiate $c (with "a" (value 0)))) ) (component (import "a" (component $m - (import "" (instance + (import "a" (instance (export "a" (core module)) )) )) @@ -91,7 +91,7 @@ )) (instance $x (instantiate $m2)) - (instance (instantiate $m (with "" (instance + (instance (instantiate $m (with "a" (instance (export "a" (core module $x "b")) )))) ) @@ -122,14 +122,14 @@ (core instance $c (instantiate $m)) (core instance (instantiate $m)) - + ;; inline exports/imports (type $empty (instance)) - (instance $d (import "i1") (type $empty)) - (instance (import "i2")) - (instance (import "i3") + (instance $d (import "g") (type $empty)) + (instance (import "h")) + (instance (import "i") (export "x" (func))) - (instance (export "c") (export "d") (import "x")) + (instance (export "j") (export "k") (import "x")) ) (assert_invalid @@ -144,7 +144,7 @@ "unknown component") (assert_invalid (component - (import "" (core module)) + (import "a" (core module)) (core instance (instantiate 1)) ) "unknown module") @@ -156,109 +156,120 @@ ) (assert_invalid (component - (import "" (core module $m (import "" "" (func)))) + (import "a" (core module $m (import "" "" (func)))) (core instance (instantiate $m)) ) "missing module instantiation argument") (assert_invalid (component - (import "" (component $m (import "" (func)))) + (import "a" (component $m (import "a" (func)))) (instance (instantiate $m)) ) - "missing component instantiation argument") + "missing import named `a`") (assert_invalid (component - (import "" (component $m - (import "" (func)) + (import "a" (component $m + (import "a" (func)) )) - (import "i" (component $c)) - (instance $i (instantiate $m (with "" (component $c)))) + (import "b" (component $c)) + (instance $i (instantiate $m (with "a" (component $c)))) ) - "to be of type `function`") + "expected func, found component") -(component - (import "" (component $m - (import "" (func)) - )) - (import "i" (func $f (result string))) - (instance $i (instantiate $m (with "" (func $f)))) -) +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (func $f (result string))) + (instance $i (instantiate $m (with "a" (func $f)))) + ) + "expected 0 results, found 1") (assert_invalid (component - (import "" (component $m - (import "" (func)) + (import "a" (component $m + (import "a" (func)) )) - (import "i" (func (param string))) - (instance $i (instantiate $m (with "" (func 0)))) + (import "b" (func (param "i" string))) + (instance $i (instantiate $m (with "a" (func 0)))) ) - "function type mismatch") + "expected 0 parameters, found 1") (assert_invalid (component - (import "" (component $m - (import "" (core module + (import "a" (component $m + (import "a" (core module (import "" "" (func)) )) )) - (import "i" (core module $i + (import "b" (core module $i (import "" "" (global i32)) )) - (instance $i (instantiate $m (with "" (core module $i)))) + (instance $i (instantiate $m (with "a" (core module $i)))) ) - "module type mismatch") + "type mismatch in import `::`") (assert_invalid (component - (import "" (component $m - (import "" (core module)) + (import "a" (component $m + (import "a" (core module)) )) - (import "i" (core module $i + (import "b" (core module $i (import "" "foobar" (global i32)) )) - (instance $i (instantiate $m (with "" (core module $i)))) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "missing expected import `::foobar`") +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module (export "x" (func)))) + )) + (import "b" (core module $i)) + (instance $i (instantiate $m (with "a" (core module $i)))) ) - "module type mismatch") + "missing expected export `x`") ;; it's ok to give a module with fewer imports (component - (import "" (component $m - (import "" (core module + (import "a" (component $m + (import "a" (core module (import "" "" (global i32)) (import "" "f" (func)) )) )) - (import "i" (core module $i + (import "b" (core module $i (import "" "" (global i32)) )) - (instance $i (instantiate $m (with "" (core module $i)))) + (instance $i (instantiate $m (with "a" (core module $i)))) ) ;; export subsets (component - (import "" (component $m - (import "" (core module + (import "a" (component $m + (import "a" (core module (export "" (func)) )) )) - (import "i" (core module $i + (import "b" (core module $i (export "" (func)) (export "a" (func)) )) - (instance $i (instantiate $m (with "" (core module $i)))) + (instance $i (instantiate $m (with "a" (core module $i)))) ) (component - (import "" (component $m - (import "" (instance - (export "" (func)) + (import "a" (component $m + (import "a" (instance + (export "a" (func)) )) )) - (import "a" (instance $i - (export "" (func)) + (import "b" (instance $i (export "a" (func)) + (export "b" (func)) )) - (instance (instantiate $m (with "" (instance $i)))) + (instance (instantiate $m (with "a" (instance $i)))) ) @@ -272,7 +283,7 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "function type mismatch") + "expected: [] -> []") (assert_invalid (component (import "m1" (core module $m1 (import "" "" (func)))) @@ -280,7 +291,7 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "function type mismatch") + "expected: [] -> []") (assert_invalid (component (import "m1" (core module $m1 (import "" "" (global i32)))) @@ -288,7 +299,7 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "global type mismatch") + "expected global type i32, found i64") (assert_invalid (component (import "m1" (core module $m1 (import "" "" (table 1 funcref)))) @@ -296,7 +307,7 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "table type mismatch") + "expected table element type funcref, found externref") (assert_invalid (component (import "m1" (core module $m1 (import "" "" (table 1 2 funcref)))) @@ -304,7 +315,7 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "table type mismatch") + "mismatch in table limits") (assert_invalid (component (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) @@ -312,7 +323,7 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "table type mismatch") + "mismatch in table limits") (assert_invalid (component (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) @@ -320,7 +331,7 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "table type mismatch") + "mismatch in table limits") (assert_invalid (component (import "m1" (core module $m1 (import "" "" (memory 1 2 shared)))) @@ -328,7 +339,7 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "memory type mismatch") + "mismatch in the shared flag for memories") (assert_invalid (component (import "m1" (core module $m1 (import "" "" (memory 1)))) @@ -336,7 +347,16 @@ (core instance $i (instantiate $m2)) (core instance (instantiate $m1 (with "" (instance $i)))) ) - "memory type mismatch") + "mismatch in memory limits") +(assert_invalid + (component + (import "m1" (core module $m1 (export "g" (func)))) + (component $c + (import "m" (core module (export "g" (global i32)))) + ) + (instance (instantiate $c (with "m" (core module $m1)))) + ) + "type mismatch in export `g`") (assert_invalid (component @@ -434,27 +454,27 @@ (with "" (instance $i)) )) ) - "module instantiation argument `` exports an item named `` but it is not a global") + "expected global, found func") (assert_invalid (component (component $m) (instance $i (instantiate $m)) (instance (instantiate $m - (with "" (instance $i)) - (with "" (instance $i)) + (with "a" (instance $i)) + (with "a" (instance $i)) )) ) - "duplicate component instantiation argument named ``") + "instantiation argument `a` conflicts with previous argument `a`") (assert_invalid (component - (component $c (import "" (func))) + (component $c (import "a" (func))) (instance (instantiate $c - (with "" (component $c)) + (with "a" (component $c)) )) ) - "expected component instantiation argument `` to be of type `function`") + "expected func, found component") (assert_invalid (component @@ -505,24 +525,24 @@ (component (component $c) (instance - (export "" (component $c)) - (export "" (component $c)) + (export "a" (component $c)) + (export "a" (component $c)) ) ) - "export name `` already defined") + "instance export name `a` conflicts with previous name `a`") (component - (import "1" (instance $i)) - (import "2" (func $f)) - (import "3" (component $c)) - (import "4" (core module $m)) - (import "5" (value $v string)) + (import "a" (instance $i)) + (import "b" (func $f)) + (import "c" (component $c)) + (import "d" (core module $m)) + (import "e" (value $v string)) (instance - (export "1" (instance $i)) - (export "2" (func $f)) - (export "3" (component $c)) - (export "4" (core module $m)) - (export "5" (value $v)) + (export "a" (instance $i)) + (export "b" (func $f)) + (export "c" (component $c)) + (export "d" (core module $m)) + (export "e" (value $v)) ) ) @@ -557,19 +577,19 @@ (component (component $c) (instance $i (instantiate $c)) - (export "" (instance $i "")) + (export "a" (instance $i "a")) ) - "no export named ``") + "no export named `a`") (assert_invalid (component - (export "" (instance 100 "")) + (export "a" (instance 100 "a")) ) "index out of bounds") (assert_invalid (component - (import "" (core module $libc + (import "a" (core module $libc (export "memory" (memory 1)) (export "table" (table 0 funcref)) (export "func" (func)) @@ -598,3 +618,376 @@ ) ) "module instantiation argument `` does not export an item named `table`") + +;; Ensure a type can be an instantiation argument +(component + (type (tuple u32 u32)) + (import "a" (type (eq 0))) + (component + (type (tuple u32 u32)) + (import "a" (type (eq 0))) + ) + (instance (instantiate 0 + (with "a" (type 1)) + ) + ) +) + +(assert_invalid + (component + (type $t (tuple string string)) + (import "a" (type $a (eq $t))) + (component $c + (type $t (tuple u32 u32)) + (import "a" (type (eq $t))) + ) + (instance (instantiate $c + (with "a" (type $a)) + ) + ) + ) + "expected primitive `u32` found primitive `string`") + + +;; subtyping for module imports reverses order of imports/exports for the +;; subtyping check +;; +;; Here `C` imports a module, and the module itself imports a table of min size +;; 1. A module import which imports a min-size table of 0, however, is valid to +;; supply for this since it'll already be given at least 1 anyway. +;; +;; Similarly for exports `C` imports a module that exports a table of at least +;; size 1. If it's given a module that exports a larger table that's ok too. +(component + (core module $a + (import "" "" (table 0 funcref)) + (table (export "x") 2 funcref) + ) + (component $C + (import "a" (core module + (import "" "" (table 1 funcref)) + (export "x" (table 1 funcref)) + )) + ) + (instance (instantiate $C (with "a" (core module $a)))) +) + +;; same as above but for memories +(component + (core module $a1 (import "" "" (memory 0))) + (core module $a2 (memory (export "x") 2)) + (component $C + (import "a1" (core module (import "" "" (memory 1)))) + (import "a2" (core module (export "x" (memory 1)))) + ) + (instance (instantiate $C + (with "a1" (core module $a1)) + (with "a2" (core module $a2)) + )) +) + +(assert_invalid + (component + (import "x" (func $x (param "x" u32))) + (import "y" (component $c + (import "x" (func (param "y" u32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "expected parameter named `y`, found `x`") +(assert_invalid + (component + (import "x" (func $x (param "x" u32))) + (import "y" (component $c + (import "x" (func (param "x" s32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "type mismatch in function parameter `x`") +(assert_invalid + (component + (import "x" (func $x (result "x" u32))) + (import "y" (component $c + (import "x" (func (result "y" u32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "mismatched result names") +(assert_invalid + (component + (import "x" (func $x (result "x" u32))) + (import "y" (component $c + (import "x" (func (result "x" s32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "type mismatch with result type") + +(assert_invalid + (component + (import "x" (instance $x (export "a" (func)))) + (import "y" (component $c + (import "x" (instance $x (export "a" (component)))) + )) + + (instance (instantiate $c (with "x" (instance $x)))) + ) + "type mismatch in instance export `a`") + +(assert_invalid + (component + (import "y" (component $c + (type $t u32) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "f" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected primitive, found record") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "f" u32))) + (import "x" (type (eq $t))) + )) + + (type $x u32) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected record, found u32") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $f (tuple u8)) + (type $x (record (field "x" $f))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected u32, found tuple") + +(assert_invalid + (component + (import "y" (component $c + (type $f (option s32)) + (type $t (record (field "x" $f))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "x" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in record field `x`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "y" u32) (field "z" u64))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 fields, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "a" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "b" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected field name `a`, found `b`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" u32) (case "y" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 cases, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "y" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case named `x`, found `y`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x"))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case `x` to have a type, found none") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x"))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case `x` to have no type") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" s32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in variant case `x`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (tuple u8)) + (import "x" (type (eq $t))) + )) + + (type $x (tuple u32 u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 types, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (tuple u8)) + (import "x" (type (eq $t))) + )) + + (type $x (tuple u16)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in tuple field 0") + +(assert_invalid + (component + (import "y" (component $c + (type $t (flags "a")) + (import "x" (type (eq $t))) + )) + + (type $x (flags "x")) + (instance (instantiate $c (with "x" (type $x)))) + ) + "mismatch in flags elements") + +(assert_invalid + (component + (import "y" (component $c + (type $t (enum "a")) + (import "x" (type (eq $t))) + )) + + (type $x (enum "x")) + (instance (instantiate $c (with "x" (type $x)))) + ) + "mismatch in enum elements") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result s32)) + (import "x" (type (eq $t))) + )) + + (type $x (result u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in ok variant") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result (error s32))) + (import "x" (type (eq $t))) + )) + + (type $x (result (error u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in err variant") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result)) + (import "x" (type (eq $t))) + )) + + (type $x (result u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected ok type to not be present") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result u32)) + (import "x" (type (eq $t))) + )) + + (type $x (result)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected ok type, but found none") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result)) + (import "x" (type (eq $t))) + )) + + (type $x (result (error u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected err type to not be present") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result (error u32))) + (import "x" (type (eq $t))) + )) + + (type $x (result)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected err type, but found none") diff --git a/tests/local/component-model/invalid.wast b/tests/local/component-model/invalid.wast index 0c5a6f46ed..3b57e3579b 100644 --- a/tests/local/component-model/invalid.wast +++ b/tests/local/component-model/invalid.wast @@ -11,7 +11,7 @@ (component quote "(export \"\" (func $foo))" ) - "failed to find func named") + "unknown func") (assert_malformed (component quote diff --git a/tests/local/component-model/lower.wast b/tests/local/component-model/lower.wast new file mode 100644 index 0000000000..827645d3e0 --- /dev/null +++ b/tests/local/component-model/lower.wast @@ -0,0 +1,15 @@ +(assert_invalid + (component + (import "f" (func $f (param "x" (list u8)))) + (core func $f (canon lower (func $f) + )) + ) + "canonical option `memory` is required") + +(assert_invalid + (component + (import "f" (func $f (result (list u8)))) + (core func $f (canon lower (func $f) + )) + ) + "canonical option `memory` is required") diff --git a/tests/local/component-model/memory64.wast b/tests/local/component-model/memory64.wast index 6edc0da62b..612e4b7290 100644 --- a/tests/local/component-model/memory64.wast +++ b/tests/local/component-model/memory64.wast @@ -7,7 +7,7 @@ (core instance $b (instantiate $B)) (core instance $a (instantiate $A (with "" (instance $b)))) ) - "memory type mismatch") + "mismatch in index type used for memories") (assert_invalid (component @@ -18,4 +18,4 @@ (core instance $b (instantiate $B)) (core instance $a (instantiate $A (with "" (instance $b)))) ) - "memory type mismatch") + "mismatch in index type used for memories") diff --git a/tests/local/component-model/module-link.wast b/tests/local/component-model/module-link.wast index ffaca03ed0..df988cac2b 100644 --- a/tests/local/component-model/module-link.wast +++ b/tests/local/component-model/module-link.wast @@ -28,7 +28,7 @@ (component $B (type $Wasi (instance)) (import "wasi" (instance $wasi (type $Wasi))) - (import "A:1.x" (component $A + (import "a1-x" (component $A (import "wasi" (instance (type $Wasi))) (export "a" (func)) )) @@ -51,7 +51,7 @@ (import "wasi" (instance $wasi (type $Wasi))) (instance $b (instantiate $B (with "wasi" (instance $wasi)) - (with "A:1.x" (component $A))) + (with "a1-x" (component $A))) ) (export "b" (func $b "b")) ) @@ -59,7 +59,7 @@ (component $C (type $Wasi (instance)) (import "wasi" (instance $wasi (type $Wasi))) - (import "B:1.x" (component $B + (import "b1-x" (component $B (import "wasi" (instance $wasi (type $Wasi))) (export "b" (func)) )) @@ -71,7 +71,7 @@ (import "wasi" (instance $wasi (type $Wasi))) (instance $c (instantiate $C (with "wasi" (instance $wasi)) - (with "B:1.x" (component $B_wrap)) + (with "b1-x" (component $B_wrap)) )) (export "c" (func $c "c")) ) @@ -79,7 +79,7 @@ (component $D (type $Wasi (instance)) (import "wasi" (instance $wasi (type $Wasi))) - (import "C:1.x" (component $C + (import "c1-x" (component $C (import "wasi" (instance $wasi (type $Wasi))) (export "c" (func)) )) @@ -89,7 +89,7 @@ (instance $d (instantiate $D (with "wasi" (instance $wasi)) - (with "C:1.x" (component $C_wrap)) + (with "c1-x" (component $C_wrap)) )) (export "d" (func $d "d")) diff --git a/tests/local/component-model/naming.wast b/tests/local/component-model/naming.wast new file mode 100644 index 0000000000..c3a6c7eabb --- /dev/null +++ b/tests/local/component-model/naming.wast @@ -0,0 +1,99 @@ +(component + (func (import "a")) + (component) + (instance (instantiate 0 (with "NotKebab-Case" (func 0)))) +) + +(assert_invalid + (component + (import "f" (func)) + (instance (export "1" (func 0))) + ) + "`1` is not in kebab case" +) + +(assert_invalid + (component + (instance) + (alias export 0 "Xml" (func)) + ) + "instance 0 has no export named `Xml`" +) + +(assert_invalid + (component + (type (flags "a-1-c")) + ) + "flag name `a-1-c` is not in kebab case" +) + +(assert_invalid + (component + (type (enum "NevEr")) + ) + "enum tag name `NevEr` is not in kebab case" +) + +(assert_invalid + (component + (type (record (field "GoNnA" string))) + ) + "record field name `GoNnA` is not in kebab case" +) + +(assert_invalid + (component + (type (variant (case "GIVe" string))) + ) + "variant case name `GIVe` is not in kebab case" +) + + +(assert_invalid + (component + (type (func (param "yOu" string))) + ) + "function parameter name `yOu` is not in kebab case" +) + +(assert_invalid + (component + (type (func (result "uP" string))) + ) + "name `uP` is not in kebab case" +) + +(assert_invalid + (component + (type (component (export "NevEr" (func)))) + ) + "`NevEr` is not in kebab case" +) + +(assert_invalid + (component + (type (component (import "GonnA" (func)))) + ) + "`GonnA` is not in kebab case" +) + +(assert_invalid + (component + (type (instance (export "lET" (func)))) + ) + "`lET` is not in kebab case" +) + +(assert_invalid + (component + (instance (export "YoU")) + ) + "`YoU` is not in kebab case" +) + +(assert_invalid + (component + (instance (import "DOWn")) + ) + "`DOWn` is not in kebab case" +) diff --git a/tests/local/component-model/nested-modules.wast b/tests/local/component-model/nested-modules.wast index ca62ba658b..a2a8394cd1 100644 --- a/tests/local/component-model/nested-modules.wast +++ b/tests/local/component-model/nested-modules.wast @@ -1,5 +1,5 @@ (component - (import "" (core module)) + (import "i1" (core module)) (core module) (core module) @@ -12,14 +12,14 @@ (component (core module $m) - (import "" (func (param string))) - (export "a" (core module $m)) + (import "a" (func (param "p" string))) + (export "b" (core module $m)) ) ) ;; does the `import` use the type annotation specified later? (component - (import "" (core module)) + (import "a" (core module)) (core type (module)) ) @@ -37,11 +37,12 @@ ;; typecheck the module code section correctly (component (core module - (func (export ""))) - (import "" (core module)) + (func (export "")) + ) + (import "a" (core module)) (core module - (func (export "") (result i32) - i32.const 5)) - (import "b" (instance (export "" (core module)))) - (alias export 0 "" (core module)) + (func (export "") (result i32) i32.const 5) + ) + (import "b" (instance (export "a" (core module)))) + (alias export 0 "a" (core module)) ) diff --git a/tests/local/component-model/resources.wast b/tests/local/component-model/resources.wast new file mode 100644 index 0000000000..e68f1b53e9 --- /dev/null +++ b/tests/local/component-model/resources.wast @@ -0,0 +1,1153 @@ +(component + (type $x (resource (rep i32))) +) + +(component + (type $x (resource (rep i32))) + + (core func (canon resource.new $x)) + (core func (canon resource.rep $x)) + (core func (canon resource.drop $x)) +) + +(component + (import "x" (type $x (sub resource))) + + (core func (canon resource.drop $x)) +) + +(component + (core module $m + (func (export "dtor") (param i32)) + ) + (core instance $m (instantiate $m)) + (type $x (resource (rep i32) (dtor (func $m "dtor")))) + (core func (canon resource.new $x)) +) + +(component + (type $x (resource (rep i32))) + (core func $f1 (canon resource.new $x)) + (core func $f2 (canon resource.rep $x)) + (core func $f3 (canon resource.drop $x)) + + (core module $m + (import "" "f1" (func (param i32) (result i32))) + (import "" "f2" (func (param i32) (result i32))) + (import "" "f3" (func (param i32))) + ) + + (core instance (instantiate $m + (with "" (instance + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + )) + )) +) + +(assert_invalid + (component + (type $x (resource (rep i64))) + ) + "resources can only be represented by `i32`") + +(assert_invalid + (component + (type $x (own 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type $x (borrow 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type $t u8) + (type $x (borrow $t)) + ) + "not a resource type") + +(assert_invalid + (component + (type $t u8) + (type $x (own $t)) + ) + "not a resource type") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (core func (canon resource.new $x)) + ) + "not a local resource") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (core func (canon resource.rep $x)) + ) + "not a local resource") + +(assert_invalid + (component + (type $t (tuple u32)) + (core func (canon resource.drop $t)) + ) + "not a resource type") + +(assert_invalid + (component + (core func (canon resource.drop 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (component)) + (core func (canon resource.drop 0)) + ) + "not a resource type") + +(assert_invalid + (component + (type (component)) + (core func (canon resource.new 0)) + ) + "not a resource type") + +(assert_invalid + (component + (core module $m + (func (export "dtor")) + ) + (core instance $m (instantiate $m)) + (type $x (resource (rep i32) (dtor (func $m "dtor")))) + (core func (canon resource.new $x)) + ) + "wrong signature for a destructor") + +(assert_invalid + (component + (type (resource (rep i32) (dtor (func 100)))) + ) + "function index out of bounds") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (import "y" (type $y (sub resource))) + (import "z" (func $z (param "x" (own $x)) (param "y" (own $y)))) + + (component $c + (import "x" (type $x (sub resource))) + (import "z" (func (param "x" (own $x)) (param "y" (own $x)))) + ) + + (instance (instantiate $c (with "x" (type $x)) (with "z" (func $z)))) + ) + "resource types are not the same") + +(component + (type (component + (import "x" (type $x (sub resource))) + (export "y" (type (eq $x))) + (export "z" (type (sub resource))) + )) +) + +(assert_invalid + (component + (type (component + (type $x (resource (rep i32))) + )) + ) + "resources can only be defined within a concrete component") + +(assert_invalid + (component + (type (instance + (type $x (resource (rep i32))) + )) + ) + "resources can only be defined within a concrete component") + +(component + (type (component + (import "x" (instance $i + (export $t "t" (type (sub resource))) + (export "f" (func (result "x" (own $t)))) + )) + (alias export $i "t" (type $t)) + (export "f" (func (result "x" (own $t)))) + )) +) + +(component + (import "fancy-fs" (instance $fancy-fs + (export $fs "fs" (instance + (export "file" (type (sub resource))) + )) + (alias export $fs "file" (type $file)) + (export "fancy-op" (func (param "f" (borrow $file)))) + )) +) + +(component $C + (type $T (list (tuple string bool))) + (type $U (option $T)) + (type $G (func (param "x" (list $T)) (result $U))) + (type $D (component + (alias outer $C $T (type $C_T)) + (type $L (list $C_T)) + (import "f" (func (param "x" $L) (result (list u8)))) + (import "g" (func (type $G))) + (export "g2" (func (type $G))) + (export "h" (func (result $U))) + (import "T" (type $T (sub resource))) + (import "i" (func (param "x" (list (own $T))))) + (export $T' "T2" (type (eq $T))) + (export $U' "U" (type (sub resource))) + (export "j" (func (param "x" (borrow $T')) (result (own $U')))) + )) +) + +(component + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) +) + +(component $C + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) + (import "T3" (type $T3 (eq $T2))) + (type $ListT1 (list (own $T1))) + (type $ListT2 (list (own $T2))) + (type $ListT3 (list (own $T3))) +) + +(component + (import "T" (type $T (sub resource))) + (import "U" (type $U (sub resource))) + (type $Own1 (own $T)) + (type $Own2 (own $T)) + (type $Own3 (own $U)) + (type $ListOwn1 (list $Own1)) + (type $ListOwn2 (list $Own2)) + (type $ListOwn3 (list $Own3)) + (type $Borrow1 (borrow $T)) + (type $Borrow2 (borrow $T)) + (type $Borrow3 (borrow $U)) + (type $ListBorrow1 (list $Borrow1)) + (type $ListBorrow2 (list $Borrow2)) + (type $ListBorrow3 (list $Borrow3)) +) + +(component + (import "C" (component $C + (export "T1" (type (sub resource))) + (export $T2 "T2" (type (sub resource))) + (export "T3" (type (eq $T2))) + )) + (instance $c (instantiate $C)) + (alias export $c "T1" (type $T1)) + (alias export $c "T2" (type $T2)) + (alias export $c "T3" (type $T3)) +) + +(component + (component $C + (type $r1 (export "r1") (resource (rep i32))) + (type $r2 (export "r2") (resource (rep i32))) + ) + (instance $c1 (instantiate $C)) + (instance $c2 (instantiate $C)) + (alias export $c1 "r1" (type $c1r1)) + (alias export $c1 "r2" (type $c1r2)) + (alias export $c2 "r1" (type $c2r1)) + (alias export $c2 "r2" (type $c2r2)) +) + +(component + (type $r (resource (rep i32))) + (export "r1" (type $r)) + (export "r2" (type $r)) +) + +(component + (type (component + (export "r1" (type (sub resource))) + (export "r2" (type (sub resource))) + )) +) + +(component + (type $r (resource (rep i32))) + (export $r1 "r1" (type $r)) + (export "r2" (type $r1)) +) + +(component + (type (component + (export $r1 "r1" (type (sub resource))) + (export "r2" (type (eq $r1))) + )) +) + +(component $P + (import "C1" (component $C1 + (import "T" (type $T (sub resource))) + (export "foo" (func (param "t" (own $T)))) + )) + (import "C2" (component $C2 + (import "T" (type $T (sub resource))) + (import "foo" (func (param "t" (own $T)))) + )) + (type $R (resource (rep i32))) + (instance $c1 (instantiate $C1 (with "T" (type $R)))) + (instance $c2 (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func $c1 "foo")) + )) +) + +(component + (import "C1" (component $C1 + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) + (export "foo" (func (param "t" (tuple (own $T1) (own $T2))))) + )) + (import "C2" (component $C2 + (import "T" (type $T (sub resource))) + (export "foo" (func (param "t" (tuple (own $T) (own $T))))) + )) + (type $R (resource (rep i32))) + (instance $c1 (instantiate $C1 + (with "T1" (type $R)) + (with "T2" (type $R)) + )) + (instance $c2 (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func $c1 "foo")) + )) +) + +(assert_invalid + (component + (component $C + (type $R (resource (rep i32))) + (export "R" (type $R)) + ) + (instance $c (instantiate $C)) + (alias export $c "R" (type $R)) + (core func (canon resource.rep $R)) + ) + "not a local resource") + +(component + (component $C + (type $R (resource (rep i32))) + (export "R" (type $R)) + ) + (instance $c (instantiate $C)) + (alias export $c "R" (type $R)) + (core func (canon resource.drop $R)) +) + +(component + (component $C1 + (import "X" (type (sub resource))) + ) + (component $C2 + (import "C1" (component + (import "X" (type (sub resource))) + )) + ) + (instance $c (instantiate $C2 (with "C1" (component $C1)))) +) + +(component + (component $C1 + (import "X" (type $X (sub resource))) + (import "f" (func $f (result (own $X)))) + (export "g" (func $f)) + ) + (component $C2 + (import "C1" (component + (import "X" (type $X (sub resource))) + (import "f" (func (result (own $X)))) + (export "g" (func (result (own $X)))) + )) + ) + (instance $c (instantiate $C2 (with "C1" (component $C1)))) +) + +(component + (component $C1 + (type $X' (resource (rep i32))) + (export $X "X" (type $X')) + + (core func $f (canon resource.drop $X)) + (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X")) + (with "f" (func $c1 "f")) + )) +) + +(assert_invalid + (component + (component $C1 + (type $X' (resource (rep i32))) + (export $X "X" (type $X')) + + (core func $f (canon resource.drop $X)) + (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + (instance $c2 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X")) + (with "f" (func $c2 "f")) + )) + ) + "resource types are not the same") + +(component + (component $C1 + (type $X (resource (rep i32))) + (export $X1 "X1" (type $X)) + (export $X2 "X2" (type $X)) + + (core func $f (canon resource.drop $X)) + (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) + (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X1")) + (with "f" (func $c1 "f1")) + )) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X2")) + (with "f" (func $c1 "f2")) + )) +) + +(component + (component $C1 + (type $X (resource (rep i32))) + (export $X1 "X1" (type $X)) + (export $X2 "X2" (type $X)) + + (core func $f (canon resource.drop $X)) + (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) + (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X1")) + (with "f" (func $c1 "f2")) + )) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X2")) + (with "f" (func $c1 "f1")) + )) +) + +(assert_invalid + (component + (component $c + (import "x" (type (sub resource))) + ) + (type $x u32) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected resource, found type") + +(assert_invalid + (component + (component $c + (type $t u32) + (import "x" (type (eq $t))) + ) + (type $x (resource (rep i32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected type, found resource") + +(assert_invalid + (component + (component $c + (import "x1" (type $x1 (sub resource))) + (import "x2" (type $x2 (eq $x1))) + ) + (type $x1 (resource (rep i32))) + (type $x2 (resource (rep i32))) + (instance (instantiate $c + (with "x1" (type $x1)) + (with "x2" (type $x2)) + )) + ) + "resource types are not the same") + +(component + (type $x (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (export "y" (type $t)) + ) + (instance $c (instantiate $c (with "x" (type $x)))) + + (alias export $c "y" (type $x2)) + (core func (canon resource.rep $x2)) + +) + +(assert_invalid + (component + (type $r (resource (rep i32))) + (import "x" (func (result (own $r)))) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type (component + (export $x "x" (type (sub resource))) + (import "f" (func (result (own $x)))) + )) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type $r (resource (rep i32))) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) + ) + "func not valid to be used as export") + +;; direct exports count as "explicit in" for resources +(component + (type $r' (resource (rep i32))) + (export $r "r" (type $r')) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; instances-as-a-bundle count as "explicit in" for resources +(component + (type $r' (resource (rep i32))) + (instance $i' + (export "r" (type $r')) + ) + (export $i "i" (instance $i')) + (alias export $i "r" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Transitive bundles count for "explicit in" +(component + (type $r' (resource (rep i32))) + (instance $i' + (export "r" (type $r')) + ) + (instance $i2' + (export "i" (instance $i')) + ) + (export $i2 "i2" (instance $i2')) + (alias export $i2 "i" (instance $i)) + (alias export $i "r" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Component instantiations count for "explicit in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (type $x (sub resource))) + (export "y" (type $x)) + ) + (instance $c' (instantiate $C (with "x" (type $r')))) + (export $c "c" (instance $c')) + (alias export $c "y" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Make sure threading things around is valid for "explicit in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (type $x (sub resource))) + (export "y" (type $x)) + ) + (instance $c (instantiate $C (with "x" (type $r')))) + (instance $i (export "x" (type $c "y"))) + + (component $C2 + (import "x" (instance $i + (export "i1" (instance + (export "i2" (type (sub resource))) + )) + )) + (export "y" (type $i "i1" "i2")) + ) + + (instance $i2 (export "i2" (type $i "x"))) + (instance $i1 (export "i1" (instance $i2))) + (instance $c2 (instantiate $C2 + (with "x" (instance $i1)) + )) + (export $r "x" (type $c2 "y")) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Importing-and-exporting instances through instantiation counts for "explicit +;; in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (instance $x (export "t" (type (sub resource))))) + (export "y" (instance $x)) + ) + (instance $c' (instantiate $C + (with "x" (instance + (export "t" (type $r')) + )) + )) + (export $c "c" (instance $c')) + (alias export $c "y" (instance $y)) + (alias export $y "t" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +(component + (type $i (instance + (export $r "r" (type (sub resource))) + (export "f" (func (result (own $r)))) + )) + (import "i1" (instance $i1 (type $i))) + (import "i2" (instance $i2 (type $i))) + + (component $c + (import "r" (type $t (sub resource))) + (import "f" (func (result (own $t)))) + ) + (instance (instantiate $c + (with "r" (type $i1 "r")) + (with "f" (func $i1 "f")) + )) + (instance (instantiate $c + (with "r" (type $i2 "r")) + (with "f" (func $i2 "f")) + )) +) + + +(assert_invalid + (component + (type $i (instance + (export $r "r" (type (sub resource))) + (export "f" (func (result (own $r)))) + )) + (import "i1" (instance $i1 (type $i))) + (import "i2" (instance $i2 (type $i))) + + (component $c + (import "r" (type $t (sub resource))) + (import "f" (func (result (own $t)))) + ) + (instance (instantiate $c + (with "r" (type $i1 "r")) + (with "f" (func $i2 "f")) + )) + ) + "resource types are not the same") + +;; substitution works +(component + (type $t (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (export "y" (type $t)) + ) + (instance $c1 (instantiate $c (with "x" (type $t)))) + (instance $c2 (instantiate $c (with "x" (type $t)))) + + (component $c2 + (import "x1" (type $t (sub resource))) + (import "x2" (type (eq $t))) + (import "x3" (type (eq $t))) + ) + (instance (instantiate $c2 + (with "x1" (type $t)) + (with "x2" (type $c1 "y")) + (with "x3" (type $c2 "y")) + )) +) + +;; must supply a resource to instantiation +(assert_invalid + (component + (component $c + (import "x" (type (sub resource))) + ) + (instance (instantiate $c)) + ) + "missing import named `x`") +(assert_invalid + (component + (type $x (resource (rep i32))) + (component $c + (import "x" (type (sub resource))) + (import "y" (type (sub resource))) + ) + (instance (instantiate $c (with "x" (type $x)))) + ) + "missing import named `y`") + +;; supply the wrong resource +(assert_invalid + (component + (type $x (resource (rep i32))) + (type $y (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (import "y" (type (eq $t))) + ) + (instance (instantiate $c + (with "x" (type $x)) + (with "y" (type $y)) + )) + ) + "resource types are not the same") + +;; aliasing outer resources is ok +(component $A + (type $C (component + (import "x" (type $x (sub resource))) + + (type $y (component + (alias outer $C $x (type $my-x)) + (import "x" (type (eq $my-x))) + )) + + (import "y" (component (type $y))) + (export "z" (component (type $y))) + )) + + (type $t (resource (rep i32))) + + (alias outer $A $t (type $other-t)) + + (type (instance (export "t" (type (eq $t))))) + (type (component (export "t" (type (eq $t))))) + (type (component (import "t" (type (eq $t))))) +) + +;; aliasing beyond components, however, is not ok +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (component (alias outer $A $t (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (record (field "x" (own $t)))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (borrow $t)) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (component (export "a" (type (eq $t))))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (component (import "a" (type (eq $t))))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") + +(assert_invalid + (component + (component $X + (type $t (resource (rep i32))) + (export "t" (type $t)) + ) + (component $F + (import "x" (component (export $t "t" (type (sub resource))))) + ) + (instance $x1 (instantiate $X)) + (instance $f1 (instantiate $F (with "x" (instance $x1)))) + ) + "expected component, found instance") + +;; Show that two instantiations of the same component produce unique exported +;; resource types. +(assert_invalid + (component + (component $F + (type $t1 (resource (rep i32))) + (export "t1" (type $t1)) + ) + (instance $f1 (instantiate $F)) + (instance $f2 (instantiate $F)) + (alias export $f1 "t1" (type $t1)) + (alias export $f2 "t1" (type $t2)) + (component $T + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance $test + (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) + ) + "type mismatch for import `y`") + +;; Show that re-exporting imported resources from an imported component doesn't +;; change the identity of that resource. +(component + (component $X + (type $t (resource (rep i32))) + (export "t" (type $t)) + ) + (component $F + (import "x" (instance $i (export $t "t" (type (sub resource))))) + (alias export $i "t" (type $t)) + (export "t" (type $t)) + ) + (instance $x1 (instantiate $X)) + (instance $f1 (instantiate $F (with "x" (instance $x1)))) + (instance $f2 (instantiate $F (with "x" (instance $x1)))) + (alias export $f1 "t" (type $t1)) + (alias export $f2 "t" (type $t2)) + (component $T + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance $test + (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) +) + +(assert_invalid + (component (import "[static]" (func))) + "failed to find `.` character") + +;; validation of `[constructor]foo` +(assert_invalid + (component (import "[constructor]" (func))) + "not in kebab case") +(assert_invalid + (component (import "[constructor]a" (func))) + "should return one value") +(assert_invalid + (component (import "[constructor]a" (func (result u32)))) + "should return `(own $T)`") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) + "import name `[constructor]a` is not valid") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) + "function does not match expected resource name `b`") +(component + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) +(component + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (param "x" u32) (result (own $a))))) + +;; validation of `[method]a.b` +(assert_invalid + (component (import "[method]" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[method]a" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[method]a." (func))) + "not in kebab case") +(assert_invalid + (component (import "[method].a" (func))) + "not in kebab case") +(assert_invalid + (component (import "[method]a.b.c" (func))) + "not in kebab case") +(assert_invalid + (component (import "[method]a.b" (instance))) + "is not a func") +(assert_invalid + (component (import "[method]a.b" (func))) + "should have at least one argument") +(assert_invalid + (component (import "[method]a.b" (func (param "x" u32)))) + "should have a first argument called `self`") +(assert_invalid + (component (import "[method]a.b" (func (param "self" u32)))) + "should take a first argument of `(borrow $T)`") +(assert_invalid + (component + (import "b" (type $T (sub resource))) + (import "[method]a.b" (func (param "self" (borrow $T))))) + "does not match expected resource name") +(component + (import "a" (type $T (sub resource))) + (import "[method]a.b" (func (param "self" (borrow $T))))) + +;; validation of `[static]a.b` +(assert_invalid + (component (import "[static]" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[static]a" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[static]a." (func))) + "not in kebab case") +(assert_invalid + (component (import "[static].a" (func))) + "not in kebab case") +(assert_invalid + (component (import "[static]a.b.c" (func))) + "not in kebab case") +(assert_invalid + (component (import "[static]a.b" (instance))) + "is not a func") +(assert_invalid + (component (import "[static]a.b" (func))) + "static resource name is not known in this context") + +(component + (import "a" (type (sub resource))) + (import "[static]a.b" (func))) + +;; exports/imports are disjoint +(assert_invalid + (component + (import "b" (type $T (sub resource))) + (import "f" (func $f (param "self" (borrow $T)))) + (export "[method]b.foo" (func $f)) + ) + "resource used in function does not have a name in this context") + +(component + (import "b" (type $T (sub resource))) + (import "f" (func $f (param "self" (borrow $T)))) + (export $c "c" (type $T)) + (export "[method]c.foo" (func $f) (func (param "self" (borrow $c)))) +) + +;; imports aren't transitive +(assert_invalid + (component + (import "i" (instance $i + (export "t" (type (sub resource))) + )) + (alias export $i "t" (type $t)) + (import "[method]t.foo" (func (param "self" (borrow $t)))) + ) + "resource used in function does not have a name in this context") + +;; validation happens in a type context +(assert_invalid + (component + (type (component + (import "b" (type $T (sub resource))) + (import "[constructor]a" (func (result (own $T)))) + )) + ) + "function does not match expected resource name `b`") + +;; bag-of-exports validation +(assert_invalid + (component + (type $T (resource (rep i32))) + (core module $m (func (export "a") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (result (own $T)) (canon lift (core func $i "a"))) + (instance + (export "a" (type $T)) + (export "[constructor]a" (func $f)) + ) + ) + "resource used in function does not have a name in this context") + +(component + (component $C) + (instance (instantiate $C (with "this is not kebab case" (component $C)))) +) + +;; Test that unused arguments to instantiation are not validated to have +;; appropriate types with respect to kebab naming conventions which require +;; functions/interfaces/etc. +(component + (component $C) + (instance (instantiate $C (with "[method]foo.bar" (component $C)))) +) + +;; thread a resource through a few layers +(component + (component $C + (import "in" (type $r (sub resource))) + (export "out" (type $r)) + ) + + (type $r (resource (rep i32))) + + (instance $c1 (instantiate $C (with "in" (type $r)))) + (instance $c2 (instantiate $C (with "in" (type $c1 "out")))) + (instance $c3 (instantiate $C (with "in" (type $c2 "out")))) + (instance $c4 (instantiate $C (with "in" (type $c3 "out")))) + (instance $c5 (instantiate $C (with "in" (type $c4 "out")))) + + (component $C2 + (import "in1" (type $r (sub resource))) + (import "in2" (type (eq $r))) + (import "in3" (type (eq $r))) + (import "in4" (type (eq $r))) + (import "in5" (type (eq $r))) + (import "in6" (type (eq $r))) + ) + + (instance (instantiate $C2 + (with "in1" (type $r)) + (with "in2" (type $c1 "out")) + (with "in3" (type $c2 "out")) + (with "in4" (type $c3 "out")) + (with "in5" (type $c4 "out")) + (with "in6" (type $c5 "out")) + )) +) + +;; exporting an instance type "freshens" resources +(assert_invalid + (component + (import "x" (instance $i + (type $i (instance + (export "r" (type (sub resource))) + )) + (export "a" (instance (type $i))) + (export "b" (instance (type $i))) + )) + + (component $C + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance (instantiate $C + (with "x" (type $i "a" "r")) + (with "y" (type $i "b" "r")) + )) + ) + "resource types are not the same") + +(component + (type (export "x") (component + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export $t "t" (instance (type $t'))) + (alias export $t "r" (type $r)) + (type $t2' (instance + (export "r2" (type (eq $r))) + (export "r" (type (sub resource))) + )) + (export "t2" (instance (type $t2'))) + )) +) + +(component + (type (component + (type (instance + (export "bar" (type (sub resource))) + (export "[static]bar.a" (func)) + )) + (export "x" (instance (type 0))) + )) +) + +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (borrow $r)))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (list (borrow $r))))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (option (borrow $r))))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type $t (record (field "f" (borrow $r)))) + (type (func (result (option (list $t))))) + ) + "function result cannot contain a `borrow` type") diff --git a/tests/local/component-model/start.wast b/tests/local/component-model/start.wast index 03e13aea3b..31a86e1c78 100644 --- a/tests/local/component-model/start.wast +++ b/tests/local/component-model/start.wast @@ -1,72 +1,72 @@ (assert_invalid (component - (import "" (func $f (param string))) + (import "a" (func $f (param "p1" string))) (start $f) ) "start function requires 1 arguments") (assert_invalid (component - (import "" (func $f (param string))) - (import "v" (value $v string)) + (import "a" (func $f (param "p" string))) + (import "b" (value $v string)) (start $f (value $v) (value $v)) ) "start function requires 1 arguments") (assert_invalid (component - (import "" (func $f (param "1" string) (param "2" string))) - (import "v" (value $v string)) + (import "a" (func $f (param "p1" string) (param "p2" string))) + (import "b" (value $v string)) (start $f (value $v) (value $v)) ) "cannot be used more than once") (assert_invalid (component - (import "" (func $f (param "x" string) (param "y" string))) - (import "v" (value $v string)) - (import "v2" (value $v2 u32)) + (import "a" (func $f (param "x" string) (param "y" string))) + (import "b" (value $v string)) + (import "c" (value $v2 u32)) (start $f (value $v) (value $v2)) ) "type mismatch for component start function argument 1") (component - (import "" (func $f (param "z" string) (param "a" string))) - (import "v" (value $v string)) - (import "v2" (value $v2 string)) + (import "a" (func $f (param "z" string) (param "a" string))) + (import "b" (value $v string)) + (import "c" (value $v2 string)) (start $f (value $v) (value $v2)) ) (component - (import "" (func $f (result string))) + (import "a" (func $f (result string))) (start $f (result (value $a))) - (export "a" (value $a)) + (export "b" (value $a)) ) (component - (import "" (func $f (param "a" string) (param "b" string) (result "c" s32) (result "d" s32))) - (import "v" (value $v string)) - (import "v2" (value $v2 string)) + (import "a" (func $f (param "a" string) (param "b" string) (result "c" s32) (result "d" s32))) + (import "b" (value $v string)) + (import "c" (value $v2 string)) (start $f (value $v) (value $v2) (result (value $c)) (result (value $d))) - (export "c" (value $c)) - (export "d" (value $d)) + (export "d" (value $c)) + (export "e" (value $d)) ) (assert_invalid (component - (import "" (func $f (param "a" string) (param "b" string) (result "c" s32) (result "d" s32))) - (import "v" (value $v string)) - (import "v2" (value $v2 string)) + (import "a" (func $f (param "a" string) (param "b" string) (result "c" s32) (result "d" s32))) + (import "b" (value $v string)) + (import "c" (value $v2 string)) (start $f (value $v) (value $v2) (result (value $c))) - (export "c" (value $c)) + (export "a" (value $c)) ) "component start function has a result count of 1 but the function type has a result count of 2" ) (assert_invalid (component - (import "" (func $f)) + (import "a" (func $f)) (start $f) (start $f) ) @@ -74,17 +74,17 @@ (assert_invalid (component binary - "\00asm" "\0a\00\01\00" ;; component header + "\00asm" "\0d\00\01\00" ;; component header - "\07\06" ;; type section, 6 bytes large + "\07\05" ;; type section, 5 bytes large "\01" ;; 1 count "\40" ;; function - "\01\00" ;; parameters, named, 0 count + "\00" ;; parameters, 0 count "\01\00" ;; results, named, 0 count - "\0a\04" ;; import section, 4 bytes large + "\0a\06" ;; import section, 6 bytes large "\01" ;; 1 count - "\00" ;; name = "" + "\00\01a" ;; name = "a" "\01\00" ;; type = func ($type 0) "\09\06" ;; start section, 6 bytes large @@ -96,17 +96,17 @@ (assert_invalid (component binary - "\00asm" "\0a\00\01\00" ;; component header + "\00asm" "\0d\00\01\00" ;; component header - "\07\06" ;; type section, 6 bytes large + "\07\05" ;; type section, 5 bytes large "\01" ;; 1 count "\40" ;; function - "\01\00" ;; parameters, named, 0 count + "\00" ;; parameters, 0 count "\01\00" ;; results, named, 0 count - "\0a\04" ;; import section, 4 bytes large + "\0a\06" ;; import section, 6 bytes large "\01" ;; 1 count - "\00" ;; name = "" + "\00\01a" ;; name = "a" "\01\00" ;; type = func ($type 0) "\09\04" ;; start section, 4 bytes large @@ -115,4 +115,4 @@ "\00" ;; no results "\ff" ;; trailing garbage byte ) - "trailing data at the end of the start section") + "unexpected content in the component start section") diff --git a/tests/local/component-model/string.wast b/tests/local/component-model/string.wast index 465cada200..e768184486 100644 --- a/tests/local/component-model/string.wast +++ b/tests/local/component-model/string.wast @@ -19,7 +19,7 @@ ) (core instance $main (instantiate $Main (with "libc" (instance $libc)))) (alias core export $main "start" (core func $main_func)) - (func $start (param string) (result string) + (func $start (param "p1" string) (result string) (canon lift (core func $main_func) (memory $libc "memory") (realloc (func $libc "canonical_abi_realloc")) diff --git a/tests/local/component-model/type-export-restrictions.wast b/tests/local/component-model/type-export-restrictions.wast new file mode 100644 index 0000000000..58dd62a035 --- /dev/null +++ b/tests/local/component-model/type-export-restrictions.wast @@ -0,0 +1,498 @@ +;; Test that unnamed types in various types are all detected + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "f" $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (tuple $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (variant (case "c" $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (option $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (result $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; Test that various types are all flagged as "requires a name" + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (enum "a")) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (flags "a")) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (variant (case "a"))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (resource (rep i32))) + (type $f (list (own $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; Some types don't need names +(component + (type $t1 (tuple (tuple u32))) + (export "t1" (type $t1)) + + (type $t2 (option (tuple (list u8) (result (list u32) (error (option string)))))) + (export "t2" (type $t2)) + + (type $t3 u32) + (export "t3" (type $t3)) +) + +(component + (type $t' (record (field "f" u32))) + (export $t "t" (type $t')) + (type $t2 (record (field "x" $t))) + (export "t2" (type $t2)) +) + +;; imports are validated as well +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $t2 (record (field "f" $t))) + (import "x" (type (eq $t2))) + ) + "type not valid to be used as import") +(component + (type $t (record (field "f" u32))) + (import "t" (type $t' (eq $t))) + (type $t2 (record (field "f" $t'))) + (import "x" (type (eq $t2))) +) +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $t2 (record (field "f" $t))) + (import "x" (func (param "x" $t2))) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type $t (resource (rep i32))) + (export "t" (type $t)) + (type $f (list (own $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; validate within the type context +(assert_invalid + (component + (type (component + (type $t (record (field "f" u32))) + (export "f" (func (param "x" $t))) + )) + ) + "func not valid to be used as export") +(assert_invalid + (component + (type (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + ) + "type not valid to be used as export") + +;; instances of unexported types is ok +(component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (instance + (export "f" (type $f)) + ) +) +;; .. but exporting them is not +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (instance $i + (export "f" (type $f)) + ) + (export "i" (instance $i)) + ) + "instance not valid to be used as export") + +;; Can't export a lifted function with unexported types +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $f) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; Unexported instances don't work +(assert_invalid + (component + (type $t' (record (field "f" u32))) + (instance $i + (export "t" (type $t')) + ) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; Even through a component it doesn't work +(assert_invalid + (component + (component $C + (type $t (record (field "f" u32))) + (export "t" (type $t)) + ) + (instance $i (instantiate $C)) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; through exported instances is ok though +(component + (type $t' (record (field "f" u32))) + (instance $i' + (export "t" (type $t')) + ) + (export $i "i" (instance $i')) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) +) +(component + (component $C + (type $t (record (field "f" u32))) + (export "t" (type $t)) + ) + (instance $i' (instantiate $C)) + (export $i "i" (instance $i')) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) +) + +;; a type-ascribed export which is otherwise invalid can become valid +(component + (type $t (record (field "f" u32))) + + (core module $m (func (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "x" $t) (canon lift (core func $i "f"))) + + (export $t' "t" (type $t)) + (export "f" (func $f) (func (param "x" $t'))) +) + +;; imports can't reference exports +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (export $t2 "t1" (type $t1)) + (import "i" (func (result $t2))) + ) + "func not valid to be used as import") + +;; exports can reference imports +(component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (export "e-t1" (type $t2)) +) +(component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (import "i" (func $f (result $t2))) + + (export "e-i" (func $f)) +) + +;; outer aliases don't work for imports/exports +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (component + (import "i" (func $f (result $t2))) + ) + ) + "func not valid to be used as import") +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (export $t2 "t1" (type $t1)) + (component + (core module $m (func (export "f") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (export "i") (result $t2) (canon lift (core func $i "f"))) + ) + ) + "func not valid to be used as export") + +;; outer aliases work for components, modules, and resources +(component + (type $c (component)) + (type (component + (import "c" (component (type $c))) + )) + (component + (import "c" (component (type $c))) + ) + (type $i (instance)) + (type (component + (import "c" (instance (type $i))) + )) + + (type $r (resource (rep i32))) + (type (component + (import "r" (type (eq $r))) + )) +) + +;; reexport of an import is fine +(component + (import "r" (func $r)) + (export "r2" (func $r)) +) +(component + (type $t (record (field "f" u32))) + (import "r" (type $r (eq $t))) + (export "r2" (type $r)) +) +(component + (import "r" (instance $r)) + (export "r2" (instance $r)) +) +(component + (import "r" (type $r (sub resource))) + (export "r2" (type $r)) +) + +;; bag of exports cannot be exported by carrying through context that's not +;; otherwise exported +(assert_invalid + (component + (component $A + (type $t (record (field "f" u32))) + (export $t2 "t" (type $t)) + (core module $m (func (export "f") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (result $t2) (canon lift (core func $i "f"))) + + (instance (export "i") + (export "f" (func $f)) + ) + ) + + (instance $a (instantiate $A)) + ;; this component only exports `f`, not the record type that is the result + ;; of `f`, so it should be invalid. + (export "a" (instance $a "i")) + ) + "instance not valid to be used as export") + +;; instance types can be "temporarily invalid", but not if they're attached +;; to a concrete component +(component + (type (instance + (type $t (record (field "f" u32))) + (export "f" (func (param "x" $t))) + )) +) +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (import "f" (instance (type $i))) + ) + "instance not valid to be used as import") + +;; allow for one import to refer to another +(component $C + (import "foo" (instance $i + (type $baz' (record (field "f" u32))) + (export $baz "baz" (type (eq $baz'))) + (type $bar' (record (field "baz" $baz))) + (export $bar "bar" (type (eq $bar'))) + )) + (alias export $i "bar" (type $bar)) + (import "bar" (instance + (alias outer $C $bar (type $bar')) + (export $bar "bar" (type (eq $bar'))) + (export $f "a" (func (result $bar))) + )) +) + +;; allow for one import to refer to another +(component + (type $r' (record (field "f" u32))) + (import "r" (type $r (eq $r'))) + (component $C + (type $r' (record (field "f" u32))) + (import "r" (type $r (eq $r'))) + (type $r2' (record (field "r" $r))) + (export "r2" (type $r2')) + ) + (instance $c (instantiate $C (with "r" (type $r)))) + (export "r2" (type $c "r2")) +) + +;; types are validated when they are exported +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (import "f" (type (eq $i))) + ) + "type not valid to be used as import") +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (export "f" (type $i)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (func (result $t))) + (import "f" (type (eq $f))) + ) + "type not valid to be used as import") +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (func (result $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component (;0;) + (type (;0;) (enum "qux")) + (import "import-type-baz" (type (;1;) (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (import "import-type-bar" (type (;3;) (eq 2))) + (export (;4;) "foo" (type 3)) + ) + (instance (;1;) (instantiate 0 + (with "import-type-baz" (type 0 "baz")) + (with "import-type-bar" (type 0 "foo")) + ) + ) + (export (;0;) (interface "demo:component/types") (instance 1)) + ) + (instance (instantiate 0 (with "demo:component/types" (instance 0)))) + (export (interface "demo:component/types") (instance 1 "demo:component/types")) +) diff --git a/tests/local/component-model/types.wast b/tests/local/component-model/types.wast index 855ec64cd6..a964c9d1d8 100644 --- a/tests/local/component-model/types.wast +++ b/tests/local/component-model/types.wast @@ -1,21 +1,21 @@ (assert_invalid (component (type $t (instance)) - (import "" (func (type $t))) + (import "a" (func (type $t))) ) "type index 0 is not a function type") (assert_invalid (component (core type $t (func)) - (import "" (core module (type $t))) + (import "a" (core module (type $t))) ) "core type index 0 is not a module type") (assert_invalid (component (type $t (func)) - (import "" (instance (type $t))) + (import "a" (instance (type $t))) ) "type index 0 is not an instance type") @@ -23,7 +23,7 @@ (component (type $t (func)) (type (component - (import "" (instance (type $t))) + (import "a" (instance (type $t))) )) ) "type index 0 is not an instance type") @@ -32,7 +32,7 @@ (component (core type $t (func)) (type (component - (import "" (core module (type $t))) + (import "a" (core module (type $t))) )) ) "core type index 0 is not a module type") @@ -41,27 +41,27 @@ (component (type $t (instance)) (type (component - (import "" (func (type $t))) + (import "a" (func (type $t))) )) ) "type index 0 is not a function type") (assert_invalid (component - (export "" (core module 0)) + (export "a" (core module 0)) ) "module index out of bounds") (assert_invalid (component - (export "" (instance 0)) + (export "a" (instance 0)) ) "instance index out of bounds") (assert_invalid (component (core type (module - (export "" (func (type 0))) + (export "a" (func (type 0))) )) ) "type index out of bounds") @@ -69,11 +69,11 @@ (assert_invalid (component (core type (module - (export "" (func)) - (export "" (func)) + (export "a" (func)) + (export "a" (func)) )) ) - "export name `` already defined") + "export name `a` already defined") (assert_invalid (component @@ -95,7 +95,7 @@ (assert_invalid (component (type (component - (export "" (func (type 0))) + (export "a" (func (type 0))) )) ) "type index out of bounds") @@ -103,20 +103,20 @@ (assert_invalid (component (type (component - (export "" (func)) - (export "" (func)) + (export "a" (func)) + (export "A" (func)) )) ) - "export name `` already defined") + "export name `A` conflicts with previous name `a`") (assert_invalid (component (type (component - (import "" (func)) - (import "" (func)) + (import "A" (func)) + (import "a" (func)) )) ) - "duplicate import name") + "import name `a` conflicts with previous name `A`") (assert_invalid (component $c @@ -124,7 +124,7 @@ (alias outer $c $t (type)) )) ) - "failed to find core type named `$t`") + "unknown core type") (assert_invalid (component $c @@ -149,7 +149,7 @@ (alias outer $c $t (type)) )) ) - "failed to find type named `$t`") + "unknown type") (assert_invalid (component $c @@ -191,11 +191,11 @@ (assert_invalid (component (type (instance - (export "" (func)) - (export "" (func)) + (export "foo-BAR-baz" (func)) + (export "FOO-bar-BAZ" (func)) )) ) - "export name `` already defined") + "export name `FOO-bar-BAZ` conflicts with previous name `foo-BAR-baz`") (assert_invalid (component $c @@ -203,7 +203,7 @@ (alias outer $c $t (type)) )) ) - "failed to find type named `$t`") + "unknown type") (assert_invalid (component $c @@ -278,14 +278,44 @@ (component (type (instance (type string) - (export "" (type (eq 0))) + (export "a" (type (eq 0))) )) ) (component (type (component (type string) - (import "" (type (eq 0))) - (export "" (type (eq 0))) + (import "a" (type (eq 0))) + (export "b" (type (eq 0))) )) -) \ No newline at end of file +) + +(assert_invalid + (component + (type (variant)) + ) + "variant type must have at least one case") + +(assert_invalid + (component + (type (enum)) + ) + "enum type must have at least one variant") + +(assert_invalid + (component + (type (record)) + ) + "record type must have at least one field") + +(assert_invalid + (component + (type (flags)) + ) + "flags must have at least one entry") + +(assert_invalid + (component + (type (tuple)) + ) + "tuple type must have at least one type") diff --git a/tests/local/component-model/very-nested.wast b/tests/local/component-model/very-nested.wast index f076780187..8e82efe31c 100644 --- a/tests/local/component-model/very-nested.wast +++ b/tests/local/component-model/very-nested.wast @@ -12,14 +12,14 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "01AGGGGle*$$qq") + (import "sdg-q12") ) (component (export "c t.*************") @@ -29,35 +29,35 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGl$$qq") + (import "jsjsjs") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGi64x2.splatle*$$qq") + (import "anonmm-x23foinas-ASDOJASD") ) (component (export "c t.****0*********") @@ -67,39 +67,39 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component - (export "c 6Ǻ*******************") - (import "00AGGG^Glllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllle*$$qq") + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") ) (component - (export "c EGGyGG$qq**") - (export "15AGGG.Gle '$$qq") + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") ) (component (export "q") ) (component (export "b 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 0.*************") @@ -112,14 +112,14 @@ ) (component (export "c 3@E*********GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E************[******") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -135,7 +135,7 @@ (import "00e*$$qq") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "0+AGGG.Gle $$qq") ) (component @@ -162,7 +162,7 @@ (export "c t.*") (component (export "c 3@EGGGG$qq**") - (export "00AGGGGle*$$qq") + (export "bsdew2-sdbsdb") ) (component (export "c t.********)*eleo &m Nx2GGGGle*$$qq") @@ -184,7 +184,7 @@ ) (component (export "c 3@E*******************") - (import "01AGGGGle*$$qq") + (import "sdg-q12") ) (component (export "c t.*************") @@ -194,40 +194,40 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGl$$qq") + (import "jsjsjs") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") (export "0*************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -241,14 +241,14 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "01AGGGGle*$$qq") + (import "sdg-q12") ) (component (export "c t.*************") @@ -258,35 +258,35 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGl$$qq") + (import "jsjsjs") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGi64x2.splatle*$$qq") + (import "anonmm-x23foinas-ASDOJASD") ) (component (export "c t.****0*********") @@ -296,39 +296,39 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component - (export "c 6Ǻ*******************") - (import "00AGGG^Glllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllle*$$qq") + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") ) (component - (export "c EGGyGG$qq**") - (export "15AGGG.Gle '$$qq") + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") ) (component (export "q") ) (component (export "b 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 0.*************") @@ -341,14 +341,14 @@ ) (component (export "c 3@E*********GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E************[******") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -364,7 +364,7 @@ (import "00e*$$qq") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "0+AGGG.Gle $$qq") ) (component @@ -391,7 +391,7 @@ (export "c .t*") (component (export "c 3@EGGGG$qq**") - (export "00AGGGGle*$$qq") + (export "bsdew2-sdbsdb") ) (component (export "c t.********)*eleo &m Nx2GGGGle*$$qq") @@ -413,7 +413,7 @@ ) (component (export "c 3@E*******************") - (import "01AGGGGle*$$qq") + (import "sdg-q12") ) (component (export "c t.*************") @@ -423,35 +423,35 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGl$$qq") + (import "jsjsjs") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -461,31 +461,31 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component - (export "c 6Ǻ*******************") - (import "00AGGG^Glllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllle*$$qq") + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "00AGGG.Gle '$$qq") ) (component @@ -493,7 +493,7 @@ ) (component (export "b 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 0.*************") @@ -506,14 +506,14 @@ ) (component (export "c 3@E*********GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E************[******") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -529,7 +529,7 @@ (import "00e*$$qq") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "00AGGG.Gle $$qq") ) (component @@ -537,7 +537,7 @@ ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c *****") @@ -551,14 +551,14 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "01AGGGGle*$$qq") + (import "sdg-q12") ) (component (export "c t.*************") @@ -568,35 +568,35 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGl$$qq") + (import "jsjsjs") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGi64x2.splatle*$$qq") + (import "anonmm-x23foinas-ASDOJASD") ) (component (export "c t.****0*********") @@ -606,39 +606,39 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component - (export "c 6Ǻ*******************") - (import "00AGGG^Glllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllle*$$qq") + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") ) (component - (export "c EGGyGG$qq**") - (export "15AGGG.Gle '$$qq") + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") ) (component (export "q") ) (component (export "b 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 0.*************") @@ -651,14 +651,14 @@ ) (component (export "c 3@E*********GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E************[******") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -674,7 +674,7 @@ (import "00e*$$qq") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "0+AGGG.Gle $$qq") ) (component @@ -701,7 +701,7 @@ (export "c t.*") (component (export "c 3@EGGGG$qq**") - (export "00AGGGGle*$$qq") + (export "bsdew2-sdbsdb") ) (component (export "c t.********)*eleo &m Nx2GGGGle*$$qq") @@ -723,7 +723,7 @@ ) (component (export "c 3@E*******************") - (import "01AGGGGle*$$qq") + (import "sdg-q12") ) (component (export "c t.*************") @@ -733,40 +733,40 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGl$$qq") + (import "jsjsjs") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") (export "0*************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -780,14 +780,14 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "01AGGGGle*$$qq") + (import "sdg-q12") ) (component (export "c t.*************") @@ -797,35 +797,35 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGl$$qq") + (import "jsjsjs") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGi64x2.splatle*$$qq") + (import "anonmm-x23foinas-ASDOJASD") ) (component (export "c t.****0*********") @@ -835,39 +835,39 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component - (export "c 6Ǻ*******************") - (import "00AGGG^Glllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllle*$$qq") + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") ) (component - (export "c EGGyGG$qq**") - (export "15AGGG.Gle '$$qq") + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") ) (component (export "q") ) (component (export "b 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 0.*************") @@ -880,14 +880,14 @@ ) (component (export "c 3@E*********GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E************[******") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -903,7 +903,7 @@ (import "00e*$$qq") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "0+AGGG.Gle $$qq") ) (component @@ -930,7 +930,7 @@ (export "c .t*") (component (export "c 3@EGGGG$qq**") - (export "00AGGGGle*$$qq") + (export "bsdew2-sdbsdb") ) (component (export "c t.********)*eleo &m Nx2GGGGle*$$qq") @@ -952,7 +952,7 @@ ) (component (export "c 3@E*******************") - (import "01AGGGGle*$$qq") + (import "sdg-q12") ) (component (export "c t.*************") @@ -962,35 +962,35 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGl$$qq") + (import "jsjsjs") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -1000,31 +1000,31 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component - (export "c 6Ǻ*******************") - (import "00AGGG^Glllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllle*$$qq") + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "00AGGG.Gle '$$qq") ) (component @@ -1032,7 +1032,7 @@ ) (component (export "b 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 0.*************") @@ -1045,14 +1045,14 @@ ) (component (export "c 3@E*********GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E************[******") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -1068,7 +1068,7 @@ (import "00e*$$qq") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "00AGGG.Gle $$qq") ) (component @@ -1076,7 +1076,7 @@ ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 1.*************") @@ -1089,7 +1089,7 @@ ) (component (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") @@ -1120,7 +1120,7 @@ (component (export "c t.*************") (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") @@ -1164,31 +1164,31 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component - (export "c 6Ǻ*******************") - (import "00AGGG^Glllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllle*$$qq") + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "00AGGG.Gle '$$qq") ) (component @@ -1196,7 +1196,7 @@ ) (component (export "b 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 0.*************") @@ -1209,14 +1209,14 @@ ) (component (export "c 3@E*********GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E************[******") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -1232,7 +1232,7 @@ (import "00e*$$qq") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "00AGGG.Gle $$qq") ) (component @@ -1240,7 +1240,7 @@ ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 1.*************") @@ -1253,7 +1253,7 @@ ) (component (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") @@ -1284,7 +1284,7 @@ (component (export "c t.*************") (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") @@ -1332,7 +1332,7 @@ ) (component (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") @@ -1363,7 +1363,7 @@ (component (export "c t.*************") (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") @@ -1407,31 +1407,31 @@ ) (component (export "q**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c=t.*************") (export "00AG") (component - (export "c 3@EGGyGG$qq**") - (export "00AGGGGle $$qq") + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component - (export "c 6Ǻ*******************") - (import "00AGGG^Glllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllle*$$qq") + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "00AGGG.Gle '$$qq") ) (component @@ -1439,7 +1439,7 @@ ) (component (export "b 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 0.*************") @@ -1452,14 +1452,14 @@ ) (component (export "c 3@E*********GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") ) (component (export "c 3@E************[******") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c t.*************") @@ -1475,7 +1475,7 @@ (import "00e*$$qq") ) (component - (export "c EGGyGG$qq**") + (export "EGG-y-GG-qq") (export "00AGGG.Gle $$qq") ) (component @@ -1483,7 +1483,7 @@ ) (component (export "c 3@E*******************") - (import "00AGGGGle*$$qq") + (import "bsdew2-sdbsdb") ) (component (export "c 1.*************") @@ -1496,7 +1496,7 @@ ) (component (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") @@ -1527,7 +1527,7 @@ (component (export "c t.*************") (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "00AGGGGle $$qq") + (export "dojgn-ejs9-nd188") ) (component (export "q") @@ -1562,126 +1562,126 @@ (component) ) ) - "duplicate export name") + "conflicts with previous name") (assert_invalid (component (type $m0 (component)) (type $m1 (component - (import "1" (component (type $m0))) - (import "2" (component (type $m0))) - (import "3" (component (type $m0))) - (import "4" (component (type $m0))) - (import "5" (component (type $m0))) - (import "6" (component (type $m0))) - (import "7" (component (type $m0))) - (import "8" (component (type $m0))) - (import "9" (component (type $m0))) - (import "10" (component (type $m0))) + (import "i1" (component (type $m0))) + (import "i2" (component (type $m0))) + (import "i3" (component (type $m0))) + (import "i4" (component (type $m0))) + (import "i5" (component (type $m0))) + (import "i6" (component (type $m0))) + (import "i7" (component (type $m0))) + (import "i8" (component (type $m0))) + (import "i9" (component (type $m0))) + (import "i10" (component (type $m0))) )) (type $m2 (component - (import "1" (component (type $m1))) - (import "2" (component (type $m1))) - (import "3" (component (type $m1))) - (import "4" (component (type $m1))) - (import "5" (component (type $m1))) - (import "6" (component (type $m1))) - (import "7" (component (type $m1))) - (import "8" (component (type $m1))) - (import "9" (component (type $m1))) - (import "10" (component (type $m1))) + (import "i1" (component (type $m1))) + (import "i2" (component (type $m1))) + (import "i3" (component (type $m1))) + (import "i4" (component (type $m1))) + (import "i5" (component (type $m1))) + (import "i6" (component (type $m1))) + (import "i7" (component (type $m1))) + (import "i8" (component (type $m1))) + (import "i9" (component (type $m1))) + (import "i10" (component (type $m1))) )) (type $m3 (component - (import "1" (component (type $m2))) - (import "2" (component (type $m2))) - (import "3" (component (type $m2))) - (import "4" (component (type $m2))) - (import "5" (component (type $m2))) - (import "6" (component (type $m2))) - (import "7" (component (type $m2))) - (import "8" (component (type $m2))) - (import "9" (component (type $m2))) - (import "10" (component (type $m2))) + (import "i1" (component (type $m2))) + (import "i2" (component (type $m2))) + (import "i3" (component (type $m2))) + (import "i4" (component (type $m2))) + (import "i5" (component (type $m2))) + (import "i6" (component (type $m2))) + (import "i7" (component (type $m2))) + (import "i8" (component (type $m2))) + (import "i9" (component (type $m2))) + (import "i10" (component (type $m2))) )) (type $m4 (component - (import "1" (component (type $m3))) - (import "2" (component (type $m3))) - (import "3" (component (type $m3))) - (import "4" (component (type $m3))) - (import "5" (component (type $m3))) - (import "6" (component (type $m3))) - (import "7" (component (type $m3))) - (import "8" (component (type $m3))) - (import "9" (component (type $m3))) - (import "10" (component (type $m3))) + (import "i1" (component (type $m3))) + (import "i2" (component (type $m3))) + (import "i3" (component (type $m3))) + (import "i4" (component (type $m3))) + (import "i5" (component (type $m3))) + (import "i6" (component (type $m3))) + (import "i7" (component (type $m3))) + (import "i8" (component (type $m3))) + (import "i9" (component (type $m3))) + (import "i10" (component (type $m3))) )) (type $m5 (component - (import "1" (component (type $m4))) - (import "2" (component (type $m4))) - (import "3" (component (type $m4))) - (import "4" (component (type $m4))) - (import "5" (component (type $m4))) - (import "6" (component (type $m4))) - (import "7" (component (type $m4))) - (import "8" (component (type $m4))) - (import "9" (component (type $m4))) - (import "10" (component (type $m4))) + (import "i1" (component (type $m4))) + (import "i2" (component (type $m4))) + (import "i3" (component (type $m4))) + (import "i4" (component (type $m4))) + (import "i5" (component (type $m4))) + (import "i6" (component (type $m4))) + (import "i7" (component (type $m4))) + (import "i8" (component (type $m4))) + (import "i9" (component (type $m4))) + (import "i10" (component (type $m4))) )) (type $m6 (component - (import "1" (component (type $m5))) - (import "2" (component (type $m5))) - (import "3" (component (type $m5))) - (import "4" (component (type $m5))) - (import "5" (component (type $m5))) - (import "6" (component (type $m5))) - (import "7" (component (type $m5))) - (import "8" (component (type $m5))) - (import "9" (component (type $m5))) - (import "10" (component (type $m5))) + (import "i1" (component (type $m5))) + (import "i2" (component (type $m5))) + (import "i3" (component (type $m5))) + (import "i4" (component (type $m5))) + (import "i5" (component (type $m5))) + (import "i6" (component (type $m5))) + (import "i7" (component (type $m5))) + (import "i8" (component (type $m5))) + (import "i9" (component (type $m5))) + (import "i10" (component (type $m5))) )) (type $m7 (component - (import "1" (component (type $m6))) - (import "2" (component (type $m6))) - (import "3" (component (type $m6))) - (import "4" (component (type $m6))) - (import "5" (component (type $m6))) - (import "6" (component (type $m6))) - (import "7" (component (type $m6))) - (import "8" (component (type $m6))) - (import "9" (component (type $m6))) - (import "10" (component (type $m6))) + (import "i1" (component (type $m6))) + (import "i2" (component (type $m6))) + (import "i3" (component (type $m6))) + (import "i4" (component (type $m6))) + (import "i5" (component (type $m6))) + (import "i6" (component (type $m6))) + (import "i7" (component (type $m6))) + (import "i8" (component (type $m6))) + (import "i9" (component (type $m6))) + (import "i10" (component (type $m6))) )) (type $m8 (component - (import "1" (component (type $m7))) - (import "2" (component (type $m7))) - (import "3" (component (type $m7))) - (import "4" (component (type $m7))) - (import "5" (component (type $m7))) - (import "6" (component (type $m7))) - (import "7" (component (type $m7))) - (import "8" (component (type $m7))) - (import "9" (component (type $m7))) - (import "10" (component (type $m7))) + (import "i1" (component (type $m7))) + (import "i2" (component (type $m7))) + (import "i3" (component (type $m7))) + (import "i4" (component (type $m7))) + (import "i5" (component (type $m7))) + (import "i6" (component (type $m7))) + (import "i7" (component (type $m7))) + (import "i8" (component (type $m7))) + (import "i9" (component (type $m7))) + (import "i10" (component (type $m7))) )) (type $m9 (component - (import "1" (component (type $m8))) - (import "2" (component (type $m8))) - (import "3" (component (type $m8))) - (import "4" (component (type $m8))) - (import "5" (component (type $m8))) - (import "6" (component (type $m8))) - (import "7" (component (type $m8))) - (import "8" (component (type $m8))) - (import "9" (component (type $m8))) - (import "10" (component (type $m8))) + (import "i1" (component (type $m8))) + (import "i2" (component (type $m8))) + (import "i3" (component (type $m8))) + (import "i4" (component (type $m8))) + (import "i5" (component (type $m8))) + (import "i6" (component (type $m8))) + (import "i7" (component (type $m8))) + (import "i8" (component (type $m8))) + (import "i9" (component (type $m8))) + (import "i10" (component (type $m8))) )) (type $m (component - (import "" (component (type $m9))) + (import "a" (component (type $m9))) )) (import "a" (component $a (type $m9))) (import "b" (component $b (type $m))) - (instance (instantiate $b (with "" (component $a)))) + (instance (instantiate $b (with "a" (component $a)))) ) "effective type size exceeds the limit") @@ -1689,88 +1689,88 @@ (component (component $m0) (component $m1 - (instance (export "0") (instantiate $m0)) - (instance (export "1") (instantiate $m0)) - (instance (export "2") (instantiate $m0)) - (instance (export "3") (instantiate $m0)) - (instance (export "4") (instantiate $m0)) - (instance (export "5") (instantiate $m0)) - (instance (export "6") (instantiate $m0)) - (instance (export "7") (instantiate $m0)) - (instance (export "8") (instantiate $m0)) - (instance (export "9") (instantiate $m0)) + (instance (export "e0") (instantiate $m0)) + (instance (export "e1") (instantiate $m0)) + (instance (export "e2") (instantiate $m0)) + (instance (export "e3") (instantiate $m0)) + (instance (export "e4") (instantiate $m0)) + (instance (export "e5") (instantiate $m0)) + (instance (export "e6") (instantiate $m0)) + (instance (export "e7") (instantiate $m0)) + (instance (export "e8") (instantiate $m0)) + (instance (export "e9") (instantiate $m0)) ) (component $m2 - (instance (export "0") (instantiate $m1)) - (instance (export "1") (instantiate $m1)) - (instance (export "2") (instantiate $m1)) - (instance (export "3") (instantiate $m1)) - (instance (export "4") (instantiate $m1)) - (instance (export "5") (instantiate $m1)) - (instance (export "6") (instantiate $m1)) - (instance (export "7") (instantiate $m1)) - (instance (export "8") (instantiate $m1)) - (instance (export "9") (instantiate $m1)) + (instance (export "e0") (instantiate $m1)) + (instance (export "e1") (instantiate $m1)) + (instance (export "e2") (instantiate $m1)) + (instance (export "e3") (instantiate $m1)) + (instance (export "e4") (instantiate $m1)) + (instance (export "e5") (instantiate $m1)) + (instance (export "e6") (instantiate $m1)) + (instance (export "e7") (instantiate $m1)) + (instance (export "e8") (instantiate $m1)) + (instance (export "e9") (instantiate $m1)) ) (component $m3 - (instance (export "0") (instantiate $m2)) - (instance (export "1") (instantiate $m2)) - (instance (export "2") (instantiate $m2)) - (instance (export "3") (instantiate $m2)) - (instance (export "4") (instantiate $m2)) - (instance (export "5") (instantiate $m2)) - (instance (export "6") (instantiate $m2)) - (instance (export "7") (instantiate $m2)) - (instance (export "8") (instantiate $m2)) - (instance (export "9") (instantiate $m2)) + (instance (export "e0") (instantiate $m2)) + (instance (export "e1") (instantiate $m2)) + (instance (export "e2") (instantiate $m2)) + (instance (export "e3") (instantiate $m2)) + (instance (export "e4") (instantiate $m2)) + (instance (export "e5") (instantiate $m2)) + (instance (export "e6") (instantiate $m2)) + (instance (export "e7") (instantiate $m2)) + (instance (export "e8") (instantiate $m2)) + (instance (export "e9") (instantiate $m2)) ) (component $m4 - (instance (export "0") (instantiate $m3)) - (instance (export "1") (instantiate $m3)) - (instance (export "2") (instantiate $m3)) - (instance (export "3") (instantiate $m3)) - (instance (export "4") (instantiate $m3)) - (instance (export "5") (instantiate $m3)) - (instance (export "6") (instantiate $m3)) - (instance (export "7") (instantiate $m3)) - (instance (export "8") (instantiate $m3)) - (instance (export "9") (instantiate $m3)) + (instance (export "e0") (instantiate $m3)) + (instance (export "e1") (instantiate $m3)) + (instance (export "e2") (instantiate $m3)) + (instance (export "e3") (instantiate $m3)) + (instance (export "e4") (instantiate $m3)) + (instance (export "e5") (instantiate $m3)) + (instance (export "e6") (instantiate $m3)) + (instance (export "e7") (instantiate $m3)) + (instance (export "e8") (instantiate $m3)) + (instance (export "e9") (instantiate $m3)) ) (component $m5 - (instance (export "0") (instantiate $m4)) - (instance (export "1") (instantiate $m4)) - (instance (export "2") (instantiate $m4)) - (instance (export "3") (instantiate $m4)) - (instance (export "4") (instantiate $m4)) - (instance (export "5") (instantiate $m4)) - (instance (export "6") (instantiate $m4)) - (instance (export "7") (instantiate $m4)) - (instance (export "8") (instantiate $m4)) - (instance (export "9") (instantiate $m4)) + (instance (export "e0") (instantiate $m4)) + (instance (export "e1") (instantiate $m4)) + (instance (export "e2") (instantiate $m4)) + (instance (export "e3") (instantiate $m4)) + (instance (export "e4") (instantiate $m4)) + (instance (export "e5") (instantiate $m4)) + (instance (export "e6") (instantiate $m4)) + (instance (export "e7") (instantiate $m4)) + (instance (export "e8") (instantiate $m4)) + (instance (export "e9") (instantiate $m4)) ) (component $m6 - (instance (export "0") (instantiate $m5)) - (instance (export "1") (instantiate $m5)) - (instance (export "2") (instantiate $m5)) - (instance (export "3") (instantiate $m5)) - (instance (export "4") (instantiate $m5)) - (instance (export "5") (instantiate $m5)) - (instance (export "6") (instantiate $m5)) - (instance (export "7") (instantiate $m5)) - (instance (export "8") (instantiate $m5)) - (instance (export "9") (instantiate $m5)) + (instance (export "e0") (instantiate $m5)) + (instance (export "e1") (instantiate $m5)) + (instance (export "e2") (instantiate $m5)) + (instance (export "e3") (instantiate $m5)) + (instance (export "e4") (instantiate $m5)) + (instance (export "e5") (instantiate $m5)) + (instance (export "e6") (instantiate $m5)) + (instance (export "e7") (instantiate $m5)) + (instance (export "e8") (instantiate $m5)) + (instance (export "e9") (instantiate $m5)) ) (component $m7 - (instance (export "0") (instantiate $m6)) - (instance (export "1") (instantiate $m6)) - (instance (export "2") (instantiate $m6)) - (instance (export "3") (instantiate $m6)) - (instance (export "4") (instantiate $m6)) - (instance (export "5") (instantiate $m6)) - (instance (export "6") (instantiate $m6)) - (instance (export "7") (instantiate $m6)) - (instance (export "8") (instantiate $m6)) - (instance (export "9") (instantiate $m6)) + (instance (export "e0") (instantiate $m6)) + (instance (export "e1") (instantiate $m6)) + (instance (export "e2") (instantiate $m6)) + (instance (export "e3") (instantiate $m6)) + (instance (export "e4") (instantiate $m6)) + (instance (export "e5") (instantiate $m6)) + (instance (export "e6") (instantiate $m6)) + (instance (export "e7") (instantiate $m6)) + (instance (export "e8") (instantiate $m6)) + (instance (export "e9") (instantiate $m6)) ) ) "effective type size exceeds the limit") @@ -1782,71 +1782,85 @@ ;; size(t1) == 10 (type $t1 (record - (field "0" $t0) - (field "1" $t0) - (field "2" $t0) - (field "3" $t0) - (field "4" $t0) - (field "5" $t0) - (field "6" $t0) - (field "7" $t0) - (field "8" $t0) - (field "9" $t0) + (field "f0" $t0) + (field "f1" $t0) + (field "f2" $t0) + (field "f3" $t0) + (field "f4" $t0) + (field "f5" $t0) + (field "f6" $t0) + (field "f7" $t0) + (field "f8" $t0) + (field "f9" $t0) )) ;; size(t2) == 100 (type $t2 (record - (field "0" $t1) - (field "1" $t1) - (field "2" $t1) - (field "3" $t1) - (field "4" $t1) - (field "5" $t1) - (field "6" $t1) - (field "7" $t1) - (field "8" $t1) - (field "9" $t1) + (field "f0" $t1) + (field "f1" $t1) + (field "f2" $t1) + (field "f3" $t1) + (field "f4" $t1) + (field "f5" $t1) + (field "f6" $t1) + (field "f7" $t1) + (field "f8" $t1) + (field "f9" $t1) )) ;; size(t3) == 1000 (type $t3 (record - (field "0" $t2) - (field "1" $t2) - (field "2" $t2) - (field "3" $t2) - (field "4" $t2) - (field "5" $t2) - (field "6" $t2) - (field "7" $t2) - (field "8" $t2) - (field "9" $t2) + (field "f0" $t2) + (field "f1" $t2) + (field "f2" $t2) + (field "f3" $t2) + (field "f4" $t2) + (field "f5" $t2) + (field "f6" $t2) + (field "f7" $t2) + (field "f8" $t2) + (field "f9" $t2) )) ;; size(t4) == 10000 (type $t4 (record - (field "0" $t3) - (field "1" $t3) - (field "2" $t3) - (field "3" $t3) - (field "4" $t3) - (field "5" $t3) - (field "6" $t3) - (field "7" $t3) - (field "8" $t3) - (field "9" $t3) + (field "f0" $t3) + (field "f1" $t3) + (field "f2" $t3) + (field "f3" $t3) + (field "f4" $t3) + (field "f5" $t3) + (field "f6" $t3) + (field "f7" $t3) + (field "f8" $t3) + (field "f9" $t3) + )) + + ;; size(t5) == 100000 + (type $t5 (record + (field "f0" $t4) + (field "f1" $t4) + (field "f2" $t4) + (field "f3" $t4) + (field "f4" $t4) + (field "f5" $t4) + (field "f6" $t4) + (field "f7" $t4) + (field "f8" $t4) + (field "f9" $t4) )) (type $f (func - (param "a" $t4) - (param "b" $t4) - (param "c" $t4) - (param "d" $t4) - (param "e" $t4) - (param "f" $t4) - (param "g" $t4) - (param "h" $t4) - (param "i" $t4) - (param "j" $t4) + (param "a" $t5) + (param "b" $t5) + (param "c" $t5) + (param "d" $t5) + (param "e" $t5) + (param "f" $t5) + (param "g" $t5) + (param "h" $t5) + (param "i" $t5) + (param "j" $t5) )) ) "effective type size exceeds the limit") diff --git a/tests/local/component-model/virtualize.wast b/tests/local/component-model/virtualize.wast index 0e24e92d5c..13926a5de6 100644 --- a/tests/local/component-model/virtualize.wast +++ b/tests/local/component-model/virtualize.wast @@ -9,8 +9,8 @@ (component $child (import "wasi-file" (instance $wasi-file - (export "read" (func $read (param u32) (result (list u8)))) - (export "write" (func $write (param (list u8)) (result u32))) + (export "read" (func (param "count" u32) (result (list u8)))) + (export "write" (func (param "bytes" (list u8)) (result u32))) )) (core instance $libc (instantiate $libc)) @@ -42,8 +42,8 @@ (component $virtualize (import "wasi-file" (instance $wasi-file - (export "read" (func $read (param u32) (result (list u8)))) - (export "write" (func $write (param (list u8)) (result u32))) + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) )) (export "read" (func $wasi-file "read")) (export "write" (func $wasi-file "write")) @@ -51,45 +51,45 @@ (component (type $WasiFile (instance - (export "read" (func $read (param u32) (result (list u8)))) - (export "write" (func $write (param (list u8)) (result u32))) + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) )) - (import "wasi_file" (instance $real-wasi (type $WasiFile))) - (import "./virtualize.wasm" (component $VIRTUALIZE - (import "wasi_file" (instance (type $WasiFile))) - (export "read" (func $read (param u32) (result (list u8)))) - (export "write" (func $write (param (list u8)) (result u32))) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) + (import "virtualize" (component $VIRTUALIZE + (import "wasi-file" (instance (type $WasiFile))) + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) )) - (import "./child.wasm" (component $CHILD - (import "wasi_file" (instance (type $WasiFile))) - (export "play" (func $play)) + (import "child" (component $CHILD + (import "wasi-file" (instance (type $WasiFile))) + (export "play" (func)) ) ) - (instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi_file" (instance $real-wasi)))) - (instance $child (instantiate $CHILD (with "wasi_file" (instance $virt-wasi)))) + (instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance $real-wasi)))) + (instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) (export "work" (func $child "play")) ) (component (type $WasiFile (instance - (export "read" (func $read (param u32) (result (list u8)))) - (export "write" (func $write (param (list u8)) (result u32))) + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) )) - (import "wasi_file" (instance $real-wasi (type $WasiFile))) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) (core instance $libc (instantiate $libc)) (core module $CHILD - (import "wasi_file" "read" (func $wasi-file (param i32 i32))) + (import "wasi-file" "read" (func $wasi-file (param i32 i32))) (func $play (export "play") unreachable ) ) (core module $VIRTUALIZE - (import "wasi_file" "read" (func (param i32 i32))) + (import "wasi-file" "read" (func (param i32 i32))) (func (export "read") (param i32 i32) unreachable ) @@ -105,8 +105,8 @@ ) ) - (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi_file" (instance (export "read" (func $real-wasi-read)))))) - (core instance $child (instantiate $CHILD (with "wasi_file" (instance $virt-wasi)))) + (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance (export "read" (func $real-wasi-read)))))) + (core instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) (func (export "work") (canon lift (core func $child "play") (memory $libc "mem") diff --git a/tests/local/dylink0.wast b/tests/local/dylink0.wast new file mode 100644 index 0000000000..9ed5fc1745 --- /dev/null +++ b/tests/local/dylink0.wast @@ -0,0 +1,70 @@ +(module + (@dylink.0) +) + +(module + (@dylink.0) + (@dylink.0) +) + +(module + (@dylink.0 + (mem-info) + (mem-info (memory 1 1)) + (mem-info (table 1 1)) + (mem-info (memory 1 1) (table 1 1)) + ) +) + +(module + (@dylink.0 + (needed) + (needed "a" "b") + (needed "a") + ) +) + +(module + (@dylink.0 + (export-info "a" 0) + (export-info "b" 1) + ) +) + +(module + (@dylink.0 + (import-info "a" "a" 0) + (import-info "b" "b" 1) + ) +) + +(module + (@dylink.0 + (mem-info (memory 1 1)) + (needed "a" "b") + (export-info "a" 0) + (import-info "a" "a" 0) + (import-info "b" "b" 1) + ) +) + +(module + (@dylink.0 + (export-info "a" 0) + (import-info "a" "a" 0) + (export-info "a" 0) + (export-info "a" 0) + (import-info "a" "a" 0) + (import-info "a" "a" 0) + (export-info "a" 0) + (import-info "a" "a" 0) + ) +) + +(module + (@dylink.0 + (export-info "a" 0xffffffff) + (export-info "a" binding-local) + (export-info "a" 2 binding-local binding-weak 0 undefined) + ) +) diff --git a/tests/local/elem.wast b/tests/local/elem.wast index 51f9a44a82..ef5a2fd642 100644 --- a/tests/local/elem.wast +++ b/tests/local/elem.wast @@ -1,3 +1,12 @@ +(module + (table 1 funcref) + (elem (offset i32.const 0) funcref) + (elem (i32.const 0) funcref) + (elem (offset i32.const 0 i32.const 0 i32.add) funcref) + (elem (offset (i32.add (i32.const 0) (i32.const 0))) funcref) + (elem (i32.add (i32.const 0) (i32.const 0)) funcref) +) + (assert_invalid (module (table 1 funcref) @@ -12,3 +21,10 @@ ) "constant expression required" ) +(assert_malformed + (module quote + "(table 1 funcref)" + "(elem (i32.const 0 i32.const 0 i32.add) funcref)" + ) + "folded instruction" +) diff --git a/tests/local/empty-elem.wast b/tests/local/empty-elem.wast index e30f9bd092..18d7979420 100644 --- a/tests/local/empty-elem.wast +++ b/tests/local/empty-elem.wast @@ -1,6 +1,13 @@ (module - (elem) + (table 1 funcref) + (table 1 funcref) + + (elem (i32.const 0) func) (elem func) - (elem funcref) + (elem (table 1) (i32.const 0) func) (elem declare func) - (elem declare funcref)) + (elem (i32.const 0) funcref) + (elem funcref) + (elem (table 1) (i32.const 0) funcref) + (elem declare funcref) +) diff --git a/tests/local/exnref/exnref.wast b/tests/local/exnref/exnref.wast new file mode 100644 index 0000000000..421eca772e --- /dev/null +++ b/tests/local/exnref/exnref.wast @@ -0,0 +1,5 @@ +(module + (func (param exnref)) + (func (param (ref null exn))) + (func (param (ref exn))) +) diff --git a/tests/local/exnref/throw_ref.wast b/tests/local/exnref/throw_ref.wast new file mode 100644 index 0000000000..67ead8198d --- /dev/null +++ b/tests/local/exnref/throw_ref.wast @@ -0,0 +1,6 @@ +(module + (func (param exnref) + local.get 0 + throw_ref + ) +) diff --git a/tests/local/exnref/try_table.wast b/tests/local/exnref/try_table.wast new file mode 100644 index 0000000000..ade6a0a520 --- /dev/null +++ b/tests/local/exnref/try_table.wast @@ -0,0 +1,95 @@ +(module + (tag $a (param i32)) + + (func + (; empty try_table ;) + try_table + end + + (; try_table with result ;) + try_table (result i32) + i32.const 0 + end + drop + + (; try_table can catches ;) + try_table (catch $a 0) + end + + try_table (catch $a 0) (catch $a 0) + end + + try_table (catch_all 0) + end + + try_table (catch $a 0) (catch_all 0) + end + + try_table (catch $a 0) (catch $a 0) (catch_all 0) + end + + (; try_table can have results and catches ;) + try_table (result i32) (catch $a 0) + i32.const 0 + end + drop + + try_table (result i32) (catch $a 0) (catch $a 0) + i32.const 0 + end + drop + + try_table (result i32) (catch_all 0) + i32.const 0 + end + drop + + try_table (result i32) (catch $a 0) (catch_all 0) + i32.const 0 + end + drop + + try_table (result i32) (catch $a 0) (catch $a 0) (catch_all 0) + i32.const 0 + end + drop + + (; mixes of catch, catch_ref, catch_all, and catch_all_ref ;) + + try_table (catch_ref $a 0) + end + + try_table (catch_ref $a 0) (catch_ref $a 0) + end + + try_table (catch $a 0) (catch_ref $a 0) + end + + try_table (catch_ref $a 0) (catch_ref $a 0) + end + + try_table (catch_ref $a 0) (catch $a 0) + end + + try_table (catch_all 0) + end + + try_table (catch_all_ref 0) + end + + try_table (catch_ref $a 0) (catch_all_ref 0) + end + + try_table (catch_ref $a 0) (catch_ref $a 0) (catch_all_ref 0) + end + + try_table (catch $a 0) (catch_ref $a 0) (catch_all_ref 0) + end + + try_table (catch_ref $a 0) (catch_ref $a 0) (catch_all_ref 0) + end + + try_table (catch_ref $a 0) (catch $a 0) (catch_all_ref 0) + end + ) +) diff --git a/tests/local/function-reference-structural-matching.wat b/tests/local/function-reference-structural-matching.wat new file mode 100644 index 0000000000..038b1bd3a3 --- /dev/null +++ b/tests/local/function-reference-structural-matching.wat @@ -0,0 +1,16 @@ +(module + (type $t1 (func)) + + (type $t2_a (func (param (ref $t1) (ref $t1)))) + + (type $t2_b (func (param (ref $t1) (ref $t1)))) + + (func $f (param (ref $t2_a)) + nop + ) + + (func $g (param (ref $t2_b)) + local.get 0 + call $f + ) +) diff --git a/tests/local/function-references/bad-call-ref-ty.wast b/tests/local/function-references/bad-call-ref-ty.wast new file mode 100644 index 0000000000..523813b439 --- /dev/null +++ b/tests/local/function-references/bad-call-ref-ty.wast @@ -0,0 +1,35 @@ +(assert_invalid + (module + (type $t (func (param i32))) + (func (param $f funcref) + (call_ref $t (local.get $f)) + ) + ) + "funcref on stack does not match specified type") + +(assert_invalid + (module + (type $t (func (param i32))) + (func (param $f (ref $t)) + (call_ref $t (local.get $f)) + ) + ) + "expected i32 but nothing on stack") + +(assert_invalid + (module + (type $t (func )) + (func (param $f (ref $t)) + (call_ref 5 (local.get $f)) + ) + ) + "type index out of bounds") + +(assert_invalid + (module + (type $t (func )) + (func (param $f (ref $t)) + (call_ref 100 (local.get $f)) + ) + ) + "type index out of bounds") diff --git a/tests/local/function-references/let-bad.wast b/tests/local/function-references/let-bad.wast index 9ffc098c8f..300026cd6d 100644 --- a/tests/local/function-references/let-bad.wast +++ b/tests/local/function-references/let-bad.wast @@ -2,4 +2,4 @@ (module (func let) ) - "fill me in once wasmparser implements validation") + "illegal opcode: 0x17") diff --git a/tests/local/function-references/table-nonnull.wast b/tests/local/function-references/table-nonnull.wast new file mode 100644 index 0000000000..2b43eeac1a --- /dev/null +++ b/tests/local/function-references/table-nonnull.wast @@ -0,0 +1,19 @@ +;; Table initializer + +(module + (type $dummy (func)) + (func $dummy) + + (table $t1 10 funcref) + (table $t2 10 funcref (ref.func $dummy)) + (table $t3 10 (ref $dummy) (ref.func $dummy)) + (table $t4 10 (ref func) (ref.func $dummy)) + + (func (export "get1") (result funcref) (table.get $t1 (i32.const 1))) + (func (export "get2") (result funcref) (table.get $t2 (i32.const 4))) + (func (export "get3") (result funcref) (table.get $t3 (i32.const 7))) +) + +(assert_return (invoke "get1") (ref.null)) +(assert_return (invoke "get2") (ref.func)) +(assert_return (invoke "get3") (ref.func)) diff --git a/tests/local/fuzz1.wat b/tests/local/fuzz1.wat index 576763f19b..a15ba7ec96 100644 --- a/tests/local/fuzz1.wat +++ b/tests/local/fuzz1.wat @@ -260,9 +260,9 @@ (i32.eqz (global.get $hangLimit) ) - (return + (then (return (i64.const 4293531749) - ) + )) ) (global.set $hangLimit (i32.sub @@ -279,8 +279,8 @@ (local.tee $0 (if (result i32) (i32.const -2147483647) - (local.get $0) - (block $label$4 (result i32) + (then (local.get $0)) + (else (block $label$4 (result i32) (br_if $label$4 (if (result i32) (block $label$5 (result i32) @@ -293,9 +293,9 @@ (i32.eqz (global.get $hangLimit) ) - (return + (then (return (i64.const -32766) - ) + )) ) (global.set $hangLimit (i32.sub @@ -315,22 +315,22 @@ ) ) ) - (block $label$7 (result f32) + (then (block $label$7 (result f32) (f32.const -nan:0x7fffda) - ) - (f32.const 4294967296) + )) + (else (f32.const 4294967296)) ) ) (i32.const -2147483648) ) - (i32.const -1073741824) - (local.get $0) + (then (i32.const -1073741824)) + (else (local.get $0)) ) (i32.eqz (global.get $global$0) ) ) - ) + )) ) ) ) diff --git a/tests/local/gc/gc-array-types-invalid.wast b/tests/local/gc/gc-array-types-invalid.wast new file mode 100644 index 0000000000..a3073bff78 --- /dev/null +++ b/tests/local/gc/gc-array-types-invalid.wast @@ -0,0 +1,8 @@ +;; --enable-gc + +(assert_invalid + (module + (type $a (array (mut (ref null 1000)))) + ) + "unknown type" +) diff --git a/tests/local/gc/gc-array-types.wat b/tests/local/gc/gc-array-types.wat new file mode 100644 index 0000000000..fd5b0eae2c --- /dev/null +++ b/tests/local/gc/gc-array-types.wat @@ -0,0 +1,9 @@ +;; --enable-gc + +(module + (type $a (array i32)) + (type $b (array (mut i32))) + (type $c (array (mut (ref null $b)))) + (type $d (array i8)) + (type $e (array (mut i16))) +) diff --git a/tests/local/gc/gc-array.wat b/tests/local/gc/gc-array.wat index f94a1c0702..92402e60aa 100644 --- a/tests/local/gc/gc-array.wat +++ b/tests/local/gc/gc-array.wat @@ -6,7 +6,7 @@ (type $c (array (mut (ref null $b)))) (data $data "\\0\\1\\2\\3") - (elem $elem funcref $func) + (elem $elem func $func) (func $func) (func diff --git a/tests/local/gc/gc-heaptypes.wat b/tests/local/gc/gc-heaptypes.wat index b2401a03de..3eed1156f7 100644 --- a/tests/local/gc/gc-heaptypes.wat +++ b/tests/local/gc/gc-heaptypes.wat @@ -6,6 +6,9 @@ (func (param anyref (ref any) (ref null any))) (func (param eqref (ref eq) (ref null eq))) (func (param i31ref (ref i31) (ref null i31))) - (func (param dataref (ref data) (ref null data))) + (func (param structref (ref struct) (ref null struct))) (func (param arrayref (ref array) (ref null array))) + (func (param nullfuncref (ref nofunc) (ref null nofunc))) + (func (param nullexternref (ref noextern) (ref null noextern))) + (func (param nullref (ref none) (ref null none))) ) diff --git a/tests/local/gc/gc-i31.wat b/tests/local/gc/gc-i31.wat new file mode 100644 index 0000000000..f723e211c2 --- /dev/null +++ b/tests/local/gc/gc-i31.wat @@ -0,0 +1,14 @@ +;; --enable-gc + +(module + (func $f (result i32 i32) + (local $a (ref i31)) + (local $b (ref null i31)) + (local $c i31ref) + + (local.set $a (ref.i31 (i32.const 42))) + (local.set $b (ref.i31 (i32.const 0))) + (i31.get_u (local.get $a)) + (i31.get_s (local.get $b)) + ) +) diff --git a/tests/local/gc/gc-rec-groups-invalid.wast b/tests/local/gc/gc-rec-groups-invalid.wast new file mode 100644 index 0000000000..b2de1893c3 --- /dev/null +++ b/tests/local/gc/gc-rec-groups-invalid.wast @@ -0,0 +1,16 @@ +;; --enable-gc + +(assert_invalid + (module + (rec + (type $t1 (struct (field (ref $t2)))) + (type $t2 (struct (field (ref $t3)))) ;; <--- unknown type + ) + + (rec + (type $t3 (struct (field (ref $t4)))) + (type $t4 (sub $t2 (struct (field (ref $t3))))) + ) + ) + "unknown type" +) diff --git a/tests/local/gc/gc-rec-sub.wat b/tests/local/gc/gc-rec-sub.wat index 9ee43c9d4b..2a29625cc3 100644 --- a/tests/local/gc/gc-rec-sub.wat +++ b/tests/local/gc/gc-rec-sub.wat @@ -29,11 +29,26 @@ ) (rec - (type $a (func)) - (sub $a (type (func))) + (type $a (sub (func))) + (type (sub $a (func))) ) (rec - (sub $a (type (func))) + (type (sub $a (func))) ) - (sub $a (type (func))) + (rec + (type (sub final $a (func))) + ) + (type (sub $a (func))) + + (rec + (type $t1 (struct (field (ref $t2)))) + (type $t2 (sub (struct (field (ref $t1))))) + ) + + (rec + (type $t3 (struct (field (ref $t4)))) + (type $t4 (sub $t2 (struct (field (ref $t3))))) + ) + + (rec) ) diff --git a/tests/local/gc/gc-ref.wat b/tests/local/gc/gc-ref.wat index 6f21578280..0a393d9a15 100644 --- a/tests/local/gc/gc-ref.wat +++ b/tests/local/gc/gc-ref.wat @@ -7,32 +7,35 @@ (type $f1 (func (param (ref $a)))) (type $f2 (func (result (ref $b)))) - (global (ref $a)) - (global (ref $b)) + (global (ref null $a) (ref.null $a)) + (global (ref null $b) (ref.null $b)) (func (param (ref $a))) (func (param (ref 0))) (func (type $f1) (param (ref 0))) - (func (type 2) (param (ref 0))) - (func (result (ref $a))) + (func (type $f1) (param (ref $a))) + (func (result (ref $a)) unreachable) (func (local (ref $a))) (func - select (result (ref $a)) - - (block (param (ref $a))) - (block (result (ref $b))) - (block $f1 (param (ref $a))) - (block $f2 (result (ref $b))) - - (loop (param (ref $a))) - (loop (result (ref $b))) - (loop $f1 (param (ref $a))) - (loop $f2 (result (ref $b))) - - (if (param (ref $a)) (then) (else)) - (if (result (ref $b)) (then) (else)) - (if $f1 (param (ref $a)) (then) (else)) - (if $f2 (result (ref $b)) (then) (else)) + (select (result (ref $a)) unreachable unreachable (i32.const 0)) + + (block (param (ref $a)) unreachable) + (block (result (ref $b)) unreachable) + (block $f1 (param (ref $a)) unreachable) + (block $f2 (result (ref $b)) unreachable) + + (loop (param (ref $a)) unreachable) + (loop (result (ref $b)) unreachable) + (loop $f1 (param (ref $a)) unreachable) + (loop $f2 (result (ref $b)) unreachable) + drop + + (if (param (ref $a)) (then unreachable) (else unreachable)) + (if (result (ref $b)) (then unreachable) (else unreachable)) + drop + (if $f1 (param (ref $a)) (then unreachable) (else unreachable)) + (if $f2 (result (ref $b)) (then unreachable) (else unreachable)) + drop ) ) diff --git a/tests/local/gc/gc-struct-types-invalid.wast b/tests/local/gc/gc-struct-types-invalid.wast new file mode 100644 index 0000000000..e02a1914b5 --- /dev/null +++ b/tests/local/gc/gc-struct-types-invalid.wast @@ -0,0 +1,20 @@ +;; --enable-gc + +(assert_malformed + (module quote + "(type (struct (field $id)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type (struct (field $id i32 i32)))" + ) + "expected `)`" +) +(assert_malformed + (module quote + "(type (struct (field i32 $id i32)))" + ) + "unexpected token" +) diff --git a/tests/local/gc/gc-struct-types.wat b/tests/local/gc/gc-struct-types.wat new file mode 100644 index 0000000000..b7f8d73abe --- /dev/null +++ b/tests/local/gc/gc-struct-types.wat @@ -0,0 +1,27 @@ +;; --enable-gc + +(module + (type (struct)) + (type (struct (field i32))) + (type (struct (field (mut i32)))) + (type (struct (field i32) (field i32))) + (type (struct (field i32) (field (mut i32)))) + (type (struct (field (mut i32)) (field (mut i32)))) + + (type $a (struct (field f32))) + (type $b (struct (field f32))) + + (type (struct (field $field_a externref))) + (type (struct (field $field_b externref) (field $field_c funcref))) + + (type (struct (field))) + (type (struct (field i32 i32))) + (type (struct (field i32 (mut i32)))) + (type (struct (field (mut i32) i32))) + (type (struct (field (mut i32) (mut i32)))) + (type (struct (field $a i32) (field f32 f32 f32))) + + (type (struct (field i32) (field (ref null $a)) (field (mut (ref null $b))))) + (type (struct (field i32 (ref null $a) (mut (ref null $b))))) + (type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) +) diff --git a/tests/local/gc/gc-struct.wat b/tests/local/gc/gc-struct.wat index 514286c723..0ca35c618a 100644 --- a/tests/local/gc/gc-struct.wat +++ b/tests/local/gc/gc-struct.wat @@ -8,8 +8,8 @@ (type (struct (field i32) (field (mut i32)))) (type (struct (field (mut i32)) (field (mut i32)))) - (type $a (struct (field f32))) - (type $b (struct (field f32))) + (type $a (struct (field $field_a f32))) + (type $b (struct (field $field_b f32))) (type (struct (field $field_a externref))) (type (struct (field $field_b externref) (field $field_c funcref))) @@ -18,6 +18,6 @@ struct.new $a struct.new_default $a struct.get $a $field_a - struct.set $b $field_c + struct.set $b $field_b ) ) diff --git a/tests/local/gc/gc-subtypes-invalid.wast b/tests/local/gc/gc-subtypes-invalid.wast new file mode 100644 index 0000000000..da05970827 --- /dev/null +++ b/tests/local/gc/gc-subtypes-invalid.wast @@ -0,0 +1,151 @@ +;; --enable-gc + +(assert_invalid + (module + (type $a (func)) + (type $b (sub $a (func))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $a (sub (func))) + (type $b (sub final $a (func))) + (type $c (sub $b (func))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $a (sub (func))) + (type $b (sub $a (struct))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $a (sub (func))) + (type $b (sub $a (func (param i32)))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $a (sub (struct (field i32)))) + (type $b (sub $a (struct (field i64)))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $d (sub (struct))) + (type $e (sub $d (struct (field (ref null $d))))) + (type $f (sub $e (struct (field (ref $e))))) + + (type $g (sub (func (param (ref $e)) (result (ref $e))))) + (type $i (sub $g (func (param (ref $f)) (result (ref $d))))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $o (sub (array i32))) + (type (sub $o (array (mut i32)))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $o (sub (array i32))) + (type (sub $o (array i64))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $q (sub (array (mut anyref)))) + (type $r (sub $q (array i31ref))) + (type $s (sub $r (array (ref i31)))) + (type (sub $s (array (ref null i31)))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $q (sub (array (mut anyref)))) + (type $rr (sub $q (array arrayref))) + (type $ss (sub $rr (array (ref array)))) + (type (sub $ss (array (ref null array)))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $q (sub (array (mut anyref)))) + (type $rrr (sub $q (array structref))) + (type $sss (sub $rrr (array (ref struct)))) + (type (sub $sss (array (ref null struct)))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $t (sub (array (mut funcref)))) + (type $u (sub $t (array (ref null func)))) + (type (sub $u (array (mut (ref func))))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $t (sub (array (mut funcref)))) + (type $u (sub $t (array (ref null func)))) + (type (sub $u (array (ref null extern)))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $t0 (sub (array (mut externref)))) + (type $u0 (sub $t0 (array (ref null extern)))) + (type (sub $u0 (array (mut (ref extern))))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $t0 (sub (array (mut externref)))) + (type $u0 (sub $t0 (array (ref null extern)))) + (type $v0 (sub $u0 (array (ref extern)))) + (type (sub $v0 (array nullexternref))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $t (sub (array (mut funcref)))) + (type (sub $t (array nullexternref))) ;; invalid + ) + "subtype must match supertype" +) +(assert_invalid + (module + (type $d (sub (struct))) + (type $e (sub $d (struct (field (ref null $d))))) + (type (sub $e (struct (field (ref 1000))))) + ) + "type index out of bounds" +) +(assert_invalid + (module + (type (struct (field $vt (mut i32)) (field $vt (mut i64)))) + ) + "duplicate identifier" +) +(assert_invalid + (module + (type $a (func)) ;; types without `(sub )` are considered final + (type (sub $a (func))) + ) + "subtype must match supertype" +) diff --git a/tests/local/gc/gc-subtypes.wat b/tests/local/gc/gc-subtypes.wat new file mode 100644 index 0000000000..66f22b4037 --- /dev/null +++ b/tests/local/gc/gc-subtypes.wat @@ -0,0 +1,105 @@ +;; --enable-gc + +(module + (type $a (sub (func))) + (type $b (sub $a (func))) + (type $c (sub $b (func))) + (type $b1 (sub final $a (func))) + + ;; struct, ref types, mutability, nullability + (type $d (sub (struct))) + (type $e (sub $d (struct (field (mut (ref null $d)))))) ;; width + (type $f (sub final $e (struct (field (ref $e))))) ;; depth + + ;; func + (type $g (sub (func (param (ref $e)) (result (ref $e))))) + (type $h (sub $g (func (param (ref $d)) (result (ref $f))))) + + (type $j (sub (func (param (ref $b)) (result (ref $b))))) + (type $k (sub $j (func (param (ref $a)) (result (ref $c))))) + + ;; valid: expanded param/result types are equal to those of the parent + (type $l (sub $j (func (param (ref $c)) (result (ref $a))))) + + ;; array, val types, ref types, mutability, nullability + (type $m (sub (array (mut i32)))) + (type $n (sub $m (array i32))) + + (type $o (sub (array i32))) + (type $p (sub $o (array i32))) + + (type $o1 (sub (array i64))) + (type $p1 (sub $o1 (array i64))) + + ;; any refs + (type $q (sub (array (mut anyref)))) + (type $q0 (sub $q (array (ref any)))) + + ;; eq refs + (type $q1 (sub $q (array (mut eqref)))) + (type $q2 (sub $q1 (array (mut (ref eq))))) + (type $q3 (sub $q2 (array (ref eq)))) + + ;; i31 refs + (type $r (sub $q (array i31ref))) + (type $r1 (sub $q1 (array i31ref))) + (type $s (sub $r (array (ref i31)))) + (type $s1 (sub $q1 (array (ref i31)))) + (type $s2 (sub $q2 (array (ref i31)))) + + ;; array refs + (type $rr (sub $q (array arrayref))) + (type $rr1 (sub $q1 (array arrayref))) + (type $ss (sub $rr (array (ref array)))) + (type $ss0 (sub $ss (array (ref $rr)))) + (type $ss1 (sub $q1 (array (ref array)))) + (type (sub $q1 (array (ref $rr)))) + (type $ss2 (sub $q2 (array (ref array)))) + (type (sub $q2 (array (ref $rr)))) + + ;; struct refs + (type $rrr (sub $q (array structref))) + (type $rrr1 (sub $q1 (array structref))) + (type $sss (sub $rrr (array (ref struct)))) + (type $sss0 (sub $rrr (array (ref null $d)))) + (type $sss1 (sub $q1 (array (ref struct)))) + (type (sub $q1 (array (ref $d)))) + (type $sss2 (sub $q2 (array (ref struct)))) + (type (sub $q2 (array (ref $d)))) + + ;; none refs + (type $z1 (sub $q (array (mut nullref)))) + (type $z2 (sub $q0 (array (ref none)))) + (type $z3 (sub $z1 (array (mut (ref none))))) + (type $z4 (sub $z1 (array nullref))) + (type (sub $q1 (array nullref))) + (type (sub $r (array nullref))) + (type (sub $rr (array nullref))) + (type (sub $rrr (array nullref))) + (type (sub $q1 (array (ref none)))) + (type (sub $r (array (ref none)))) + (type (sub $rr (array (ref none)))) + (type (sub $rrr (array (ref none)))) + + ;; func refs + (type $t (sub (array (mut funcref)))) + (type $u (sub $t (array (ref null func)))) + (type $v (sub $u (array (ref func)))) + (type $w (sub $v (array (ref $a)))) + (type $x (sub $t (array (ref null $a)))) + (type $y (sub $w (array (ref nofunc)))) + (type $z (sub $x (array nullfuncref))) + + ;; extern refs + (type $t0 (sub (array (mut externref)))) + (type $u0 (sub $t0 (array (ref null extern)))) + (type $v0 (sub $u0 (array (ref extern)))) + (type $y0 (sub $v0 (array (ref noextern)))) + (type $y01 (sub $u0 (array (ref noextern)))) + (type $z0 (sub $u0 (array nullexternref))) + + (type $A (sub (struct (field $vt (mut i32))))) + (type $B (sub $A (struct (field $vt (mut i32))))) + (type (sub $A (struct (field $tv (mut i32))))) ;; same field, different name + (type (sub $A (struct (field (mut i32)) (field $vt (mut i64))))) ;; different field, same name +) diff --git a/tests/local/gc/let.wat b/tests/local/gc/let.wat deleted file mode 100644 index d3d223881b..0000000000 --- a/tests/local/gc/let.wat +++ /dev/null @@ -1,46 +0,0 @@ -;; --enable-function-references - -(module - (func - (let) - - let end - - let - end - ) - (func - i32.const 0 - (let (param i32) drop) - - i32.const 0 - let (param i32) drop end - - i32.const 0 - let (param i32) - drop - end - ) - (func - (let (result i32) - i32.const 0 - ) - drop - - let (result i32) i32.const 0 end - drop - - let (result i32) - i32.const 0 - end - drop - ) - (func - (let (local $x i32) local.get $x drop) - let (local $x i32) local.get $x drop end - let (local $x i32) - local.get $x - drop - end - ) -) diff --git a/tests/local/gc/type-equivalence.wast b/tests/local/gc/type-equivalence.wast new file mode 100644 index 0000000000..3f785fe7ae --- /dev/null +++ b/tests/local/gc/type-equivalence.wast @@ -0,0 +1,134 @@ +;; Cloned from tests/testsuite/proposals/function-references/type-equivalence.wast +;; and modified for the GC proposal. + +;; Syntactic types (validation time) + +;; Simple types. + +(module + (type $t1 (func (param f32 f32) (result f32))) + (type $t2 (func (param $x f32) (param $y f32) (result f32))) + + (func $f1 (param $r (ref $t1)) (call $f2 (local.get $r))) + (func $f2 (param $r (ref $t2)) (call $f1 (local.get $r))) +) + + +;; Indirect types. + +(module + (type $s0 (func (param i32) (result f32))) + (type $s1 (func (param i32 (ref $s0)) (result (ref $s0)))) + (type $s2 (func (param i32 (ref $s0)) (result (ref $s0)))) + (type $t1 (func (param (ref $s1)) (result (ref $s2)))) + (type $t2 (func (param (ref $s2)) (result (ref $s1)))) + + (func $f1 (param $r (ref $t1)) (call $f2 (local.get $r))) + (func $f2 (param $r (ref $t2)) (call $f1 (local.get $r))) +) + + +;; Recursive types. + +;; This case has been made valid by the GC proposal: +;; every standalone type is now a recursive type group of size 1. +(module + (type $t (func (result (ref $t)))) +) + +(assert_invalid + (module + (type $t1 (func (param (ref $t2)))) + (type $t2 (func (param (ref $t1)))) + ) + "unknown type" +) + + +;; Semantic types (run time) + +;; Simple types. + +(module + (type $t1 (func (param f32 f32))) + (type $t2 (func (param $x f32) (param $y f32))) + + (func $f1 (type $t1)) + (func $f2 (type $t2)) + (table funcref (elem $f1 $f2)) + + (func (export "run") + (call_indirect (type $t1) (f32.const 1) (f32.const 2) (i32.const 1)) + (call_indirect (type $t2) (f32.const 1) (f32.const 2) (i32.const 0)) + ) +) +(assert_return (invoke "run")) + + +;; Indirect types. + +(module + (type $s0 (func (param i32))) + (type $s1 (func (param i32 (ref $s0)))) + (type $s2 (func (param i32 (ref $s0)))) + (type $t1 (func (param (ref $s1)))) + (type $t2 (func (param (ref $s2)))) + + (func $s1 (type $s1)) + (func $s2 (type $s2)) + (func $f1 (type $t1)) + (func $f2 (type $t2)) + (table funcref (elem $f1 $f2 $s1 $s2)) + + (func (export "run") + (call_indirect (type $t1) (ref.func $s1) (i32.const 0)) + (call_indirect (type $t1) (ref.func $s1) (i32.const 1)) + (call_indirect (type $t1) (ref.func $s2) (i32.const 0)) + (call_indirect (type $t1) (ref.func $s2) (i32.const 1)) + (call_indirect (type $t2) (ref.func $s1) (i32.const 0)) + (call_indirect (type $t2) (ref.func $s1) (i32.const 1)) + (call_indirect (type $t2) (ref.func $s2) (i32.const 0)) + (call_indirect (type $t2) (ref.func $s2) (i32.const 1)) + ) +) +(assert_return (invoke "run")) + + +;; Semantic types (link time) + +;; Simple types. + +(module + (type $t1 (func (param f32 f32) (result f32))) + (func (export "f") (param (ref $t1))) +) +(register "M") +(module + (type $t2 (func (param $x f32) (param $y f32) (result f32))) + (func (import "M" "f") (param (ref $t2))) +) + + +;; Indirect types. + +(module + (type $s0 (func (param i32) (result f32))) + (type $s1 (func (param i32 (ref $s0)) (result (ref $s0)))) + (type $s2 (func (param i32 (ref $s0)) (result (ref $s0)))) + (type $t1 (func (param (ref $s1)) (result (ref $s2)))) + (type $t2 (func (param (ref $s2)) (result (ref $s1)))) + (func (export "f1") (param (ref $t1))) + (func (export "f2") (param (ref $t1))) +) +(register "M") +(module + (type $s0 (func (param i32) (result f32))) + (type $s1 (func (param i32 (ref $s0)) (result (ref $s0)))) + (type $s2 (func (param i32 (ref $s0)) (result (ref $s0)))) + (type $t1 (func (param (ref $s1)) (result (ref $s2)))) + (type $t2 (func (param (ref $s2)) (result (ref $s1)))) + (func (import "M" "f1") (param (ref $t1))) + (func (import "M" "f1") (param (ref $t2))) + (func (import "M" "f2") (param (ref $t1))) + (func (import "M" "f2") (param (ref $t1))) +) diff --git a/tests/local/if-else-parsing.wast b/tests/local/if-else-parsing.wast new file mode 100644 index 0000000000..98a8bb60c6 --- /dev/null +++ b/tests/local/if-else-parsing.wast @@ -0,0 +1,42 @@ +(module + (func $a1 + i32.const 0 + (if (then) (else)) + ) + (func $a2 + (if (i32.const 1) (i32.eqz) (then) (else)) + ) + (func $a3 + (if (i32.const 1) (i32.eqz) (then)) + ) + (func $a4 + (if (i32.const 1) (i32.eqz) (then nop)) + ) +) +(assert_invalid + (module quote + "(func (if))" + ) + "no `then`") + +(assert_invalid + (module quote + "(func (if (else)))" + ) + "no `then`") + +(assert_invalid + (module quote + "(func (if nop (else)))" + ) + "expected `(`") +(assert_invalid + (module quote + "(func (if (nop) (else)))" + ) + "no `then`") +(assert_invalid + (module quote + "(func (if (nop) nop (then)))" + ) + "expected `(`") diff --git a/tests/local/invalid-funcref-in-data-segment.wast b/tests/local/invalid-funcref-in-data-segment.wast index 45815d27e4..3e0220bc58 100644 --- a/tests/local/invalid-funcref-in-data-segment.wast +++ b/tests/local/invalid-funcref-in-data-segment.wast @@ -2,7 +2,7 @@ (module (memory 0) (func $f) - (elem declare $f) + (elem declare func $f) (data (ref.func $f) "")) "type mismatch") diff --git a/tests/local/invalid-init-expr.wast b/tests/local/invalid-init-expr.wast new file mode 100644 index 0000000000..a0de5a5821 --- /dev/null +++ b/tests/local/invalid-init-expr.wast @@ -0,0 +1,11 @@ +(assert_invalid + (module + (table funcref (elem (call_indirect))) + ) + "non-constant operator") + +(assert_invalid + (module + (table 1 1 funcref (call_indirect)) + ) + "non-constant operator") diff --git a/tests/local/invalid-unreachable.wast b/tests/local/invalid-unreachable.wast new file mode 100644 index 0000000000..058ac77bab --- /dev/null +++ b/tests/local/invalid-unreachable.wast @@ -0,0 +1,11 @@ +(assert_invalid + (module + (func + unreachable + select + loop + i32x4.eq + end + ) + ) + "expected v128 but nothing on stack") diff --git a/tests/local/memory-discard.wat b/tests/local/memory-discard.wat new file mode 100644 index 0000000000..50d2cf897e --- /dev/null +++ b/tests/local/memory-discard.wat @@ -0,0 +1,14 @@ +(module + (memory $m i32 2) + + (func + (memory.discard (i32.const 0) (i32.const 65536)) + ) + (func + (memory.discard $m (i32.const 0) (i32.const 65536)) + ) + + (func + (memory.discard 0 (i32.const 0) (i32.const 65536)) + ) +) diff --git a/tests/local/missing-features/component-model/value-not-enabled.wast b/tests/local/missing-features/component-model/value-not-enabled.wast new file mode 100644 index 0000000000..16b340a010 --- /dev/null +++ b/tests/local/missing-features/component-model/value-not-enabled.wast @@ -0,0 +1,41 @@ +(assert_invalid + (component + (import "f" (func $f)) + (start $f) + ) + "support for component model `value`s is not enabled") + +(assert_invalid + (component + (import "f" (value string)) + ) + "support for component model `value`s is not enabled") + +(assert_invalid + (component + (export "f" (value 0)) + ) + "support for component model `value`s is not enabled") + +(assert_invalid + (component + (alias export 0 "f" (value)) + ) + "support for component model `value`s is not enabled") +(assert_invalid + (component + (import "f1" (func)) + (export "f" (func 0) (value string)) + ) + "support for component model `value`s is not enabled") +(assert_invalid + (component + (component) + (instance (instantiate 0 (with "" (value 0)))) + ) + "support for component model `value`s is not enabled") +(assert_invalid + (component + (instance (export "i" (value 0))) + ) + "support for component model `value`s is not enabled") diff --git a/tests/local/missing-features/component-not-enabled.wast b/tests/local/missing-features/component-not-enabled.wast index b31cc9a237..ace71c2d0d 100644 --- a/tests/local/missing-features/component-not-enabled.wast +++ b/tests/local/missing-features/component-not-enabled.wast @@ -3,4 +3,4 @@ "\00asm" "\0a\00\01\00" ) - "WebAssembly component model feature not enabled") + "unknown binary version and encoding combination: 0xa and 0x1, note: encoded as a component but the WebAssembly component model feature is not enabled - enable the feature to allow component validation") diff --git a/tests/local/missing-features/floats-disabled.wast b/tests/local/missing-features/floats-disabled.wast new file mode 100644 index 0000000000..de8eaae936 --- /dev/null +++ b/tests/local/missing-features/floats-disabled.wast @@ -0,0 +1,10 @@ +(assert_invalid + (module + (func (param f32)) + ) + "floating-point support is disabled") +(assert_invalid + (module + (func (local f32)) + ) + "floating-point support is disabled") diff --git a/tests/local/missing-features/rec-group.wast b/tests/local/missing-features/rec-group.wast new file mode 100644 index 0000000000..516a06c387 --- /dev/null +++ b/tests/local/missing-features/rec-group.wast @@ -0,0 +1,11 @@ +(assert_invalid + (module (rec)) + "requires `gc` proposal to be enabled") + +(assert_invalid + (module (rec (type (func)))) + "requires `gc` proposal to be enabled") + +(assert_invalid + (module (rec (type (func)) (type (func)))) + "requires `gc` proposal to be enabled") diff --git a/tests/local/missing-features/reference-types/function-references.wast b/tests/local/missing-features/reference-types/function-references.wast new file mode 100644 index 0000000000..1e3dd51327 --- /dev/null +++ b/tests/local/missing-features/reference-types/function-references.wast @@ -0,0 +1,12 @@ +(assert_invalid + (module (type (func (param (ref func))))) + "function references required") +(assert_invalid + (module (type (func (param (ref extern))))) + "function references required") +(assert_invalid + (module + (type $f (func)) + (type (func (param (ref $f)))) + ) + "function references required") diff --git a/tests/local/missing-features/reference-types/gc-indexed-types.wast b/tests/local/missing-features/reference-types/gc-indexed-types.wast new file mode 100644 index 0000000000..ff44b09463 --- /dev/null +++ b/tests/local/missing-features/reference-types/gc-indexed-types.wast @@ -0,0 +1,9 @@ +(assert_invalid + (module (type (array i32))) + "array indexed types not supported without the gc feature") +(assert_invalid + (module (type (array i8))) + "array indexed types not supported without the gc feature") +(assert_invalid + (module (type (struct))) + "struct indexed types not supported without the gc feature") diff --git a/tests/local/missing-features/reference-types/gc.wast b/tests/local/missing-features/reference-types/gc.wast new file mode 100644 index 0000000000..dd1e45ba00 --- /dev/null +++ b/tests/local/missing-features/reference-types/gc.wast @@ -0,0 +1,30 @@ +(assert_invalid + (module (type (func (param i31ref)))) + "heap types not supported without the gc feature") +(assert_invalid + (module (type (func (param anyref)))) + "heap types not supported without the gc feature") +(assert_invalid + (module (type (func (param (ref none))))) + "heap types not supported without the gc feature") +(assert_invalid + (module (type (func (param (ref array))))) + "heap types not supported without the gc feature") +(assert_invalid + (module (type (func (param (ref struct))))) + "heap types not supported without the gc feature") +(assert_invalid + (module (type (func (param (ref eq))))) + "heap types not supported without the gc feature") +(assert_invalid + (module (type (func (param (ref noextern))))) + "heap types not supported without the gc feature") +(assert_invalid + (module (type (func (param (ref nofunc))))) + "heap types not supported without the gc feature") +(assert_invalid + (module (func (local i31ref))) + "heap types not supported without the gc feature") +(assert_invalid + (module (func (block (result i31ref) unreachable))) + "heap types not supported without the gc feature") diff --git a/tests/local/missing-features/reference-types/v128-without-simd-feature.wast b/tests/local/missing-features/reference-types/v128-without-simd-feature.wast new file mode 100644 index 0000000000..7808459ac0 --- /dev/null +++ b/tests/local/missing-features/reference-types/v128-without-simd-feature.wast @@ -0,0 +1,3 @@ +(assert_invalid + (module (func select (result v128))) + "SIMD support is not enabled") diff --git a/tests/local/missing-features/v128-without-simd-feature.wast b/tests/local/missing-features/v128-without-simd-feature.wast index ec8e94e420..63a4a226d8 100644 --- a/tests/local/missing-features/v128-without-simd-feature.wast +++ b/tests/local/missing-features/v128-without-simd-feature.wast @@ -16,9 +16,6 @@ (assert_invalid (module (global v128 v128.const i64x2 0 0)) "SIMD support is not enabled") -(assert_invalid - (module (func select (result v128))) - "SIMD support is not enabled") (assert_invalid (module (func block (result v128) end)) "SIMD support is not enabled") diff --git a/tests/local/multi-memory.wast b/tests/local/multi-memory.wast index dc4b4755ac..89bc1a92ca 100644 --- a/tests/local/multi-memory.wast +++ b/tests/local/multi-memory.wast @@ -216,7 +216,7 @@ (module quote "(func i32.load $a)" ) - "failed to find memory") + "unknown memory") (module (memory 1) diff --git a/tests/local/order.wast b/tests/local/order.wast index 31bbacd443..721cf41271 100644 --- a/tests/local/order.wast +++ b/tests/local/order.wast @@ -7,6 +7,6 @@ (assert_malformed (module quote "(func)" - "(elem)" + "(elem func)" "(func (import \"\" \"\"))") "import after function") diff --git a/tests/local/producers.wast b/tests/local/producers.wast new file mode 100644 index 0000000000..9e29885ece --- /dev/null +++ b/tests/local/producers.wast @@ -0,0 +1,51 @@ +(module + (@producers) +) + +(module + (@producers + (language "foo" "bar") + ) +) + +(module + (@producers + (language "foo" "bar") + (language "foo" "bar") + (sdk "foo" "bar") + (processed-by "foo" "bar") + ) +) + +(module + (@producers) + (@producers (sdk "foo" "bar")) +) + +(assert_invalid + (module quote "(@producers (foo))") + "unexpected token") + + +;; invalid is ok +(module binary + "\00asm" "\01\00\00\00" + + "\00" ;; custom + "\0b" ;; length + "\09producers" ;; custom section name + "\01" ;; 1 entry +) + +;; weird name +(module binary + "\00asm" "\01\00\00\00" + + "\00" ;; custom + "\14" ;; length + "\09producers" ;; custom section name + "\01" ;; 1 entry + "\03a\na" ;; name = "a\na" + "\01" ;; 1 field + "\01a\01a" ;; value = "a" version = "a" +) diff --git a/tests/local/relaxed-simd.wast b/tests/local/relaxed-simd.wast index 35cfbfcfbe..71764bc8f8 100644 --- a/tests/local/relaxed-simd.wast +++ b/tests/local/relaxed-simd.wast @@ -25,49 +25,49 @@ local.get 0 local.get 1 local.get 2 - f32x4.fma) + f32x4.relaxed_madd) - (func $f32x4_fms (param v128 v128 v128) (result v128) + (func $f32x4_fnma (param v128 v128 v128) (result v128) local.get 0 local.get 1 local.get 2 - f32x4.fms) + f32x4.relaxed_nmadd) (func $f64x2_fma (param v128 v128 v128) (result v128) local.get 0 local.get 1 local.get 2 - f64x2.fma) + f64x2.relaxed_madd) - (func $f64x2_fms (param v128 v128 v128) (result v128) + (func $f64x2_fnma (param v128 v128 v128) (result v128) local.get 0 local.get 1 local.get 2 - f64x2.fms) + f64x2.relaxed_nmadd) (func $i8x16_laneselect (param v128 v128 v128) (result v128) local.get 0 local.get 1 local.get 2 - i8x16.laneselect) + i8x16.relaxed_laneselect) (func $i16x8_laneselect (param v128 v128 v128) (result v128) local.get 0 local.get 1 local.get 2 - i16x8.laneselect) + i16x8.relaxed_laneselect) (func $i32x4_laneselect (param v128 v128 v128) (result v128) local.get 0 local.get 1 local.get 2 - i32x4.laneselect) + i32x4.relaxed_laneselect) (func $i64x2_laneselect (param v128 v128 v128) (result v128) local.get 0 local.get 1 local.get 2 - i64x2.laneselect) + i64x2.relaxed_laneselect) (func $f32x4_min (param v128 v128) (result v128) local.get 0 @@ -88,4 +88,20 @@ local.get 0 local.get 1 f64x2.relaxed_max) + + (func $i16x8_q15mulr_s (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.relaxed_q15mulr_s) + + (func $i16x8_dot_i8x16_i7x16_s (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.relaxed_dot_i8x16_i7x16_s) + + (func $i32x4_dot_i8x16_i7x16_add_s (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_dot_i8x16_i7x16_add_s) ) diff --git a/tests/local/select-interesting.wat b/tests/local/select-interesting.wat new file mode 100644 index 0000000000..f037182670 --- /dev/null +++ b/tests/local/select-interesting.wat @@ -0,0 +1,2 @@ +(func (result i32) unreachable select (result i32) (result)) +(func (result i32) unreachable select (result i32) (result) select) diff --git a/tests/local/table-funcref.wast b/tests/local/table-funcref.wast index ca39e89c23..f523db7966 100644 --- a/tests/local/table-funcref.wast +++ b/tests/local/table-funcref.wast @@ -7,5 +7,5 @@ ) (table (;0;) 1 externref) ) - "indirect calls must go through a table of funcref" + "indirect calls must go through a table with type <= funcref" ) diff --git a/tests/local/table-opt-idx.wat b/tests/local/table-opt-idx.wat index 22b66f56ba..51739b02c5 100644 --- a/tests/local/table-opt-idx.wat +++ b/tests/local/table-opt-idx.wat @@ -1,7 +1,7 @@ (; table indices are optional for backwards compatibility ;) (module (table 1 funcref) - (elem $a $f) + (elem $a func $f) (func $f) (func i32.const 0 diff --git a/tests/local/threads.wast b/tests/local/threads.wast new file mode 100644 index 0000000000..211ee5919f --- /dev/null +++ b/tests/local/threads.wast @@ -0,0 +1,9 @@ +(assert_invalid + (module + (memory 1) + (func (param i32) (result i32) + local.get 0 + i32.atomic.load align=1 + ) + ) + "must always specify maximum alignment") diff --git a/tests/local/try.wast b/tests/local/try.wast index bc4a93d650..e4ffa23d48 100644 --- a/tests/local/try.wast +++ b/tests/local/try.wast @@ -52,4 +52,4 @@ (module quote "(func (try $l (do) (delegate $l)))" ) - "failed to find label") + "unknown label") diff --git a/tests/local/upstream-threads/LB.wast b/tests/local/upstream-threads/LB.wast new file mode 100644 index 0000000000..dc5af8530d --- /dev/null +++ b/tests/local/upstream-threads/LB.wast @@ -0,0 +1,62 @@ +(module $Mem + (memory (export "shared") 1 1 shared) +) + +(thread $T1 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 10 shared) + (func (export "run") + (local i32) + (i32.load (i32.const 4)) + (local.set 0) + (i32.store (i32.const 0) (i32.const 1)) + + ;; store results for checking + (i32.store (i32.const 24) (local.get 0)) + ) + ) + (invoke "run") +) + +(thread $T2 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 1 shared) + (func (export "run") + (local i32) + (i32.load (i32.const 0)) + (local.set 0) + (i32.store (i32.const 4) (i32.const 1)) + + ;; store results for checking + (i32.store (i32.const 32) (local.get 0)) + ) + ) + + (invoke "run") +) + +(wait $T1) +(wait $T2) + +(module $Check + (memory (import "mem" "shared") 1 1 shared) + + (func (export "check") (result i32) + (local i32 i32) + (i32.load (i32.const 24)) + (local.set 0) + (i32.load (i32.const 32)) + (local.set 1) + + ;; allowed results: (L_0 = 0 || L_0 = 1) && (L_1 = 0 || L_1 = 1) + + (i32.or (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 0) (i32.const 0))) + (i32.or (i32.eq (local.get 1) (i32.const 1)) (i32.eq (local.get 0) (i32.const 0))) + (i32.and) + (return) + ) +) + +(assert_return (invoke $Check "check") (i32.const 1)) diff --git a/tests/local/upstream-threads/LB_atomic.wast b/tests/local/upstream-threads/LB_atomic.wast new file mode 100644 index 0000000000..79642713a4 --- /dev/null +++ b/tests/local/upstream-threads/LB_atomic.wast @@ -0,0 +1,64 @@ +(module $Mem + (memory (export "shared") 1 1 shared) +) + +(thread $T1 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 10 shared) + (func (export "run") + (local i32) + (i32.atomic.load (i32.const 4)) + (local.set 0) + (i32.atomic.store (i32.const 0) (i32.const 1)) + + ;; store results for checking + (i32.store (i32.const 24) (local.get 0)) + ) + ) + (invoke "run") +) + +(thread $T2 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 1 shared) + (func (export "run") + (local i32) + (i32.atomic.load (i32.const 0)) + (local.set 0) + (i32.atomic.store (i32.const 4) (i32.const 1)) + + ;; store results for checking + (i32.store (i32.const 32) (local.get 0)) + ) + ) + + (invoke "run") +) + +(wait $T1) +(wait $T2) + +(module $Check + (memory (import "mem" "shared") 1 1 shared) + + (func (export "check") (result i32) + (local i32 i32) + (i32.load (i32.const 24)) + (local.set 0) + (i32.load (i32.const 32)) + (local.set 1) + + ;; allowed results: (L_0 = 0 && L_1 = 0) || (L_0 = 0 && L_1 = 1) || (L_0 = 1 && L_1 = 0) + + (i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 0))) + (i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 1))) + (i32.and (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 1) (i32.const 0))) + (i32.or) + (i32.or) + (return) + ) +) + +(assert_return (invoke $Check "check") (i32.const 1)) diff --git a/tests/local/upstream-threads/MP.wast b/tests/local/upstream-threads/MP.wast new file mode 100644 index 0000000000..e14508596f --- /dev/null +++ b/tests/local/upstream-threads/MP.wast @@ -0,0 +1,59 @@ +(module $Mem + (memory (export "shared") 1 1 shared) +) + +(thread $T1 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 10 shared) + (func (export "run") + (i32.store (i32.const 0) (i32.const 42)) + (i32.store (i32.const 4) (i32.const 1)) + ) + ) + (invoke "run") +) + +(thread $T2 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 1 shared) + (func (export "run") + (local i32 i32) + (i32.load (i32.const 4)) + (local.set 0) + (i32.load (i32.const 0)) + (local.set 1) + + ;; store results for checking + (i32.store (i32.const 24) (local.get 0)) + (i32.store (i32.const 32) (local.get 1)) + ) + ) + + (invoke "run") +) + +(wait $T1) +(wait $T2) + +(module $Check + (memory (import "mem" "shared") 1 1 shared) + + (func (export "check") (result i32) + (local i32 i32) + (i32.load (i32.const 24)) + (local.set 0) + (i32.load (i32.const 32)) + (local.set 1) + + ;; allowed results: (L_0 = 0 || L_0 = 1) && (L_1 = 0 || L_1 = 42) + + (i32.or (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 0) (i32.const 0))) + (i32.or (i32.eq (local.get 1) (i32.const 42)) (i32.eq (local.get 0) (i32.const 0))) + (i32.and) + (return) + ) +) + +(assert_return (invoke $Check "check") (i32.const 1)) diff --git a/tests/local/upstream-threads/MP_atomic.wast b/tests/local/upstream-threads/MP_atomic.wast new file mode 100644 index 0000000000..2001634a22 --- /dev/null +++ b/tests/local/upstream-threads/MP_atomic.wast @@ -0,0 +1,61 @@ +(module $Mem + (memory (export "shared") 1 1 shared) +) + +(thread $T1 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 10 shared) + (func (export "run") + (i32.atomic.store (i32.const 0) (i32.const 42)) + (i32.atomic.store (i32.const 4) (i32.const 1)) + ) + ) + (invoke "run") +) + +(thread $T2 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 1 shared) + (func (export "run") + (local i32 i32) + (i32.atomic.load (i32.const 4)) + (local.set 0) + (i32.atomic.load (i32.const 0)) + (local.set 1) + + ;; store results for checking + (i32.store (i32.const 24) (local.get 0)) + (i32.store (i32.const 32) (local.get 1)) + ) + ) + + (invoke "run") +) + +(wait $T1) +(wait $T2) + +(module $Check + (memory (import "mem" "shared") 1 1 shared) + + (func (export "check") (result i32) + (local i32 i32) + (i32.load (i32.const 24)) + (local.set 0) + (i32.load (i32.const 32)) + (local.set 1) + + ;; allowed results: (L_0 = 1 && L_1 = 42) || (L_0 = 0 && L_1 = 0) || (L_0 = 0 && L_1 = 42) + + (i32.and (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 1) (i32.const 42))) + (i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 0))) + (i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 42))) + (i32.or) + (i32.or) + (return) + ) +) + +(assert_return (invoke $Check "check") (i32.const 1)) diff --git a/tests/local/upstream-threads/MP_wait.wast b/tests/local/upstream-threads/MP_wait.wast new file mode 100644 index 0000000000..2001634a22 --- /dev/null +++ b/tests/local/upstream-threads/MP_wait.wast @@ -0,0 +1,61 @@ +(module $Mem + (memory (export "shared") 1 1 shared) +) + +(thread $T1 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 10 shared) + (func (export "run") + (i32.atomic.store (i32.const 0) (i32.const 42)) + (i32.atomic.store (i32.const 4) (i32.const 1)) + ) + ) + (invoke "run") +) + +(thread $T2 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 1 shared) + (func (export "run") + (local i32 i32) + (i32.atomic.load (i32.const 4)) + (local.set 0) + (i32.atomic.load (i32.const 0)) + (local.set 1) + + ;; store results for checking + (i32.store (i32.const 24) (local.get 0)) + (i32.store (i32.const 32) (local.get 1)) + ) + ) + + (invoke "run") +) + +(wait $T1) +(wait $T2) + +(module $Check + (memory (import "mem" "shared") 1 1 shared) + + (func (export "check") (result i32) + (local i32 i32) + (i32.load (i32.const 24)) + (local.set 0) + (i32.load (i32.const 32)) + (local.set 1) + + ;; allowed results: (L_0 = 1 && L_1 = 42) || (L_0 = 0 && L_1 = 0) || (L_0 = 0 && L_1 = 42) + + (i32.and (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 1) (i32.const 42))) + (i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 0))) + (i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 42))) + (i32.or) + (i32.or) + (return) + ) +) + +(assert_return (invoke $Check "check") (i32.const 1)) diff --git a/tests/local/upstream-threads/SB.wast b/tests/local/upstream-threads/SB.wast new file mode 100644 index 0000000000..65fe7853d8 --- /dev/null +++ b/tests/local/upstream-threads/SB.wast @@ -0,0 +1,62 @@ +(module $Mem + (memory (export "shared") 1 1 shared) +) + +(thread $T1 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 10 shared) + (func (export "run") + (local i32) + (i32.store (i32.const 0) (i32.const 1)) + (i32.load (i32.const 4)) + (local.set 0) + + ;; store results for checking + (i32.store (i32.const 24) (local.get 0)) + ) + ) + (invoke "run") +) + +(thread $T2 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 1 shared) + (func (export "run") + (local i32) + (i32.store (i32.const 4) (i32.const 1)) + (i32.load (i32.const 0)) + (local.set 0) + + ;; store results for checking + (i32.store (i32.const 32) (local.get 0)) + ) + ) + + (invoke "run") +) + +(wait $T1) +(wait $T2) + +(module $Check + (memory (import "mem" "shared") 1 1 shared) + + (func (export "check") (result i32) + (local i32 i32) + (i32.load (i32.const 24)) + (local.set 0) + (i32.load (i32.const 32)) + (local.set 1) + + ;; allowed results: (L_0 = 0 || L_0 = 1) && (L_1 = 0 || L_1 = 1) + + (i32.or (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 0) (i32.const 0))) + (i32.or (i32.eq (local.get 1) (i32.const 1)) (i32.eq (local.get 0) (i32.const 0))) + (i32.and) + (return) + ) +) + +(assert_return (invoke $Check "check") (i32.const 1)) diff --git a/tests/local/upstream-threads/SB_atomic.wast b/tests/local/upstream-threads/SB_atomic.wast new file mode 100644 index 0000000000..3bd8c8a6db --- /dev/null +++ b/tests/local/upstream-threads/SB_atomic.wast @@ -0,0 +1,64 @@ +(module $Mem + (memory (export "shared") 1 1 shared) +) + +(thread $T1 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 10 shared) + (func (export "run") + (local i32) + (i32.atomic.store (i32.const 0) (i32.const 1)) + (i32.atomic.load (i32.const 4)) + (local.set 0) + + ;; store results for checking + (i32.store (i32.const 24) (local.get 0)) + ) + ) + (invoke "run") +) + +(thread $T2 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 1 shared) + (func (export "run") + (local i32) + (i32.atomic.store (i32.const 4) (i32.const 1)) + (i32.atomic.load (i32.const 0)) + (local.set 0) + + ;; store results for checking + (i32.store (i32.const 32) (local.get 0)) + ) + ) + + (invoke "run") +) + +(wait $T1) +(wait $T2) + +(module $Check + (memory (import "mem" "shared") 1 1 shared) + + (func (export "check") (result i32) + (local i32 i32) + (i32.load (i32.const 24)) + (local.set 0) + (i32.load (i32.const 32)) + (local.set 1) + + ;; allowed results: (L_0 = 1 && L_1 = 1) || (L_0 = 0 && L_1 = 1) || (L_0 = 1 && L_1 = 0) + + (i32.and (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 1) (i32.const 1))) + (i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 1))) + (i32.and (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 1) (i32.const 0))) + (i32.or) + (i32.or) + (return) + ) +) + +(assert_return (invoke $Check "check") (i32.const 1)) diff --git a/tests/local/upstream-threads/wait_notify.wast b/tests/local/upstream-threads/wait_notify.wast new file mode 100644 index 0000000000..270509a92d --- /dev/null +++ b/tests/local/upstream-threads/wait_notify.wast @@ -0,0 +1,41 @@ +;; test that looping notify eventually unblocks a parallel waiting thread +(module $Mem + (memory (export "shared") 1 1 shared) +) + +(thread $T1 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 10 shared) + (func (export "run") (result i32) + (memory.atomic.wait32 (i32.const 0) (i32.const 0) (i64.const -1)) + ) + ) + ;; test that this thread eventually gets unblocked + (assert_return (invoke "run") (i32.const 0)) +) + +(thread $T2 (shared (module $Mem)) + (register "mem" $Mem) + (module + (memory (import "mem" "shared") 1 1 shared) + (func (export "notify-0") (result i32) + (memory.atomic.notify (i32.const 0) (i32.const 0)) + ) + (func (export "notify-1-while") + (loop + (i32.const 1) + (memory.atomic.notify (i32.const 0) (i32.const 1)) + (i32.ne) + (br_if 0) + ) + ) + ) + ;; notifying with a count of 0 will not unblock + (assert_return (invoke "notify-0") (i32.const 0)) + ;; loop until something is notified + (assert_return (invoke "notify-1-while")) +) + +(wait $T1) +(wait $T2) diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index 49998d0631..daba84f67a 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -23,7 +23,9 @@ use anyhow::{bail, Context, Result}; use rayon::prelude::*; +use std::io::{Read, Write}; use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; use std::str; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use wasmparser::*; @@ -35,6 +37,10 @@ use wast::{parser, QuoteWat, Wast, WastDirective, Wat}; fn main() { let tests = find_tests(); let filter = std::env::args().nth(1); + let bless = std::env::var_os("BLESS").is_some(); + if bless { + drop(std::fs::remove_dir_all("tests/snapshots")); + } let tests = tests .par_iter() @@ -60,7 +66,14 @@ fn main() { let state = TestState::default(); let errors = tests .par_iter() - .filter_map(|(test, contents)| state.run_test(test, contents).err()) + .filter_map(|(test, contents)| { + let start = std::time::Instant::now(); + let result = state.run_test(test, contents).err(); + if start.elapsed().as_secs() > 2 { + println!("{test:?} SLOW"); + } + result + }) .collect::>(); if !errors.is_empty() { @@ -81,7 +94,12 @@ fn main() { /// then load up and test in parallel. fn find_tests() -> Vec { let mut tests = Vec::new(); - if !Path::new("tests/testsuite").exists() { + let test_suite = Path::new("tests/testsuite"); + if !test_suite.exists() + || std::fs::read_dir(test_suite) + .map(|mut d| d.next().is_none()) + .unwrap_or(true) + { panic!("submodules need to be checked out"); } find_tests("tests/local".as_ref(), &mut tests); @@ -124,21 +142,11 @@ fn skip_test(test: &Path, contents: &[u8]) -> bool { "exception-handling/try_delegate.wast", "exception-handling/try_catch.wast", "exception-handling/throw.wast", - // TODO: The call_ref instructions formats changed: the testsuite needs - // to be updated. Remove local/function-references/call_ref/ as well. - "function-references/br_on_non_null.wast", - "function-references/br_on_null.wast", - "function-references/call_ref.wast", - "function-references/func_bind.wast", - "function-references/ref_as_non_null.wast", - "function-references/return_call_ref.wast", + // This is an empty file which currently doesn't parse + "multi-memory/memory_copy1.wast", ]; - if broken.iter().any(|x| test.ends_with(x)) { - return true; - } - - // TODO: the gc proposal isn't implemented yet - if test.iter().any(|p| p == "gc") { + let test_path = test.to_str().unwrap().replace("\\", "/"); // for windows paths + if broken.iter().any(|x| test_path.contains(x)) { return true; } @@ -157,6 +165,43 @@ fn skip_test(test: &Path, contents: &[u8]) -> bool { false } +fn skip_validation(test: &Path) -> bool { + let broken = &[ + "gc/gc-array.wat", + "gc/gc-rec-sub.wat", + "gc/gc-struct.wat", + "/proposals/gc/array.wast", + "/proposals/gc/array_copy.wast", + "/proposals/gc/array_fill.wast", + "/proposals/gc/array_init_data.wast", + "/proposals/gc/array_init_elem.wast", + "/proposals/gc/binary-gc.wast", + "/proposals/gc/br_on_cast.wast", + "/proposals/gc/br_on_cast_fail.wast", + "/proposals/gc/data.wast", + "/proposals/gc/elem.wast", + "/proposals/gc/extern.wast", + "/proposals/gc/global.wast", + "/proposals/gc/i31.wast", + "/proposals/gc/ref_cast.wast", + "/proposals/gc/ref_eq.wast", + "/proposals/gc/ref_test.wast", + "/proposals/gc/struct.wast", + "/proposals/gc/type-equivalence.wast", + "/proposals/gc/type-rec.wast", + "/proposals/gc/type-subtyping.wast", + "/exnref/exnref.wast", + "/exnref/throw_ref.wast", + "/exnref/try_table.wast", + ]; + let test_path = test.to_str().unwrap().replace("\\", "/"); // for windows paths + if broken.iter().any(|x| test_path.contains(x)) { + return true; + } + + false +} + #[derive(Default)] struct TestState { ntests: AtomicUsize, @@ -177,6 +222,11 @@ impl TestState { // wasm file. let binary = wat::parse_file(test)?; self.bump_ntests(); + + if skip_validation(test) { + return Ok(()); + } + self.test_wasm(test, &binary, true) .context("failed testing the binary output of `wat`")?; Ok(()) @@ -189,6 +239,10 @@ impl TestState { // Test that we can print these bytes. let string = wasmprinter::print_bytes(contents).context("failed to print wasm")?; self.bump_ntests(); + // Snapshot these bytes. + self.snapshot("print", test, &string) + .context("failed to validate the `print` snapshot")?; + self.bump_ntests(); // If we can, convert the string back to bytes and assert it has the // same binary representation. @@ -200,6 +254,36 @@ impl TestState { .context("failed to compare original `wat` with roundtrip `wat`")?; } + // Test that the `wasmprinter`-printed bytes have "pretty" whitespace + // which means that all whitespace is either categorized as leading + // whitespace or a single space. Examples of "bad whitespace" are: + // + // * trailing whitespace at the end of a line + // * two spaces in a row + // + // Both of these cases indicate possible bugs in `wasmprinter` itself + // which while they don't actually affect the meaning they do "affect" + // humans reading the output. + for token in wast::lexer::Lexer::new(&string) + .allow_confusing_unicode(true) + .iter(0) + { + let token = token?; + let ws = match token.kind { + wast::lexer::TokenKind::Whitespace => token.src(&string), + _ => continue, + }; + if ws.starts_with("\n") || ws == " " { + continue; + } + let offset = ws.as_ptr() as usize - string.as_ptr() as usize; + let span = wast::token::Span::from_offset(offset); + let msg = format!("found non-one-length whitespace in `wasmprinter` output: {ws:?}"); + let mut err = wast::Error::new(span, msg); + err.set_text(&string); + return Err(err.into()); + } + Ok(()) } @@ -222,9 +306,10 @@ impl TestState { let errors = wast .directives .into_par_iter() - .filter_map(|directive| { + .enumerate() + .filter_map(|(index, directive)| { let span = directive.span(); - self.test_wast_directive(test, directive) + self.test_wast_directive(test, directive, index) .with_context(|| { let (line, col) = span.linecol_in(contents); format!( @@ -252,18 +337,17 @@ impl TestState { bail!("{}", s) } - fn test_wast_directive(&self, test: &Path, directive: WastDirective) -> Result<()> { - // Only test parsing and encoding of modules which wasmparser doesn't - // support test (basically just test `wast`, nothing else) - let skip_verify = test.iter().any(|t| t == "function-references" || t == "gc"); - + fn test_wast_directive(&self, test: &Path, directive: WastDirective, idx: usize) -> Result<()> { match directive { WastDirective::Wat(mut module) => { let actual = module.encode()?; self.bump_ntests(); // testing encode - if skip_verify { + + if skip_validation(test) { + // Verify that we can parse the wat, but otherwise do nothing. return Ok(()); } + let test_roundtrip = match module { // Don't test the wasmprinter round trip since these bytes // may not be in their canonical form (didn't come from the @@ -275,7 +359,11 @@ impl TestState { _ => true, }; - self.test_wasm(test, &actual, test_roundtrip) + + let mut test_path = test.to_path_buf(); + test_path.push(idx.to_string()); + + self.test_wasm(&test_path, &actual, test_roundtrip) .context("failed testing wasm binary produced by `wast`")?; } @@ -289,6 +377,10 @@ impl TestState { message, span: _, } => { + if skip_validation(test) { + return Ok(()); + } + let result = module.encode().map_err(|e| e.into()).and_then(|wasm| { // TODO: when memory64 merges into the proper spec then this // should be removed since it will presumably no longer be a @@ -310,12 +402,9 @@ impl TestState { self.test_wasm_valid(test, &wasm) }); - if skip_verify { - return Ok(()); - } match result { Ok(_) => bail!( - "parsed successfully but should have failed with: {}", + "encoded and validated successfully but should have failed with: {}", message, ), Err(e) => { @@ -328,6 +417,12 @@ impl TestState { } } + WastDirective::Thread(thread) => { + for (i, directive) in thread.directives.into_iter().enumerate() { + self.test_wast_directive(test, directive, idx * 1000 + i)?; + } + } + // This test suite doesn't actually execute any wasm code, so ignore // all of these assertions. WastDirective::Register { .. } @@ -336,7 +431,8 @@ impl TestState { | WastDirective::AssertReturn { .. } | WastDirective::AssertExhaustion { .. } | WastDirective::AssertUnlinkable { .. } - | WastDirective::AssertException { .. } => {} + | WastDirective::AssertException { .. } + | WastDirective::Wait { .. } => {} } Ok(()) } @@ -347,6 +443,67 @@ impl TestState { Ok(()) } + /// Compare the test result with a snapshot stored in the repository. + /// + /// Works great for tools like wasmprinter for which having a nice overview of what effect the + /// changes cause. + fn snapshot(&self, kind: &str, path: &Path, contents: &str) -> Result<()> { + let contents = contents.replace("\r\n", "\n"); + let bless = std::env::var_os("BLESS").is_some(); + let snapshot_dir = ["tests", "snapshots"] + .into_iter() + .collect::(); + let test_name = path + .iter() + .skip_while(|&c| c != std::ffi::OsStr::new("tests")) + .skip(1) + .collect::(); + let mut snapshot_name = test_name.into_os_string(); + snapshot_name.push("."); + snapshot_name.push(kind); + let snapshot_path = snapshot_dir.join(snapshot_name); + if bless { + std::fs::create_dir_all(snapshot_path.parent().unwrap()).with_context(|| { + format!("could not create the snapshot dir {:?}", snapshot_path) + })?; + std::fs::write(&snapshot_path, contents).with_context(|| { + format!("could not write out the snapshot to {:?}", snapshot_path) + })?; + } else { + let snapshot = std::fs::read(snapshot_path) + .context("could not read the snapshot, try `env BLESS=1`")?; + let snapshot = + std::str::from_utf8(&snapshot).context("can't decode snapshot as utf-8")?; + // Handle git possibly doing some newline shenanigans on windows. + let snapshot = snapshot.replace("\r\n", "\n"); + if snapshot != contents { + let mut result = String::with_capacity(snapshot.len()); + for diff in diff::lines(&snapshot, &contents) { + match diff { + diff::Result::Left(s) => { + result.push_str("-"); + result.push_str(s); + } + diff::Result::Right(s) => { + result.push_str("+"); + result.push_str(s); + } + diff::Result::Both(s, _) => { + result.push_str(" "); + result.push_str(s); + } + } + result.push_str("\n"); + } + anyhow::bail!( + "snapshot does not match the expected result, try `env BLESS=1`\n{}", + result + ); + } + } + Ok(()) + } + /// Compare the `actual` and `expected`, asserting that they are the same. /// /// If they are not equal this attempts to produce as nice of an error @@ -375,8 +532,8 @@ impl TestState { msg.push_str(&format!(" | + {:#04x}\n", actual[pos])); } - if let Ok(actual) = wasmparser_dump::dump_wasm(&actual) { - if let Ok(expected) = wasmparser_dump::dump_wasm(&expected) { + if let Ok(actual) = self.dump(&actual) { + if let Ok(expected) = self.dump(&expected) { let mut actual = actual.lines(); let mut expected = expected.lines(); let mut differences = 0; @@ -413,6 +570,21 @@ impl TestState { bail!("{}", msg); } + fn dump(&self, bytes: &[u8]) -> Result { + let mut dump = Command::new(env!("CARGO_BIN_EXE_wasm-tools")) + .arg("dump") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + dump.stdin.take().unwrap().write_all(bytes)?; + let mut stdout = String::new(); + dump.stdout.take().unwrap().read_to_string(&mut stdout)?; + if dump.wait()?.success() { + bail!("dump subcommand failed"); + } + Ok(stdout) + } + fn wasmparser_validator_for(&self, test: &Path) -> Validator { let mut features = WasmFeatures { threads: true, @@ -423,7 +595,7 @@ impl TestState { bulk_memory: true, tail_call: true, component_model: false, - deterministic_only: false, + floats: true, multi_value: true, multi_memory: true, memory64: true, @@ -431,10 +603,23 @@ impl TestState { saturating_float_to_int: true, sign_extension: true, mutable_global: true, + function_references: true, + memory_control: true, + gc: true, + component_model_values: true, }; for part in test.iter().filter_map(|t| t.to_str()) { match part { - "testsuite" => features = WasmFeatures::default(), + "testsuite" => { + features = WasmFeatures::default(); + + // NB: when these proposals are merged upstream in the spec + // repo then this should be removed. Currently this hasn't + // happened so this is required to get tests passing for + // when these proposals are enabled by default. + features.multi_memory = false; + features.threads = false; + } "missing-features" => { features = WasmFeatures::default(); features.simd = false; @@ -444,7 +629,11 @@ impl TestState { features.saturating_float_to_int = false; features.mutable_global = false; features.bulk_memory = false; + features.function_references = false; + features.gc = false; + features.component_model_values = false; } + "floats-disabled.wast" => features.floats = false, "threads" => { features.threads = true; features.bulk_memory = false; @@ -460,6 +649,13 @@ impl TestState { "component-model" => features.component_model = true, "multi-memory" => features.multi_memory = true, "extended-const" => features.extended_const = true, + "function-references" => features.function_references = true, + "relaxed-simd" => features.relaxed_simd = true, + "reference-types" => features.reference_types = true, + "gc" => { + features.function_references = true; + features.gc = true; + } _ => {} } } @@ -570,10 +766,16 @@ fn error_matches(error: &str, message: &str) -> bool { // section counts/lengths. if message == "length out of bounds" || message == "unexpected end of section or function" { return error.contains("unexpected end-of-file") - || error.contains("control frames remain at end of function"); + || error.contains("control frames remain at end of function") + // This is the same case as "unexpected end" (below) but in + // function-references fsr it includes "of section or function" + || error.contains("type index out of bounds"); } - // this feels like a busted test in the spec suite + // binary.wast includes a test in which a 0b (End) is eaten by a botched + // br_table. The test assumes that the parser (not the validator) errors on + // a missing End before failing to validate the botched instruction. However + // wasmparser fails to validate the botched instruction first if message == "unexpected end" { return error.contains("type index out of bounds"); } @@ -602,5 +804,30 @@ fn error_matches(error: &str, message: &str) -> bool { return error.contains("invalid u32 number: constant out of range"); } + if message == "illegal opcode" { + // The test suite includes "bad opcodes" that later became valid opcodes + // (0xd4, function references proposal). However, they are still not + // constant expressions, so we can sidestep by checking for that error + // instead + return error.contains("constant expression required") + // The test suite contains a test with a global section where the + // init expression is truncated and doesn't have an "end" + // instruction. That's reported with wasmparser as end-of-file + // because the end of the section was reached while the spec + // interpreter says "illegal opcode". + || error.contains("unexpected end-of-file"); + } + if message == "unknown global" { + return error.contains("global.get of locally defined global"); + } + + if message == "immutable global" { + return error.contains("global is immutable"); + } + + if message == "sub type" { + return error.contains("subtype"); + } + return false; } diff --git a/tests/snapshots/local/anyref1.wat.print b/tests/snapshots/local/anyref1.wat.print new file mode 100644 index 0000000000..46336354aa --- /dev/null +++ b/tests/snapshots/local/anyref1.wat.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + table.init 0 + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) 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)) +) \ No newline at end of file diff --git a/tests/snapshots/local/atomics.wast/0.print b/tests/snapshots/local/atomics.wast/0.print new file mode 100644 index 0000000000..3f1a84ad2b --- /dev/null +++ b/tests/snapshots/local/atomics.wast/0.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + atomic.fence + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/atomics.wast/1.print b/tests/snapshots/local/atomics.wast/1.print new file mode 100644 index 0000000000..70b7bed77c --- /dev/null +++ b/tests/snapshots/local/atomics.wast/1.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.const 0 + memory.atomic.notify + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/local/block-w-params-unreachable.wat.print b/tests/snapshots/local/block-w-params-unreachable.wat.print new file mode 100644 index 0000000000..a63e9bdd1b --- /dev/null +++ b/tests/snapshots/local/block-w-params-unreachable.wat.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (param i32 i32))) + (func (;0;) (type 0) (param i32 i32) + unreachable + local.get 1 + loop (type 0) (param i32 i32) ;; label = @1 + loop (type 0) (param i32 i32) ;; label = @2 + call 0 + end + end + unreachable + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/blockty.wat.print b/tests/snapshots/local/blockty.wat.print new file mode 100644 index 0000000000..1dc0903651 --- /dev/null +++ b/tests/snapshots/local/blockty.wat.print @@ -0,0 +1,139 @@ +(module + (type (;0;) (func (param f32 f32 f32 f32 f32 f32))) + (type (;1;) (func (param i32 f32 f32 f32 f32 f32))) + (type (;2;) (func (param f32 i32 f32 f32 f32 f32))) + (type (;3;) (func (param i32 i32 f32 f32 f32 f32))) + (type (;4;) (func (param f32 f32 i32 f32 f32 f32))) + (type (;5;) (func (param i32 f32 i32 f32 f32 f32))) + (type (;6;) (func (param f32 i32 i32 f32 f32 f32))) + (type (;7;) (func (param i32 i32 i32 f32 f32 f32))) + (type (;8;) (func (param f32 f32 f32 i32 f32 f32))) + (type (;9;) (func (param i32 f32 f32 i32 f32 f32))) + (type (;10;) (func (param f32 i32 f32 i32 f32 f32))) + (type (;11;) (func (param i32 i32 f32 i32 f32 f32))) + (type (;12;) (func (param f32 f32 i32 i32 f32 f32))) + (type (;13;) (func (param i32 f32 i32 i32 f32 f32))) + (type (;14;) (func (param f32 i32 i32 i32 f32 f32))) + (type (;15;) (func (param i32 i32 i32 i32 f32 f32))) + (type (;16;) (func (param f32 f32 f32 f32 i32 f32))) + (type (;17;) (func (param i32 f32 f32 f32 i32 f32))) + (type (;18;) (func (param f32 i32 f32 f32 i32 f32))) + (type (;19;) (func (param i32 i32 f32 f32 i32 f32))) + (type (;20;) (func (param f32 f32 i32 f32 i32 f32))) + (type (;21;) (func (param i32 f32 i32 f32 i32 f32))) + (type (;22;) (func (param f32 i32 i32 f32 i32 f32))) + (type (;23;) (func (param i32 i32 i32 f32 i32 f32))) + (type (;24;) (func (param f32 f32 f32 i32 i32 f32))) + (type (;25;) (func (param i32 f32 f32 i32 i32 f32))) + (type (;26;) (func (param f32 i32 f32 i32 i32 f32))) + (type (;27;) (func (param i32 i32 f32 i32 i32 f32))) + (type (;28;) (func (param f32 f32 i32 i32 i32 f32))) + (type (;29;) (func (param i32 f32 i32 i32 i32 f32))) + (type (;30;) (func (param f32 i32 i32 i32 i32 f32))) + (type (;31;) (func (param i32 i32 i32 i32 i32 f32))) + (type (;32;) (func (param f32 f32 f32 f32 f32 i32))) + (type (;33;) (func (param i32 f32 f32 f32 f32 i32))) + (type (;34;) (func (param f32 i32 f32 f32 f32 i32))) + (type (;35;) (func (param i32 i32 f32 f32 f32 i32))) + (type (;36;) (func (param f32 f32 i32 f32 f32 i32))) + (type (;37;) (func (param i32 f32 i32 f32 f32 i32))) + (type (;38;) (func (param f32 i32 i32 f32 f32 i32))) + (type (;39;) (func (param i32 i32 i32 f32 f32 i32))) + (type (;40;) (func (param f32 f32 f32 i32 f32 i32))) + (type (;41;) (func (param i32 f32 f32 i32 f32 i32))) + (type (;42;) (func (param f32 i32 f32 i32 f32 i32))) + (type (;43;) (func (param i32 i32 f32 i32 f32 i32))) + (type (;44;) (func (param f32 f32 i32 i32 f32 i32))) + (type (;45;) (func (param i32 f32 i32 i32 f32 i32))) + (type (;46;) (func (param f32 i32 i32 i32 f32 i32))) + (type (;47;) (func (param i32 i32 i32 i32 f32 i32))) + (type (;48;) (func (param f32 f32 f32 f32 i32 i32))) + (type (;49;) (func (param i32 f32 f32 f32 i32 i32))) + (type (;50;) (func (param f32 i32 f32 f32 i32 i32))) + (type (;51;) (func (param i32 i32 f32 f32 i32 i32))) + (type (;52;) (func (param f32 f32 i32 f32 i32 i32))) + (type (;53;) (func (param i32 f32 i32 f32 i32 i32))) + (type (;54;) (func (param f32 i32 i32 f32 i32 i32))) + (type (;55;) (func (param i32 i32 i32 f32 i32 i32))) + (type (;56;) (func (param f32 f32 f32 i32 i32 i32))) + (type (;57;) (func (param i32 f32 f32 i32 i32 i32))) + (type (;58;) (func (param f32 i32 f32 i32 i32 i32))) + (type (;59;) (func (param i32 i32 f32 i32 i32 i32))) + (type (;60;) (func (param f32 f32 i32 i32 i32 i32))) + (type (;61;) (func (param i32 f32 i32 i32 i32 i32))) + (type (;62;) (func (param f32 i32 i32 i32 i32 i32))) + (type (;63;) (func (param i32 i32 i32 i32 i32 i32))) + (type (;64;) (func (result i32))) + (type (;65;) (func (result i32 i32))) + (func (;0;) (type 0) (param f32 f32 f32 f32 f32 f32)) + (func (;1;) (type 1) (param i32 f32 f32 f32 f32 f32)) + (func (;2;) (type 2) (param f32 i32 f32 f32 f32 f32)) + (func (;3;) (type 3) (param i32 i32 f32 f32 f32 f32)) + (func (;4;) (type 4) (param f32 f32 i32 f32 f32 f32)) + (func (;5;) (type 5) (param i32 f32 i32 f32 f32 f32)) + (func (;6;) (type 6) (param f32 i32 i32 f32 f32 f32)) + (func (;7;) (type 7) (param i32 i32 i32 f32 f32 f32)) + (func (;8;) (type 8) (param f32 f32 f32 i32 f32 f32)) + (func (;9;) (type 9) (param i32 f32 f32 i32 f32 f32)) + (func (;10;) (type 10) (param f32 i32 f32 i32 f32 f32)) + (func (;11;) (type 11) (param i32 i32 f32 i32 f32 f32)) + (func (;12;) (type 12) (param f32 f32 i32 i32 f32 f32)) + (func (;13;) (type 13) (param i32 f32 i32 i32 f32 f32)) + (func (;14;) (type 14) (param f32 i32 i32 i32 f32 f32)) + (func (;15;) (type 15) (param i32 i32 i32 i32 f32 f32)) + (func (;16;) (type 16) (param f32 f32 f32 f32 i32 f32)) + (func (;17;) (type 17) (param i32 f32 f32 f32 i32 f32)) + (func (;18;) (type 18) (param f32 i32 f32 f32 i32 f32)) + (func (;19;) (type 19) (param i32 i32 f32 f32 i32 f32)) + (func (;20;) (type 20) (param f32 f32 i32 f32 i32 f32)) + (func (;21;) (type 21) (param i32 f32 i32 f32 i32 f32)) + (func (;22;) (type 22) (param f32 i32 i32 f32 i32 f32)) + (func (;23;) (type 23) (param i32 i32 i32 f32 i32 f32)) + (func (;24;) (type 24) (param f32 f32 f32 i32 i32 f32)) + (func (;25;) (type 25) (param i32 f32 f32 i32 i32 f32)) + (func (;26;) (type 26) (param f32 i32 f32 i32 i32 f32)) + (func (;27;) (type 27) (param i32 i32 f32 i32 i32 f32)) + (func (;28;) (type 28) (param f32 f32 i32 i32 i32 f32)) + (func (;29;) (type 29) (param i32 f32 i32 i32 i32 f32)) + (func (;30;) (type 30) (param f32 i32 i32 i32 i32 f32)) + (func (;31;) (type 31) (param i32 i32 i32 i32 i32 f32)) + (func (;32;) (type 32) (param f32 f32 f32 f32 f32 i32)) + (func (;33;) (type 33) (param i32 f32 f32 f32 f32 i32)) + (func (;34;) (type 34) (param f32 i32 f32 f32 f32 i32)) + (func (;35;) (type 35) (param i32 i32 f32 f32 f32 i32)) + (func (;36;) (type 36) (param f32 f32 i32 f32 f32 i32)) + (func (;37;) (type 37) (param i32 f32 i32 f32 f32 i32)) + (func (;38;) (type 38) (param f32 i32 i32 f32 f32 i32)) + (func (;39;) (type 39) (param i32 i32 i32 f32 f32 i32)) + (func (;40;) (type 40) (param f32 f32 f32 i32 f32 i32)) + (func (;41;) (type 41) (param i32 f32 f32 i32 f32 i32)) + (func (;42;) (type 42) (param f32 i32 f32 i32 f32 i32)) + (func (;43;) (type 43) (param i32 i32 f32 i32 f32 i32)) + (func (;44;) (type 44) (param f32 f32 i32 i32 f32 i32)) + (func (;45;) (type 45) (param i32 f32 i32 i32 f32 i32)) + (func (;46;) (type 46) (param f32 i32 i32 i32 f32 i32)) + (func (;47;) (type 47) (param i32 i32 i32 i32 f32 i32)) + (func (;48;) (type 48) (param f32 f32 f32 f32 i32 i32)) + (func (;49;) (type 49) (param i32 f32 f32 f32 i32 i32)) + (func (;50;) (type 50) (param f32 i32 f32 f32 i32 i32)) + (func (;51;) (type 51) (param i32 i32 f32 f32 i32 i32)) + (func (;52;) (type 52) (param f32 f32 i32 f32 i32 i32)) + (func (;53;) (type 53) (param i32 f32 i32 f32 i32 i32)) + (func (;54;) (type 54) (param f32 i32 i32 f32 i32 i32)) + (func (;55;) (type 55) (param i32 i32 i32 f32 i32 i32)) + (func (;56;) (type 56) (param f32 f32 f32 i32 i32 i32)) + (func (;57;) (type 57) (param i32 f32 f32 i32 i32 i32)) + (func (;58;) (type 58) (param f32 i32 f32 i32 i32 i32)) + (func (;59;) (type 59) (param i32 i32 f32 i32 i32 i32)) + (func (;60;) (type 60) (param f32 f32 i32 i32 i32 i32)) + (func (;61;) (type 61) (param i32 f32 i32 i32 i32 i32)) + (func (;62;) (type 62) (param f32 i32 i32 i32 i32 i32)) + (func (;63;) (type 63) (param i32 i32 i32 i32 i32 i32)) + (func (;64;) (type 64) (result i32) + block (type 65) (result i32 i32) ;; label = @1 + i32.const 32 + i32.const 10 + end + i32.add + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/br_if-loop-stack.wat.print b/tests/snapshots/local/br_if-loop-stack.wat.print new file mode 100644 index 0000000000..52d359a5b4 --- /dev/null +++ b/tests/snapshots/local/br_if-loop-stack.wat.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func (result i32))) + (func $main (;0;) (type 0) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 77 + i32.const 0 + br_if 0 (;@2;) + br 1 (;@1;) + end + end + ) + (export "main" (func $main)) +) \ No newline at end of file diff --git a/tests/snapshots/local/br_if-loop-unreachable.wat.print b/tests/snapshots/local/br_if-loop-unreachable.wat.print new file mode 100644 index 0000000000..490c3983da --- /dev/null +++ b/tests/snapshots/local/br_if-loop-unreachable.wat.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result f64 i32))) + (func (;0;) (type 1) (result f64 i32) + loop (type 1) (result f64 i32) ;; label = @1 + br 0 (;@1;) + call 0 + br_if 0 (;@1;) + i32.trunc_f64_u + unreachable + end + unreachable + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/br_table_loop_multi.wat.print b/tests/snapshots/local/br_table_loop_multi.wat.print new file mode 100644 index 0000000000..0ae6f9c7de --- /dev/null +++ b/tests/snapshots/local/br_table_loop_multi.wat.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param i32) (result i32) + (local i32) + local.get 1 + loop (type 1) (param i32) ;; label = @1 + i32.const -458751 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + unreachable + end + unreachable + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/comments.wat.print b/tests/snapshots/local/comments.wat.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/local/comments.wat.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/a.wast/0.print b/tests/snapshots/local/component-model/a.wast/0.print new file mode 100644 index 0000000000..4717804eeb --- /dev/null +++ b/tests/snapshots/local/component-model/a.wast/0.print @@ -0,0 +1,25 @@ +(component + (type (;0;) (func)) + (import "one" (func (;0;) (type 0))) + (import "two" (value $v (;0;) string)) + (type (;1;) + (instance + (type (;0;) + (instance + (core type (;0;) + (module + (type (;0;) (func)) + (import "six" "a" (func (type 0))) + (type (;1;) (func)) + (import "six" "b" (func (type 1))) + ) + ) + (export (;0;) "five" (core module (type 0))) + ) + ) + (export (;0;) "four" (instance (type 0))) + ) + ) + (import "three" (instance (;0;) (type 1))) + (export (;1;) "four" (value $v)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/adapt.wast/0.print b/tests/snapshots/local/component-model/adapt.wast/0.print new file mode 100644 index 0000000000..56534a7989 --- /dev/null +++ b/tests/snapshots/local/component-model/adapt.wast/0.print @@ -0,0 +1,65 @@ +(component + (type (;0;) (func (param "msg" string))) + (import "log" (func $log (;0;) (type 0))) + (core module $libc (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "canonical_abi_realloc" (func 0)) + ) + (core module $my_module (;1;) + (type (;0;) (func (param i32 i32))) + (import "env" "log-utf8" (func $log_utf8 (;0;) (type 0))) + (import "env" "log-utf16" (func $log_utf16 (;1;) (type 0))) + (import "env" "log-compact-utf16" (func $log_compact_utf16 (;2;) (type 0))) + (func (;3;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + call $log_utf8 + ) + (func (;4;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + call $log_utf16 + ) + (func (;5;) (type 0) (param i32 i32) + local.get 0 + local.get 1 + call $log_compact_utf16 + ) + (export "log-utf8" (func 3)) + (export "log-utf16" (func 4)) + (export "log-compact-utf16" (func 5)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "canonical_abi_realloc" (core func $realloc (;0;))) + (alias core export $libc "memory" (core memory $memory (;0;))) + (core func $log_lower_utf8 (;1;) (canon lower (func $log) string-encoding=utf8 (memory $memory) (realloc $realloc))) + (core func $log_lower_utf16 (;2;) (canon lower (func $log) string-encoding=utf16 (memory $memory) (realloc $realloc))) + (core func $log_lower_compact_utf16 (;3;) (canon lower (func $log) string-encoding=latin1+utf16 (memory $memory) (realloc $realloc))) + (core instance (;1;) + (export "log-utf8" (func $log_lower_utf8)) + (export "log-utf16" (func $log_lower_utf16)) + (export "log-compact-utf16" (func $log_lower_compact_utf16)) + ) + (core instance $my_instance (;2;) (instantiate $my_module + (with "libc" (instance $libc)) + (with "env" (instance 1)) + ) + ) + (type (;1;) (func (param "msg" string))) + (alias core export $my_instance "log-utf8" (core func (;4;))) + (func (;1;) (type 1) (canon lift (core func 4) string-encoding=utf8 (memory $memory) (realloc $realloc))) + (type (;2;) (func (param "msg" string))) + (alias core export $my_instance "log-utf16" (core func (;5;))) + (func (;2;) (type 2) (canon lift (core func 5) string-encoding=utf16 (memory $memory) (realloc $realloc))) + (type (;3;) (func (param "msg" string))) + (alias core export $my_instance "log-compact-utf16" (core func (;6;))) + (func (;3;) (type 3) (canon lift (core func 6) string-encoding=latin1+utf16 (memory $memory) (realloc $realloc))) + (export (;4;) "log1" (func 1)) + (export (;5;) "log2" (func 2)) + (export (;6;) "log3" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/adapt.wast/13.print b/tests/snapshots/local/component-model/adapt.wast/13.print new file mode 100644 index 0000000000..ee9c6d0a10 --- /dev/null +++ b/tests/snapshots/local/component-model/adapt.wast/13.print @@ -0,0 +1,26 @@ +(component + (core module $m (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (type (;2;) (func (param i32))) + (func (;0;) (type 0) (result i32) + unreachable + ) + (func (;1;) (type 1) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (func (;2;) (type 2) (param i32)) + (memory (;0;) 1) + (export "m" (memory 0)) + (export "f" (func 0)) + (export "r" (func 1)) + (export "p" (func 2)) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;0;) (func (result string))) + (alias core export $i "f" (core func (;0;))) + (alias core export $i "m" (core memory (;0;))) + (alias core export $i "r" (core func (;1;))) + (alias core export $i "p" (core func (;2;))) + (func (;0;) (type 0) (canon lift (core func 0) (memory 0) (realloc 1) (post-return 2))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/0.print b/tests/snapshots/local/component-model/alias.wast/0.print new file mode 100644 index 0000000000..c7d1632ed0 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/0.print @@ -0,0 +1,13 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "f1" (func (type 0))) + (type (;1;) (func (param "p1" string))) + (export (;1;) "f2" (func (type 1))) + ) + ) + (import "i" (instance $i (;0;) (type 0))) + (alias export $i "f1" (func (;0;))) + (export (;1;) "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/1.print b/tests/snapshots/local/component-model/alias.wast/1.print new file mode 100644 index 0000000000..cf467f5421 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/1.print @@ -0,0 +1,14 @@ +(component + (type (;0;) + (component + (type (;0;) (func)) + (export (;0;) "f1" (func (type 0))) + (type (;1;) (func (param "p1" string))) + (export (;1;) "f2" (func (type 1))) + ) + ) + (import "i" (component $c (;0;) (type 0))) + (instance $i (;0;) (instantiate $c)) + (alias export $i "f1" (func (;0;))) + (export (;1;) "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/12.print b/tests/snapshots/local/component-model/alias.wast/12.print new file mode 100644 index 0000000000..5493ba6a74 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/12.print @@ -0,0 +1,12 @@ +(component $PARENT + (type $t (;0;) (func (result string))) + (component (;0;) + (alias outer $PARENT $t (type $t (;0;))) + (import "a" (func (;0;) (type $t))) + ) + (component (;1;) + (alias outer $PARENT $t (type $my_type (;0;))) + (alias outer 0 $my_type (type $my_type_again (;1;))) + (import "a" (func (;0;) (type $my_type_again))) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/13.print b/tests/snapshots/local/component-model/alias.wast/13.print new file mode 100644 index 0000000000..93081466b8 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/13.print @@ -0,0 +1,34 @@ +(component + (type $a (;0;) (func (result string))) + (component (;0;) + (type $b (;0;) (func (result u32))) + (component (;0;) + (type $c (;0;) (func (result s32))) + (component (;0;) + (alias outer 3 $a (type $a (;0;))) + (import "a" (func $a (;0;) (type $a))) + (alias outer 2 $b (type $b (;1;))) + (import "b" (func $b (;1;) (type $b))) + (alias outer 1 $c (type $c (;2;))) + (import "c" (func $c (;2;) (type $c))) + (type (;3;) + (component + (type (;0;) (func (result string))) + (import "a" (func (;0;) (type 0))) + (type (;1;) (func (result u32))) + (import "b" (func (;1;) (type 1))) + (type (;2;) (func (result s32))) + (import "c" (func (;2;) (type 2))) + ) + ) + (import "d" (component $C (;0;) (type 3))) + (instance (;0;) (instantiate $C + (with "a" (func $a)) + (with "b" (func $b)) + (with "c" (func $c)) + ) + ) + ) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/14.print b/tests/snapshots/local/component-model/alias.wast/14.print new file mode 100644 index 0000000000..bad29a2581 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/14.print @@ -0,0 +1,39 @@ +(component $a + (type (;0;) + (instance + (type (;0;) + (instance + (type (;0;) + (instance + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + ) + ) + (export (;0;) "a" (instance (type 0))) + ) + ) + (export (;0;) "a" (instance (type 0))) + ) + ) + (export (;0;) "a" (instance (type 0))) + ) + ) + (import "a" (instance $a (;0;) (type 0))) + (type (;1;) + (component + (type (;0;) (func)) + (import "a" (func (;0;) (type 0))) + ) + ) + (import "b" (component $b (;0;) (type 1))) + (alias export $a "a" (instance (;1;))) + (alias export 1 "a" (instance (;2;))) + (alias export 2 "a" (instance (;3;))) + (alias export 3 "a" (func (;0;))) + (instance (;4;) (instantiate $b + (with "a" (func 0)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/15.print b/tests/snapshots/local/component-model/alias.wast/15.print new file mode 100644 index 0000000000..3812793d04 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/15.print @@ -0,0 +1,10 @@ +(component + (type (;0;) + (instance + (export (;0;) "v" (value s32)) + ) + ) + (import "a" (instance $foo (;0;) (type 0))) + (alias export $foo "v" (value (;0;))) + (export (;1;) "v" (value 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/16.print b/tests/snapshots/local/component-model/alias.wast/16.print new file mode 100644 index 0000000000..a3c89314cd --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/16.print @@ -0,0 +1,13 @@ +(component + (type (;0;) + (instance + (type (;0;) + (component) + ) + (export (;0;) "v" (component (type 0))) + ) + ) + (import "a" (instance $foo (;0;) (type 0))) + (alias export $foo "v" (component (;0;))) + (export (;1;) "v" (component 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/17.print b/tests/snapshots/local/component-model/alias.wast/17.print new file mode 100644 index 0000000000..cc0a6c5839 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/17.print @@ -0,0 +1,13 @@ +(component + (type (;0;) + (instance + (core type (;0;) + (module) + ) + (export (;0;) "v" (core module (type 0))) + ) + ) + (import "a" (instance $foo (;0;) (type 0))) + (alias export $foo "v" (core module (;0;))) + (export (;1;) "v" (core module 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/18.print b/tests/snapshots/local/component-model/alias.wast/18.print new file mode 100644 index 0000000000..d4984a2772 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/18.print @@ -0,0 +1,10 @@ +(component $C + (core type $t (;0;) (func)) + (component $C2 (;0;) + (alias outer $C $t (core type $t2 (;0;))) + (component (;0;) + (alias outer $C $t (core type (;0;))) + (alias outer $C2 $t2 (core type (;1;))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/19.print b/tests/snapshots/local/component-model/alias.wast/19.print new file mode 100644 index 0000000000..9a2ae2c27d --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/19.print @@ -0,0 +1,5 @@ +(component $C + (core module $m (;0;)) + (alias outer $C $m (core module $target (;1;))) + (export (;2;) "v" (core module $target)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/2.print b/tests/snapshots/local/component-model/alias.wast/2.print new file mode 100644 index 0000000000..36530f5c3b --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/2.print @@ -0,0 +1,24 @@ +(component + (core type (;0;) + (module + (type (;0;) (func)) + (export "f1" (func (type 0))) + (type (;1;) (func (param i32))) + (export "f2" (func (type 1))) + ) + ) + (import "i" (core module $m (;0;) (type 0))) + (core instance $i (;0;) (instantiate $m)) + (core module $m2 (;1;) + (type (;0;) (func)) + (import "" "" (func (;0;) (type 0))) + ) + (alias core export $i "f1" (core func (;0;))) + (core instance (;1;) + (export "" (func 0)) + ) + (core instance (;2;) (instantiate $m2 + (with "" (instance 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/20.print b/tests/snapshots/local/component-model/alias.wast/20.print new file mode 100644 index 0000000000..8182dbc171 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/20.print @@ -0,0 +1,5 @@ +(component $C + (component $m (;0;)) + (alias outer $C $m (component $target (;1;))) + (export (;2;) "v" (component $target)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/27.print b/tests/snapshots/local/component-model/alias.wast/27.print new file mode 100644 index 0000000000..4ff4b069cc --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/27.print @@ -0,0 +1,13 @@ +(component + (type (;0;) + (instance + (core type (;0;) + (module) + ) + (export (;0;) "x" (core module (type 0))) + ) + ) + (import "a" (instance $i (;0;) (type 0))) + (alias export $i "x" (core module (;0;))) + (core instance (;0;) (instantiate 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/28.print b/tests/snapshots/local/component-model/alias.wast/28.print new file mode 100644 index 0000000000..72472e5688 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/28.print @@ -0,0 +1,13 @@ +(component + (type (;0;) + (instance + (type (;0;) + (component) + ) + (export (;0;) "x" (component (type 0))) + ) + ) + (import "a" (instance $i (;0;) (type 0))) + (alias export $i "x" (component (;0;))) + (instance (;1;) (instantiate 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/3.print b/tests/snapshots/local/component-model/alias.wast/3.print new file mode 100644 index 0000000000..9a54f4babb --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/3.print @@ -0,0 +1,41 @@ +(component + (core type (;0;) + (module + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (type (;0;) (func)) + (export "func" (func (type 0))) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + ) + ) + (import "a" (core module $libc (;0;) (type 0))) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "memory" (core memory $mem (;0;))) + (alias core export $libc "table" (core table $tbl (;0;))) + (alias core export $libc "func" (core func $func (;0;))) + (alias core export $libc "global" (core global $global (;0;))) + (alias core export $libc "global mut" (core global $global_mut (;1;))) + (core type (;1;) + (module + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (type (;0;) (func)) + (import "" "func" (func (type 0))) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + ) + ) + (import "x" (core module $needs_libc (;1;) (type 1))) + (core instance (;1;) + (export "memory" (memory $mem)) + (export "table" (table $tbl)) + (export "func" (func $func)) + (export "global" (global $global)) + (export "global mut" (global $global_mut)) + ) + (core instance (;2;) (instantiate $needs_libc + (with "" (instance 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/4.print b/tests/snapshots/local/component-model/alias.wast/4.print new file mode 100644 index 0000000000..daccd6e465 --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/4.print @@ -0,0 +1,23 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + (core type (;0;) + (module) + ) + (export (;0;) "b" (core module (type 0))) + (type (;1;) + (instance) + ) + (export (;0;) "c" (instance (type 1))) + ) + ) + (import "a" (instance $i (;0;) (type 0))) + (alias export $i "a" (func (;0;))) + (export (;1;) "b" (func 0)) + (alias export $i "b" (core module (;0;))) + (export (;1;) "c" (core module 0)) + (alias export $i "c" (instance (;1;))) + (export (;2;) "d" (instance 1)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/alias.wast/5.print b/tests/snapshots/local/component-model/alias.wast/5.print new file mode 100644 index 0000000000..0873ae9d2b --- /dev/null +++ b/tests/snapshots/local/component-model/alias.wast/5.print @@ -0,0 +1,41 @@ +(component + (core type (;0;) + (module + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (type (;0;) (func)) + (export "func" (func (type 0))) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + ) + ) + (import "a" (core module $libc (;0;) (type 0))) + (core type (;1;) + (module + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (type (;0;) (func)) + (import "" "func" (func (type 0))) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + ) + ) + (import "b" (core module $needs_libc (;1;) (type 1))) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "memory" (core memory (;0;))) + (alias core export $libc "table" (core table (;0;))) + (alias core export $libc "func" (core func (;0;))) + (alias core export $libc "global" (core global (;0;))) + (alias core export $libc "global mut" (core global (;1;))) + (core instance (;1;) + (export "memory" (memory 0)) + (export "table" (table 0)) + (export "func" (func 0)) + (export "global" (global 0)) + (export "global mut" (global 1)) + ) + (core instance (;2;) (instantiate $needs_libc + (with "" (instance 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/big.wast/0.print b/tests/snapshots/local/component-model/big.wast/0.print new file mode 100644 index 0000000000..ae6b625a26 --- /dev/null +++ b/tests/snapshots/local/component-model/big.wast/0.print @@ -0,0 +1,51 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (param "msg" string))) + (export (;0;) "log" (func (type 0))) + ) + ) + (import "wasi-logging" (instance $logging (;0;) (type 0))) + (core type (;0;) + (module + (export "memory" (memory 1)) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (export "realloc" (func (type 0))) + ) + ) + (import "libc" (core module $Libc (;0;) (type 0))) + (core instance $libc (;0;) (instantiate $Libc)) + (alias export $logging "log" (func (;0;))) + (alias core export $libc "memory" (core memory (;0;))) + (alias core export $libc "realloc" (core func (;0;))) + (core func $log (;1;) (canon lower (func 0) (memory 0) (realloc 0))) + (core module $Main (;1;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (type (;2;) (func (param i32 i32) (result i32))) + (import "libc" "memory" (memory (;0;) 1)) + (import "libc" "realloc" (func (;0;) (type 0))) + (import "wasi-logging" "log" (func $log (;1;) (type 1))) + (func (;2;) (type 2) (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $log + unreachable + ) + (export "run" (func 2)) + ) + (core instance (;1;) + (export "log" (func $log)) + ) + (core instance $main (;2;) (instantiate $Main + (with "libc" (instance $libc)) + (with "wasi-logging" (instance 1)) + ) + ) + (type (;1;) (func (param "in" string) (result string))) + (alias core export $main "run" (core func (;2;))) + (alias core export $libc "memory" (core memory (;1;))) + (alias core export $libc "realloc" (core func (;3;))) + (func $run (;1;) (type 1) (canon lift (core func 2) (memory 1) (realloc 3))) + (export (;2;) "run" (func $run)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/definedtypes.wast/0.print b/tests/snapshots/local/component-model/definedtypes.wast/0.print new file mode 100644 index 0000000000..89ccab4390 --- /dev/null +++ b/tests/snapshots/local/component-model/definedtypes.wast/0.print @@ -0,0 +1,36 @@ +(component $C + (type $A1 (;0;) bool) + (type $A2 (;1;) u8) + (type $A3 (;2;) s8) + (type $A4 (;3;) u16) + (type $A5 (;4;) s16) + (type $A6 (;5;) u32) + (type $A7 (;6;) s32) + (type $A8 (;7;) u64) + (type $A9 (;8;) s64) + (type $A10 (;9;) float32) + (type $A11 (;10;) float64) + (type $A12 (;11;) char) + (type $A13 (;12;) string) + (type (;13;) (tuple char)) + (type $A14b (;14;) (record (field "x" 13))) + (type $A14c (;15;) (record (field "x" $A1))) + (type $A15a (;16;) (variant (case "x"))) + (type $A15b (;17;) (variant (case "x" $A1))) + (type $A15c (;18;) (variant (case "x") (case "y" string (refines 0)) (case "z" string (refines 1)))) + (type $A15d (;19;) (variant (case "x") (case "y" string (refines 0)) (case "z" string (refines 1)))) + (type (;20;) (tuple u8)) + (type $A16a (;21;) (list 20)) + (type $A16b (;22;) (list $A3)) + (type $A17a (;23;) (tuple u8)) + (type $A17b (;24;) (tuple $A4)) + (type $A18b (;25;) (flags "x")) + (type $A19b (;26;) (enum "x")) + (type (;27;) (tuple u32)) + (type $A21a (;28;) (option 27)) + (type $A21b (;29;) (option $A6)) + (type $A22a (;30;) (result)) + (type $A22b (;31;) (result $A7)) + (type $A22c (;32;) (result (error $A8))) + (type $A22d (;33;) (result $A9 (error $A10))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/empty.wast/0.print b/tests/snapshots/local/component-model/empty.wast/0.print new file mode 100644 index 0000000000..04743950ba --- /dev/null +++ b/tests/snapshots/local/component-model/empty.wast/0.print @@ -0,0 +1 @@ +(component) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/example.wast/0.print b/tests/snapshots/local/component-model/example.wast/0.print new file mode 100644 index 0000000000..780448a75c --- /dev/null +++ b/tests/snapshots/local/component-model/example.wast/0.print @@ -0,0 +1,37 @@ +(component + (component (;0;) + (core module (;0;) + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + ) + (export "one" (func 0)) + ) + (core module (;1;) + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1p+1 (;=2;) + ) + (export "two" (func 0)) + ) + ) + (core module (;0;) + (type (;0;) (func (result i64))) + (func (;0;) (type 0) (result i64) + i64.const 3 + ) + (export "three" (func 0)) + ) + (component (;1;) + (component (;0;) + (core module (;0;) + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p+2 (;=4;) + ) + (export "four" (func 0)) + ) + ) + ) + (component (;2;)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export-ascription.wast/0.print b/tests/snapshots/local/component-model/export-ascription.wast/0.print new file mode 100644 index 0000000000..744630e9f3 --- /dev/null +++ b/tests/snapshots/local/component-model/export-ascription.wast/0.print @@ -0,0 +1,6 @@ +(component + (type (;0;) (func)) + (import "f" (func $f (;0;) (type 0))) + (type (;1;) (func)) + (export (;1;) "f2" (func $f) (func (type 1))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export-ascription.wast/1.print b/tests/snapshots/local/component-model/export-ascription.wast/1.print new file mode 100644 index 0000000000..4ff2ee483c --- /dev/null +++ b/tests/snapshots/local/component-model/export-ascription.wast/1.print @@ -0,0 +1,13 @@ +(component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "f" (func (type 0))) + ) + ) + (import "f" (instance $i (;0;) (type 0))) + (type (;1;) + (instance) + ) + (export (;1;) "f2" (instance $i) (instance (type 1))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export-introduces-alias.wast/0.print b/tests/snapshots/local/component-model/export-introduces-alias.wast/0.print new file mode 100644 index 0000000000..cd547a9c97 --- /dev/null +++ b/tests/snapshots/local/component-model/export-introduces-alias.wast/0.print @@ -0,0 +1,6 @@ +(component + (type (;0;) (func)) + (import "x" (func $f (;0;) (type 0))) + (export $g (;1;) "g" (func $f)) + (export $g2 (;2;) "g2" (func $g)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export-introduces-alias.wast/1.print b/tests/snapshots/local/component-model/export-introduces-alias.wast/1.print new file mode 100644 index 0000000000..092f94732e --- /dev/null +++ b/tests/snapshots/local/component-model/export-introduces-alias.wast/1.print @@ -0,0 +1,15 @@ +(component + (type (;0;) + (component + (type (;0;) u8) + (type (;1;) + (instance + (alias outer 1 0 (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (import "x" (instance (;0;) (type 1))) + (alias export 0 "t" (type (;2;))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export-introduces-alias.wast/2.print b/tests/snapshots/local/component-model/export-introduces-alias.wast/2.print new file mode 100644 index 0000000000..46f213d97e --- /dev/null +++ b/tests/snapshots/local/component-model/export-introduces-alias.wast/2.print @@ -0,0 +1,21 @@ +(component + (type (;0;) + (component + (type (;0;) u8) + (type (;1;) + (instance + (type (;0;) + (instance + (alias outer 2 0 (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (export (;0;) "i" (instance (type 0))) + ) + ) + (import "x" (instance (;0;) (type 1))) + (alias export 0 "i" (instance (;1;))) + (alias export 1 "t" (type (;2;))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export-introduces-alias.wast/4.print b/tests/snapshots/local/component-model/export-introduces-alias.wast/4.print new file mode 100644 index 0000000000..3a6d05c3cd --- /dev/null +++ b/tests/snapshots/local/component-model/export-introduces-alias.wast/4.print @@ -0,0 +1,9 @@ +(component + (type (;0;) + (instance + (type (;0;) u8) + (export (;1;) "t" (type (eq 0))) + (export (;2;) "t2" (type (eq 1))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export.wast/5.print b/tests/snapshots/local/component-model/export.wast/5.print new file mode 100644 index 0000000000..82092aae62 --- /dev/null +++ b/tests/snapshots/local/component-model/export.wast/5.print @@ -0,0 +1,22 @@ +(component + (type (;0;) + (instance) + ) + (import "a" (instance $i (;0;) (type 0))) + (core type (;0;) + (module) + ) + (import "b" (core module $m (;0;) (type 0))) + (type (;1;) + (component) + ) + (import "c" (component $c (;0;) (type 1))) + (import "d" (value $v (;0;) string)) + (type (;2;) (func)) + (import "e" (func $f (;0;) (type 2))) + (export (;1;) "f" (instance $i)) + (export (;1;) "g" (core module $m)) + (export (;1;) "h" (component $c)) + (export (;1;) "i" (value $v)) + (export (;1;) "j" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export.wast/7.print b/tests/snapshots/local/component-model/export.wast/7.print new file mode 100644 index 0000000000..19402892e6 --- /dev/null +++ b/tests/snapshots/local/component-model/export.wast/7.print @@ -0,0 +1,5 @@ +(component + (type (;0;) (func)) + (import "a" (func (;0;) (type 0))) + (export (;1;) (interface "wasi:http/types@2.0.0") (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/export.wast/8.print b/tests/snapshots/local/component-model/export.wast/8.print new file mode 100644 index 0000000000..ce88c858a7 --- /dev/null +++ b/tests/snapshots/local/component-model/export.wast/8.print @@ -0,0 +1,5 @@ +(component + (type (;0;) (func)) + (import (interface "wasi:http/types@2.0.0") (func (;0;) (type 0))) + (export (;1;) (interface "wasi:http/types@2.0.0") (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/func.wast/0.print b/tests/snapshots/local/component-model/func.wast/0.print new file mode 100644 index 0000000000..970257e942 --- /dev/null +++ b/tests/snapshots/local/component-model/func.wast/0.print @@ -0,0 +1,11 @@ +(component + (type (;0;) (func (param "foo" string))) + (import "a" (func (;0;) (type 0))) + (type (;1;) (func (param "foo" string) (param "bar" s32) (param "baz" u32))) + (import "b" (func (;1;) (type 1))) + (type (;2;) (tuple u8)) + (type (;3;) (func (result "foo" 2))) + (import "c" (func (;2;) (type 3))) + (type (;4;) (func (result "foo" string) (result "bar" s32) (result "baz" u32))) + (import "d" (func (;3;) (type 4))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/func.wast/1.print b/tests/snapshots/local/component-model/func.wast/1.print new file mode 100644 index 0000000000..7b9498fbc3 --- /dev/null +++ b/tests/snapshots/local/component-model/func.wast/1.print @@ -0,0 +1,10 @@ +(component + (type (;0;) (func)) + (import "a" (func (;0;) (type 0))) + (type (;1;) (func (param "p1" string))) + (import "b" (func (;1;) (type 1))) + (type (;2;) (func (result u32))) + (import "c" (func (;2;) (type 2))) + (type (;3;) (func (param "p1" bool) (result string))) + (import "d" (func (;3;) (type 3))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/func.wast/6.print b/tests/snapshots/local/component-model/func.wast/6.print new file mode 100644 index 0000000000..5b0e7d3908 --- /dev/null +++ b/tests/snapshots/local/component-model/func.wast/6.print @@ -0,0 +1,11 @@ +(component + (type (;0;) (func (param "msg" string))) + (import "a" (func $log (;0;) (type 0))) + (core module $libc (;0;) + (memory (;0;) 1) + (export "memory" (memory 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "memory" (core memory (;0;))) + (core func (;0;) (canon lower (func $log) (memory 0))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/func.wast/7.print b/tests/snapshots/local/component-model/func.wast/7.print new file mode 100644 index 0000000000..12c23d2f0f --- /dev/null +++ b/tests/snapshots/local/component-model/func.wast/7.print @@ -0,0 +1,18 @@ +(component + (core module $m (;0;) + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + unreachable + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "ret-list" (func 0)) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;0;) (list u8)) + (type (;1;) (func (result 0))) + (alias core export $i "ret-list" (core func (;0;))) + (alias core export $i "memory" (core memory (;0;))) + (func (;0;) (type 1) (canon lift (core func 0) (memory 0))) + (export (;1;) "ret-list" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/func.wast/8.print b/tests/snapshots/local/component-model/func.wast/8.print new file mode 100644 index 0000000000..2e029e82cd --- /dev/null +++ b/tests/snapshots/local/component-model/func.wast/8.print @@ -0,0 +1,14 @@ +(component + (type $big (;0;) (func (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32))) + (component $c (;0;) + (alias outer 1 $big (type $big (;0;))) + (import "big" (func $big (;0;) (type $big))) + (core module $libc (;0;) + (memory (;0;) 1) + (export "memory" (memory 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "memory" (core memory (;0;))) + (core func $big (;0;) (canon lower (func $big) (memory 0))) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/import.wast/0.print b/tests/snapshots/local/component-model/import.wast/0.print new file mode 100644 index 0000000000..c78744c06b --- /dev/null +++ b/tests/snapshots/local/component-model/import.wast/0.print @@ -0,0 +1,28 @@ +(component + (type (;0;) (func)) + (import "a" (func (;0;) (type 0))) + (type (;1;) + (instance) + ) + (import "b" (instance (;0;) (type 1))) + (type (;2;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + ) + ) + (import "c" (instance (;1;) (type 2))) + (type (;3;) + (component + (core type (;0;) + (module) + ) + (import "a" (core module (;0;) (type 0))) + (type (;0;) (func)) + (export (;0;) "b" (func (type 0))) + ) + ) + (import "d" (component (;0;) (type 3))) + (type $t (;4;) (func)) + (import "e" (type (;5;) (eq $t))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/import.wast/13.print b/tests/snapshots/local/component-model/import.wast/13.print new file mode 100644 index 0000000000..d79d8d9621 --- /dev/null +++ b/tests/snapshots/local/component-model/import.wast/13.print @@ -0,0 +1,4 @@ +(component + (import "a" (value (;0;) string)) + (export (;1;) "b" (value 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/import.wast/14.print b/tests/snapshots/local/component-model/import.wast/14.print new file mode 100644 index 0000000000..95fa2297b2 --- /dev/null +++ b/tests/snapshots/local/component-model/import.wast/14.print @@ -0,0 +1,22 @@ +(component + (type (;0;) (func)) + (import (interface "wasi:http/types") (func (;0;) (type 0))) + (type (;1;) (func)) + (import (interface "wasi:http/types@1.0.0") (func (;1;) (type 1))) + (type (;2;) (func)) + (import (interface "wasi:http/types@2.0.0") (func (;2;) (type 2))) + (type (;3;) (func)) + (import (interface "a-b:c-d/e-f@123456.7890.488") (func (;3;) (type 3))) + (type (;4;) (func)) + (import (interface "a:b/c@1.2.3") (func (;4;) (type 4))) + (type (;5;) (func)) + (import (interface "a:b/c@0.0.0") (func (;5;) (type 5))) + (type (;6;) (func)) + (import (interface "a:b/c@0.0.0+abcd") (func (;6;) (type 6))) + (type (;7;) (func)) + (import (interface "a:b/c@0.0.0+abcd-efg") (func (;7;) (type 7))) + (type (;8;) (func)) + (import (interface "a:b/c@0.0.0-abcd+efg") (func (;8;) (type 8))) + (type (;9;) (func)) + (import (interface "a:b/c@0.0.0-abcd.1.2+efg.4.ee.5") (func (;9;) (type 9))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/imports-exports.wast/0.print b/tests/snapshots/local/component-model/imports-exports.wast/0.print new file mode 100644 index 0000000000..82bba87689 --- /dev/null +++ b/tests/snapshots/local/component-model/imports-exports.wast/0.print @@ -0,0 +1,36 @@ +(component + (type (;0;) + (instance + (type (;0;) (func (result string))) + (export (;0;) "f" (func (type 0))) + ) + ) + (import "c" (instance $c (;0;) (type 0))) + (type (;1;) + (component + (type (;0;) + (instance + (type (;0;) (func (result string))) + (export (;0;) "f" (func (type 0))) + ) + ) + (import "c" (instance (;0;) (type 0))) + (type (;1;) (func (result string))) + (export (;0;) "g" (func (type 1))) + ) + ) + (import "d" (component $D (;0;) (type 1))) + (instance $d1 (;1;) (instantiate $D + (with "c" (instance $c)) + ) + ) + (alias export $d1 "g" (func (;0;))) + (instance (;2;) + (export "f" (func 0)) + ) + (instance $d2 (;3;) (instantiate $D + (with "c" (instance 2)) + ) + ) + (export (;4;) "d2" (instance $d2)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/inline-exports.wast/0.print b/tests/snapshots/local/component-model/inline-exports.wast/0.print new file mode 100644 index 0000000000..ed84a2648b --- /dev/null +++ b/tests/snapshots/local/component-model/inline-exports.wast/0.print @@ -0,0 +1,4 @@ +(component + (type (;0;) u8) + (export (;1;) "foo" (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instance-type.wast/0.print b/tests/snapshots/local/component-model/instance-type.wast/0.print new file mode 100644 index 0000000000..1ce047a16f --- /dev/null +++ b/tests/snapshots/local/component-model/instance-type.wast/0.print @@ -0,0 +1,91 @@ +(component + (type (;0;) + (instance) + ) + (type $foo (;1;) (func)) + (type $t (;2;) (func (result string))) + (core type (;0;) + (module + (type (;0;) (func)) + (export "a" (func (type 0))) + (export "b" (func (type 0))) + (export "c" (func (type 0))) + (export "d" (func (type 0))) + (export "e" (func (type 0))) + (type (;1;) (func (param i32))) + (export "f" (func (type 1))) + (type (;2;) (func (param i32) (result i32 i64))) + (export "g" (func (type 2))) + (export "h" (func (type 0))) + (export "i" (global i32)) + (export "j" (global i32)) + (export "k" (global (mut i32))) + (export "l" (table 1 funcref)) + (export "m" (table 1 funcref)) + (export "n" (memory 1)) + (export "o" (memory 1)) + (export "p" (memory 1 2)) + (export "q" (memory 1 2 shared)) + ) + ) + (type $outer (;3;) + (instance + (type (;0;) (func)) + (type (;1;) (func)) + (export (;0;) "a" (func (type 1))) + (export (;1;) "a2" (func (type 0))) + (type (;2;) (func)) + (export (;2;) "b" (func (type 2))) + (type (;3;) (func)) + (export (;3;) "c" (func (type 3))) + (type (;4;) (func)) + (export (;4;) "d" (func (type 4))) + (alias outer 1 $t (type (;5;))) + (export (;5;) "e" (func (type 5))) + (type (;6;) (func (param "f" string))) + (export (;6;) "f" (func (type 6))) + (type (;7;) (func (param "g" s32) (result u32))) + (export (;7;) "g" (func (type 7))) + (export (;8;) "h" (func (type 5))) + (type (;8;) + (component) + ) + (type (;9;) + (component) + ) + (export (;0;) "c1" (component (type 9))) + (type (;10;) + (component + (type (;0;) (func)) + (import "i1" (func (;0;) (type 0))) + ) + ) + (export (;1;) "c2" (component (type 10))) + (type (;11;) + (component + (type (;0;) (func)) + (export (;0;) "e1" (func (type 0))) + ) + ) + (export (;2;) "c3" (component (type 11))) + (export (;3;) "c4" (component (type 8))) + (type (;12;) + (component + (type (;0;) (func)) + (alias outer 1 0 (type (;1;))) + (import "i1" (func (;0;) (type 0))) + (type (;2;) + (component) + ) + (import "i2" (component (;0;) (type 2))) + (export (;1;) "e1" (func (type 1))) + (type (;3;) + (component) + ) + (export (;1;) "e2" (component (type 3))) + ) + ) + (export (;4;) "c5" (component (type 12))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instance-type.wast/1.print b/tests/snapshots/local/component-model/instance-type.wast/1.print new file mode 100644 index 0000000000..a9e1b1a86a --- /dev/null +++ b/tests/snapshots/local/component-model/instance-type.wast/1.print @@ -0,0 +1,10 @@ +(component + (type (;0;) + (instance + (type (;0;) + (instance) + ) + (export (;0;) "a" (instance (type 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instance-type.wast/2.print b/tests/snapshots/local/component-model/instance-type.wast/2.print new file mode 100644 index 0000000000..68f1153c0c --- /dev/null +++ b/tests/snapshots/local/component-model/instance-type.wast/2.print @@ -0,0 +1,19 @@ +(component + (type (;0;) + (instance + (type (;0;) + (instance) + ) + (export (;0;) "a" (instance (type 0))) + ) + ) + (type $x (;1;) + (instance) + ) + (type (;2;) + (instance + (alias outer 1 $x (type (;0;))) + (export (;0;) "a" (instance (type 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instance-type.wast/3.print b/tests/snapshots/local/component-model/instance-type.wast/3.print new file mode 100644 index 0000000000..e52c18eee5 --- /dev/null +++ b/tests/snapshots/local/component-model/instance-type.wast/3.print @@ -0,0 +1,23 @@ +(component + (type (;0;) + (instance + (core type (;0;) + (module + (type (;0;) (func)) + (export "a" (func (type 0))) + (export "b" (func (type 0))) + (type (;1;) (func (param i32))) + (export "c" (func (type 1))) + (export "d" (func (type 0))) + (export "e" (global i32)) + (export "f" (global (mut i32))) + (export "g" (table 1 funcref)) + (export "h" (memory 1)) + (export "i" (memory 1 2)) + (export "j" (memory 1 2 shared)) + ) + ) + (export (;0;) "a" (core module (type 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instance-type.wast/4.print b/tests/snapshots/local/component-model/instance-type.wast/4.print new file mode 100644 index 0000000000..0682ec7b2f --- /dev/null +++ b/tests/snapshots/local/component-model/instance-type.wast/4.print @@ -0,0 +1,106 @@ +(component + (core type (;0;) + (module) + ) + (core type $foo (;1;) + (module) + ) + (type $empty (;0;) (func)) + (type $i (;1;) + (instance) + ) + (core type (;2;) + (module + (type (;0;) (func)) + (import "" "a" (func (type 0))) + (import "" "b" (func (type 0))) + (type (;1;) (func (param i32))) + (import "" "c" (func (type 1))) + (type (;2;) (func (param i32) (result i32))) + (import "" "d" (func (type 2))) + (import "" "e" (global i32)) + (import "" "f" (memory 1)) + (import "" "g" (table 1 funcref)) + (export "a" (func (type 0))) + (export "b" (global i32)) + (export "c" (memory 1)) + (export "d" (table 1 funcref)) + (export "e" (func (type 0))) + (type (;3;) (func (param i32))) + (export "f" (func (type 3))) + ) + ) + (type (;2;) + (component + (type (;0;) (func)) + (import "a" (func (;0;) (type 0))) + (alias outer 1 $empty (type (;1;))) + (import "b" (func (;1;) (type 1))) + (type (;2;) (func (param "c" s32))) + (import "c" (func (;2;) (type 2))) + (type (;3;) (func (param "d" s32) (result s32))) + (import "d" (func (;3;) (type 3))) + (type (;4;) + (instance) + ) + (import "h" (instance (;0;) (type 4))) + (alias outer 1 $i (type (;5;))) + (import "i" (instance (;1;) (type 5))) + (type (;6;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + (alias outer 1 1 (type (;1;))) + (export (;1;) "b" (func (type 1))) + (type (;2;) (func (param "c" s32))) + (export (;2;) "c" (func (type 2))) + ) + ) + (import "j" (instance (;2;) (type 6))) + (core type (;0;) + (module) + ) + (import "k" (core module (;0;) (type 0))) + (core type (;1;) + (module + (type (;0;) (func)) + (import "" "a" (func (type 0))) + (type (;1;) (func (param i32))) + (import "" "b" (func (type 1))) + (export "a" (func (type 0))) + (type (;2;) (func (param i32))) + (export "b" (func (type 2))) + ) + ) + (import "l" (core module (;1;) (type 1))) + (type (;7;) (func)) + (export (;4;) "m" (func (type 7))) + (export (;5;) "n" (func (type 1))) + (type (;8;) (func (param "f" s32))) + (export (;6;) "o" (func (type 8))) + (type (;9;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + (alias outer 1 1 (type (;1;))) + (export (;1;) "b" (func (type 1))) + (type (;2;) (func (param "c" s32))) + (export (;2;) "c" (func (type 2))) + ) + ) + (export (;3;) "p" (instance (type 9))) + (core type (;2;) + (module + (type (;0;) (func)) + (import "" "a" (func (type 0))) + (type (;1;) (func (param i32))) + (import "" "b" (func (type 1))) + (export "a" (func (type 0))) + (type (;2;) (func (param i32))) + (export "b" (func (type 2))) + ) + ) + (export (;2;) "q" (core module (type 2))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/0.print b/tests/snapshots/local/component-model/instantiate.wast/0.print new file mode 100644 index 0000000000..f03b6d8e3f --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/0.print @@ -0,0 +1,7 @@ +(component + (core type (;0;) + (module) + ) + (import "a" (core module $m (;0;) (type 0))) + (core instance $a (;0;) (instantiate $m)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/1.print b/tests/snapshots/local/component-model/instantiate.wast/1.print new file mode 100644 index 0000000000..fb5a0e8d0e --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/1.print @@ -0,0 +1,15 @@ +(component + (type (;0;) (func)) + (import "a" (func $i (;0;) (type 0))) + (type (;1;) + (component + (type (;0;) (func)) + (import "a" (func (;0;) (type 0))) + ) + ) + (import "b" (component $c (;0;) (type 1))) + (instance (;0;) (instantiate $c + (with "a" (func $i)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/10.print b/tests/snapshots/local/component-model/instantiate.wast/10.print new file mode 100644 index 0000000000..f65bf73f81 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/10.print @@ -0,0 +1,68 @@ +(component + (type (;0;) + (component + (core type (;0;) + (module) + ) + (import "a" (core module (;0;) (type 0))) + (type (;0;) (func)) + (import "b" (func (;0;) (type 0))) + (type (;1;) + (component) + ) + (import "c" (component (;0;) (type 1))) + (type (;2;) + (instance) + ) + (import "d" (instance (;0;) (type 2))) + (import "e" (value (;0;) string)) + ) + ) + (import "a" (component $c (;0;) (type 0))) + (core type (;0;) + (module) + ) + (import "b" (core module $m (;0;) (type 0))) + (type (;1;) (func)) + (import "c" (func $f (;0;) (type 1))) + (type (;2;) + (component) + ) + (import "d" (component $c2 (;1;) (type 2))) + (type (;3;) + (instance) + ) + (import "e" (instance $i (;0;) (type 3))) + (import "f" (value $v (;0;) string)) + (instance (;1;) (instantiate $c + (with "a" (core module $m)) + (with "b" (func $f)) + (with "c" (component $c2)) + (with "d" (instance $i)) + (with "e" (value $v)) + ) + ) + (core instance $c (;0;) (instantiate $m)) + (core instance (;1;) (instantiate $m)) + (type $empty (;4;) + (instance) + ) + (import "g" (instance $d (;2;) (type $empty))) + (type (;5;) + (instance) + ) + (import "h" (instance (;3;) (type 5))) + (type (;6;) + (instance + (type (;0;) (func)) + (export (;0;) "x" (func (type 0))) + ) + ) + (import "i" (instance (;4;) (type 6))) + (type (;7;) + (instance) + ) + (import "x" (instance (;5;) (type 7))) + (export (;6;) "j" (instance 5)) + (export (;7;) "k" (instance 5)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/14.print b/tests/snapshots/local/component-model/instantiate.wast/14.print new file mode 100644 index 0000000000..874efa38af --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/14.print @@ -0,0 +1,12 @@ +(component + (type (;0;) (func)) + (import "a" (func $f (;0;) (type 0))) + (type (;1;) + (component) + ) + (import "b" (component $c (;0;) (type 1))) + (instance (;0;) (instantiate $c + (with "a" (func $f)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/2.print b/tests/snapshots/local/component-model/instantiate.wast/2.print new file mode 100644 index 0000000000..af1c57f292 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/2.print @@ -0,0 +1,13 @@ +(component + (import "a" (value $i (;0;) string)) + (type (;0;) + (component + (import "a" (value (;0;) string)) + ) + ) + (import "b" (component $c (;0;) (type 0))) + (instance (;0;) (instantiate $c + (with "a" (value $i)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/23.print b/tests/snapshots/local/component-model/instantiate.wast/23.print new file mode 100644 index 0000000000..b49dad228b --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/23.print @@ -0,0 +1,25 @@ +(component + (type (;0;) + (component + (core type (;0;) + (module + (import "" "" (global i32)) + (type (;0;) (func)) + (import "" "f" (func (type 0))) + ) + ) + (import "a" (core module (;0;) (type 0))) + ) + ) + (import "a" (component $m (;0;) (type 0))) + (core type (;0;) + (module + (import "" "" (global i32)) + ) + ) + (import "b" (core module $i (;0;) (type 0))) + (instance $i (;0;) (instantiate $m + (with "a" (core module $i)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/24.print b/tests/snapshots/local/component-model/instantiate.wast/24.print new file mode 100644 index 0000000000..5d0a5eadc8 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/24.print @@ -0,0 +1,27 @@ +(component + (type (;0;) + (component + (core type (;0;) + (module + (type (;0;) (func)) + (export "" (func (type 0))) + ) + ) + (import "a" (core module (;0;) (type 0))) + ) + ) + (import "a" (component $m (;0;) (type 0))) + (core type (;0;) + (module + (type (;0;) (func)) + (export "" (func (type 0))) + (type (;1;) (func)) + (export "a" (func (type 1))) + ) + ) + (import "b" (core module $i (;0;) (type 0))) + (instance $i (;0;) (instantiate $m + (with "a" (core module $i)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/25.print b/tests/snapshots/local/component-model/instantiate.wast/25.print new file mode 100644 index 0000000000..763ef61649 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/25.print @@ -0,0 +1,27 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + ) + ) + (import "a" (instance (;0;) (type 0))) + ) + ) + (import "a" (component $m (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (func)) + (export (;0;) "a" (func (type 0))) + (type (;1;) (func)) + (export (;1;) "b" (func (type 1))) + ) + ) + (import "b" (instance $i (;0;) (type 1))) + (instance (;1;) (instantiate $m + (with "a" (instance $i)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/3.print b/tests/snapshots/local/component-model/instantiate.wast/3.print new file mode 100644 index 0000000000..27da9d7e22 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/3.print @@ -0,0 +1,19 @@ +(component + (type (;0;) + (component) + ) + (import "a" (component $i (;0;) (type 0))) + (type (;1;) + (component + (type (;0;) + (component) + ) + (import "a" (component (;0;) (type 0))) + ) + ) + (import "b" (component $c (;1;) (type 1))) + (instance (;0;) (instantiate $c + (with "a" (component $i)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/37.print b/tests/snapshots/local/component-model/instantiate.wast/37.print new file mode 100644 index 0000000000..ca05e9c9ad --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/37.print @@ -0,0 +1,27 @@ +(component + (component $m (;0;) + (core module $sub (;0;) + (type (;0;) (func (result i32))) + (func $f (;0;) (type 0) (result i32) + i32.const 5 + ) + (export "" (func $f)) + ) + (export (;1;) "module" (core module $sub)) + ) + (instance $a (;0;) (instantiate $m)) + (alias export $a "module" (core module $sub (;0;))) + (core instance $b (;0;) (instantiate $sub)) + (core module $final (;1;) + (type (;0;) (func (result i32))) + (import "" "" (func $b (;0;) (type 0))) + (func (;1;) (type 0) (result i32) + call $b + ) + (export "get" (func 1)) + ) + (core instance (;1;) (instantiate $final + (with "" (instance $b)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/4.print b/tests/snapshots/local/component-model/instantiate.wast/4.print new file mode 100644 index 0000000000..3f25b3c9ce --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/4.print @@ -0,0 +1,19 @@ +(component + (core type (;0;) + (module) + ) + (import "a" (core module $i (;0;) (type 0))) + (type (;0;) + (component + (core type (;0;) + (module) + ) + (import "a" (core module (;0;) (type 0))) + ) + ) + (import "b" (component $c (;0;) (type 0))) + (instance (;0;) (instantiate $c + (with "a" (core module $i)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/5.print b/tests/snapshots/local/component-model/instantiate.wast/5.print new file mode 100644 index 0000000000..b149c9322d --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/5.print @@ -0,0 +1,19 @@ +(component + (type (;0;) + (instance) + ) + (import "a" (instance $i (;0;) (type 0))) + (type (;1;) + (component + (type (;0;) + (instance) + ) + (import "a" (instance (;0;) (type 0))) + ) + ) + (import "b" (component $c (;0;) (type 1))) + (instance (;1;) (instantiate $c + (with "a" (instance $i)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/59.print b/tests/snapshots/local/component-model/instantiate.wast/59.print new file mode 100644 index 0000000000..c6d029ced5 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/59.print @@ -0,0 +1,24 @@ +(component + (type (;0;) + (instance) + ) + (import "a" (instance $i (;0;) (type 0))) + (type (;1;) (func)) + (import "b" (func $f (;0;) (type 1))) + (type (;2;) + (component) + ) + (import "c" (component $c (;0;) (type 2))) + (core type (;0;) + (module) + ) + (import "d" (core module $m (;0;) (type 0))) + (import "e" (value $v (;0;) string)) + (instance (;1;) + (export "a" (instance $i)) + (export "b" (func $f)) + (export "c" (component $c)) + (export "d" (core module $m)) + (export "e" (value $v)) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/6.print b/tests/snapshots/local/component-model/instantiate.wast/6.print new file mode 100644 index 0000000000..9e9ae600bb --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/6.print @@ -0,0 +1,27 @@ +(component + (core type (;0;) + (module + (type (;0;) (func)) + (import "" "a" (func (type 0))) + (import "" "b" (global i32)) + (import "" "c" (table 1 funcref)) + (import "" "d" (memory 1)) + ) + ) + (import "a" (core module $m (;0;) (type 0))) + (core type (;1;) + (module + (type (;0;) (func)) + (export "a" (func (type 0))) + (export "b" (global i32)) + (export "c" (table 1 funcref)) + (export "d" (memory 1)) + ) + ) + (import "b" (core module $m2 (;1;) (type 1))) + (core instance $x (;0;) (instantiate $m2)) + (core instance (;1;) (instantiate $m + (with "" (instance $x)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/60.print b/tests/snapshots/local/component-model/instantiate.wast/60.print new file mode 100644 index 0000000000..b8c4386ad0 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/60.print @@ -0,0 +1,24 @@ +(component + (core module $m (;0;) + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 1 funcref) + (memory (;0;) 1) + (global (;0;) i32 i32.const 0) + (export "1" (func 0)) + (export "2" (memory 0)) + (export "3" (table 0)) + (export "4" (global 0)) + ) + (core instance $i (;0;) (instantiate $m)) + (alias core export $i "1" (core func (;0;))) + (alias core export $i "2" (core memory (;0;))) + (alias core export $i "3" (core table (;0;))) + (alias core export $i "4" (core global (;0;))) + (core instance (;1;) + (export "a" (func 0)) + (export "b" (memory 0)) + (export "c" (table 0)) + (export "d" (global 0)) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/65.print b/tests/snapshots/local/component-model/instantiate.wast/65.print new file mode 100644 index 0000000000..aeab4b3b79 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/65.print @@ -0,0 +1,12 @@ +(component + (type (;0;) (tuple u32 u32)) + (import "a" (type (;1;) (eq 0))) + (component (;0;) + (type (;0;) (tuple u32 u32)) + (import "a" (type (;1;) (eq 0))) + ) + (instance (;0;) (instantiate 0 + (with "a" (type 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/67.print b/tests/snapshots/local/component-model/instantiate.wast/67.print new file mode 100644 index 0000000000..6d3344a9bf --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/67.print @@ -0,0 +1,20 @@ +(component + (core module $a (;0;) + (import "" "" (table (;0;) 0 funcref)) + (table (;1;) 2 funcref) + (export "x" (table 1)) + ) + (component $C (;0;) + (core type (;0;) + (module + (import "" "" (table 1 funcref)) + (export "x" (table 1 funcref)) + ) + ) + (import "a" (core module (;0;) (type 0))) + ) + (instance (;0;) (instantiate $C + (with "a" (core module $a)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/68.print b/tests/snapshots/local/component-model/instantiate.wast/68.print new file mode 100644 index 0000000000..3971ee4358 --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/68.print @@ -0,0 +1,28 @@ +(component + (core module $a1 (;0;) + (import "" "" (memory (;0;) 0)) + ) + (core module $a2 (;1;) + (memory (;0;) 2) + (export "x" (memory 0)) + ) + (component $C (;0;) + (core type (;0;) + (module + (import "" "" (memory 1)) + ) + ) + (import "a1" (core module (;0;) (type 0))) + (core type (;1;) + (module + (export "x" (memory 1)) + ) + ) + (import "a2" (core module (;1;) (type 1))) + ) + (instance (;0;) (instantiate $C + (with "a1" (core module $a1)) + (with "a2" (core module $a2)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/7.print b/tests/snapshots/local/component-model/instantiate.wast/7.print new file mode 100644 index 0000000000..19011fbd0e --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/7.print @@ -0,0 +1,37 @@ +(component + (core type (;0;) + (module + (type (;0;) (func)) + (import "" "d" (func (type 0))) + (import "" "c" (global i32)) + (import "" "b" (table 1 funcref)) + (import "" "a" (memory 1)) + ) + ) + (import "a" (core module $m (;0;) (type 0))) + (core type (;1;) + (module + (type (;0;) (func)) + (export "a" (func (type 0))) + (export "b" (global i32)) + (export "c" (table 1 funcref)) + (export "d" (memory 1)) + ) + ) + (import "b" (core module $m2 (;1;) (type 1))) + (core instance $x (;0;) (instantiate $m2)) + (alias core export $x "a" (core func (;0;))) + (alias core export $x "b" (core global (;0;))) + (alias core export $x "c" (core table (;0;))) + (alias core export $x "d" (core memory (;0;))) + (core instance (;1;) + (export "d" (func 0)) + (export "c" (global 0)) + (export "b" (table 0)) + (export "a" (memory 0)) + ) + (core instance (;2;) (instantiate $m + (with "" (instance 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/8.print b/tests/snapshots/local/component-model/instantiate.wast/8.print new file mode 100644 index 0000000000..6f5e1769fa --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/8.print @@ -0,0 +1,12 @@ +(component + (type $t (;0;) string) + (import "a" (value (;0;) (type $t))) + (component $c (;0;) + (import "a" (value (;0;) string)) + (export (;1;) "b" (value 0)) + ) + (instance (;0;) (instantiate $c + (with "a" (value 0)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/instantiate.wast/9.print b/tests/snapshots/local/component-model/instantiate.wast/9.print new file mode 100644 index 0000000000..9646eb3aec --- /dev/null +++ b/tests/snapshots/local/component-model/instantiate.wast/9.print @@ -0,0 +1,34 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (core type (;0;) + (module) + ) + (export (;0;) "a" (core module (type 0))) + ) + ) + (import "a" (instance (;0;) (type 0))) + ) + ) + (import "a" (component $m (;0;) (type 0))) + (type (;1;) + (component + (core type (;0;) + (module) + ) + (export (;0;) "b" (core module (type 0))) + ) + ) + (import "b" (component $m2 (;1;) (type 1))) + (instance $x (;0;) (instantiate $m2)) + (alias export $x "b" (core module (;0;))) + (instance (;1;) + (export "a" (core module 0)) + ) + (instance (;2;) (instantiate $m + (with "a" (instance 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/link.wast/0.print b/tests/snapshots/local/component-model/link.wast/0.print new file mode 100644 index 0000000000..3570f2affa --- /dev/null +++ b/tests/snapshots/local/component-model/link.wast/0.print @@ -0,0 +1,18 @@ +(component + (core module $A (;0;) + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + ) + (export "one" (func 0)) + ) + (core module $B (;1;) + (type (;0;) (func (result i32))) + (import "a" "one" (func (;0;) (type 0))) + ) + (core instance $a (;0;) (instantiate $A)) + (core instance $b (;1;) (instantiate $B + (with "a" (instance $a)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/module-link.wast/0.print b/tests/snapshots/local/component-model/module-link.wast/0.print new file mode 100644 index 0000000000..83a0f5ac73 --- /dev/null +++ b/tests/snapshots/local/component-model/module-link.wast/0.print @@ -0,0 +1,12 @@ +(component + (type $Wasi (;0;) + (instance) + ) + (component $B (;0;)) + (component $B_wrap (;1;) + (alias outer 1 $Wasi (type $Wasi (;0;))) + (import "wasi" (instance $wasi (;0;) (type $Wasi))) + (alias outer 1 $B (component $B (;0;))) + (instance $b (;1;) (instantiate $B)) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/module-link.wast/1.print b/tests/snapshots/local/component-model/module-link.wast/1.print new file mode 100644 index 0000000000..54a5911b6f --- /dev/null +++ b/tests/snapshots/local/component-model/module-link.wast/1.print @@ -0,0 +1,139 @@ +(component + (type $Wasi (;0;) + (instance) + ) + (import "wasi" (instance $wasi (;0;) (type $Wasi))) + (component $A (;0;) + (type $Wasi (;0;) + (instance) + ) + (import "wasi" (instance (;0;) (type $Wasi))) + (core module $m (;0;) + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;1;) (func)) + (alias core export $i "a" (core func (;0;))) + (func (;0;) (type 1) (canon lift (core func 0))) + (export (;1;) "a" (func 0)) + ) + (component $B (;1;) + (type $Wasi (;0;) + (instance) + ) + (import "wasi" (instance $wasi (;0;) (type $Wasi))) + (type (;1;) + (component + (alias outer $B $Wasi (type (;0;))) + (import "wasi" (instance (;0;) (type 0))) + (type (;1;) (func)) + (export (;0;) "a" (func (type 1))) + ) + ) + (import "a1-x" (component $A (;0;) (type 1))) + (instance $a (;1;) (instantiate $A + (with "wasi" (instance $wasi)) + ) + ) + (alias export $a "a" (func (;0;))) + (core func $lower (;0;) (canon lower (func 0))) + (core module $b (;0;) + (type (;0;) (func)) + (import "a" "a" (func (;0;) (type 0))) + (func (;1;) (type 0)) + (export "b" (func 1)) + ) + (core instance (;0;) + (export "a" (func $lower)) + ) + (core instance $b (;1;) (instantiate $b + (with "a" (instance 0)) + ) + ) + (type (;2;) (func)) + (alias core export $b "b" (core func (;1;))) + (func (;1;) (type 2) (canon lift (core func 1))) + (export (;2;) "b" (func 1)) + ) + (component $B_wrap (;2;) + (type $Wasi (;0;) + (instance) + ) + (import "wasi" (instance $wasi (;0;) (type $Wasi))) + (alias outer 1 $B (component $B (;0;))) + (alias outer 1 $A (component $A (;1;))) + (instance $b (;1;) (instantiate $B + (with "wasi" (instance $wasi)) + (with "a1-x" (component $A)) + ) + ) + (alias export $b "b" (func (;0;))) + (export (;1;) "b" (func 0)) + ) + (component $C (;3;) + (type $Wasi (;0;) + (instance) + ) + (import "wasi" (instance $wasi (;0;) (type $Wasi))) + (type (;1;) + (component + (alias outer $C $Wasi (type (;0;))) + (import "wasi" (instance (;0;) (type 0))) + (type (;1;) (func)) + (export (;0;) "b" (func (type 1))) + ) + ) + (import "b1-x" (component $B (;0;) (type 1))) + (instance $b (;1;) (instantiate $B + (with "wasi" (instance $wasi)) + ) + ) + (alias export $b "b" (func (;0;))) + (export (;1;) "c" (func 0)) + ) + (component $C_wrap (;4;) + (type $Wasi (;0;) + (instance) + ) + (import "wasi" (instance $wasi (;0;) (type $Wasi))) + (alias outer 1 $C (component $C (;0;))) + (alias outer 1 $B_wrap (component $B_wrap (;1;))) + (instance $c (;1;) (instantiate $C + (with "wasi" (instance $wasi)) + (with "b1-x" (component $B_wrap)) + ) + ) + (alias export $c "c" (func (;0;))) + (export (;1;) "c" (func 0)) + ) + (component $D (;5;) + (type $Wasi (;0;) + (instance) + ) + (import "wasi" (instance $wasi (;0;) (type $Wasi))) + (type (;1;) + (component + (alias outer $D $Wasi (type (;0;))) + (import "wasi" (instance (;0;) (type 0))) + (type (;1;) (func)) + (export (;0;) "c" (func (type 1))) + ) + ) + (import "c1-x" (component $C (;0;) (type 1))) + (instance $c (;1;) (instantiate $C + (with "wasi" (instance $wasi)) + ) + ) + (alias export $c "c" (func (;0;))) + (export (;1;) "d" (func 0)) + ) + (instance $d (;1;) (instantiate $D + (with "wasi" (instance $wasi)) + (with "c1-x" (component $C_wrap)) + ) + ) + (alias export $d "d" (func (;0;))) + (export (;1;) "d" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/naming.wast/0.print b/tests/snapshots/local/component-model/naming.wast/0.print new file mode 100644 index 0000000000..29425ffb83 --- /dev/null +++ b/tests/snapshots/local/component-model/naming.wast/0.print @@ -0,0 +1,9 @@ +(component + (type (;0;) (func)) + (import "a" (func (;0;) (type 0))) + (component (;0;)) + (instance (;0;) (instantiate 0 + (with "NotKebab-Case" (func 0)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/nested-modules.wast/0.print b/tests/snapshots/local/component-model/nested-modules.wast/0.print new file mode 100644 index 0000000000..36fa91b709 --- /dev/null +++ b/tests/snapshots/local/component-model/nested-modules.wast/0.print @@ -0,0 +1,19 @@ +(component + (core type (;0;) + (module) + ) + (import "i1" (core module (;0;) (type 0))) + (core module (;1;)) + (core module (;2;)) + (core module (;3;)) + (component (;0;) + (core module (;0;)) + ) + (component (;1;) + (core module $m (;0;)) + (type (;0;) (func (param "p" string))) + (import "a" (func (;0;) (type 0))) + (export (;1;) "b" (core module $m)) + ) + (export (;4;) "x" (core module 3)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/nested-modules.wast/1.print b/tests/snapshots/local/component-model/nested-modules.wast/1.print new file mode 100644 index 0000000000..3a4f52d6a1 --- /dev/null +++ b/tests/snapshots/local/component-model/nested-modules.wast/1.print @@ -0,0 +1,9 @@ +(component + (core type (;0;) + (module) + ) + (import "a" (core module (;0;) (type 0))) + (core type (;1;) + (module) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/nested-modules.wast/3.print b/tests/snapshots/local/component-model/nested-modules.wast/3.print new file mode 100644 index 0000000000..58ecbe3490 --- /dev/null +++ b/tests/snapshots/local/component-model/nested-modules.wast/3.print @@ -0,0 +1,28 @@ +(component + (core module (;0;) + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "" (func 0)) + ) + (core type (;0;) + (module) + ) + (import "a" (core module (;1;) (type 0))) + (core module (;2;) + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 5 + ) + (export "" (func 0)) + ) + (type (;0;) + (instance + (core type (;0;) + (module) + ) + (export (;0;) "a" (core module (type 0))) + ) + ) + (import "b" (instance (;0;) (type 0))) + (alias export 0 "a" (core module (;3;))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/0.print b/tests/snapshots/local/component-model/resources.wast/0.print new file mode 100644 index 0000000000..bd774ff15f --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/0.print @@ -0,0 +1,3 @@ +(component + (type $x (;0;) (resource (rep i32))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/1.print b/tests/snapshots/local/component-model/resources.wast/1.print new file mode 100644 index 0000000000..a0846300ae --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/1.print @@ -0,0 +1,6 @@ +(component + (type $x (;0;) (resource (rep i32))) + (core func (;0;) (canon resource.new $x)) + (core func (;1;) (canon resource.rep $x)) + (core func (;2;) (canon resource.drop $x)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/100.print b/tests/snapshots/local/component-model/resources.wast/100.print new file mode 100644 index 0000000000..60e719b86b --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/100.print @@ -0,0 +1,10 @@ +(component + (import "b" (type $T (;0;) (sub resource))) + (type (;1;) (borrow $T)) + (type (;2;) (func (param "self" 1))) + (import "f" (func $f (;0;) (type 2))) + (export $c (;3;) "c" (type $T)) + (type (;4;) (borrow $c)) + (type (;5;) (func (param "self" 4))) + (export (;1;) "[method]c.foo" (func $f) (func (type 5))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/104.print b/tests/snapshots/local/component-model/resources.wast/104.print new file mode 100644 index 0000000000..3277a8a234 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/104.print @@ -0,0 +1,7 @@ +(component + (component $C (;0;)) + (instance (;0;) (instantiate $C + (with "this is not kebab case" (component $C)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/105.print b/tests/snapshots/local/component-model/resources.wast/105.print new file mode 100644 index 0000000000..4af1dd0f4a --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/105.print @@ -0,0 +1,7 @@ +(component + (component $C (;0;)) + (instance (;0;) (instantiate $C + (with "[method]foo.bar" (component $C)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/106.print b/tests/snapshots/local/component-model/resources.wast/106.print new file mode 100644 index 0000000000..86b57d1b2b --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/106.print @@ -0,0 +1,53 @@ +(component + (component $C (;0;) + (import "in" (type $r (;0;) (sub resource))) + (export (;1;) "out" (type $r)) + ) + (type $r (;0;) (resource (rep i32))) + (instance $c1 (;0;) (instantiate $C + (with "in" (type $r)) + ) + ) + (alias export $c1 "out" (type (;1;))) + (instance $c2 (;1;) (instantiate $C + (with "in" (type 1)) + ) + ) + (alias export $c2 "out" (type (;2;))) + (instance $c3 (;2;) (instantiate $C + (with "in" (type 2)) + ) + ) + (alias export $c3 "out" (type (;3;))) + (instance $c4 (;3;) (instantiate $C + (with "in" (type 3)) + ) + ) + (alias export $c4 "out" (type (;4;))) + (instance $c5 (;4;) (instantiate $C + (with "in" (type 4)) + ) + ) + (component $C2 (;1;) + (import "in1" (type $r (;0;) (sub resource))) + (import "in2" (type (;1;) (eq $r))) + (import "in3" (type (;2;) (eq $r))) + (import "in4" (type (;3;) (eq $r))) + (import "in5" (type (;4;) (eq $r))) + (import "in6" (type (;5;) (eq $r))) + ) + (alias export $c1 "out" (type (;5;))) + (alias export $c2 "out" (type (;6;))) + (alias export $c3 "out" (type (;7;))) + (alias export $c4 "out" (type (;8;))) + (alias export $c5 "out" (type (;9;))) + (instance (;5;) (instantiate $C2 + (with "in1" (type $r)) + (with "in2" (type 5)) + (with "in3" (type 6)) + (with "in4" (type 7)) + (with "in5" (type 8)) + (with "in6" (type 9)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/108.print b/tests/snapshots/local/component-model/resources.wast/108.print new file mode 100644 index 0000000000..fa0a26ecab --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/108.print @@ -0,0 +1,22 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (export (;0;) "r" (type (sub resource))) + ) + ) + (export (;0;) "t" (instance (type 0))) + (alias export 0 "r" (type (;1;))) + (type (;2;) + (instance + (alias outer 1 1 (type (;0;))) + (export (;1;) "r2" (type (eq 0))) + (export (;2;) "r" (type (sub resource))) + ) + ) + (export (;1;) "t2" (instance (type 2))) + ) + ) + (export (;1;) "x" (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/109.print b/tests/snapshots/local/component-model/resources.wast/109.print new file mode 100644 index 0000000000..6662df037c --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/109.print @@ -0,0 +1,14 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (export (;0;) "bar" (type (sub resource))) + (type (;1;) (func)) + (export (;0;) "[static]bar.a" (func (type 1))) + ) + ) + (export (;0;) "x" (instance (type 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/19.print b/tests/snapshots/local/component-model/resources.wast/19.print new file mode 100644 index 0000000000..08a62d41ae --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/19.print @@ -0,0 +1,9 @@ +(component + (type (;0;) + (component + (import "x" (type (;0;) (sub resource))) + (export (;1;) "y" (type (eq 0))) + (export (;2;) "z" (type (sub resource))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/2.print b/tests/snapshots/local/component-model/resources.wast/2.print new file mode 100644 index 0000000000..e5a6cb1ed7 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/2.print @@ -0,0 +1,4 @@ +(component + (import "x" (type $x (;0;) (sub resource))) + (core func (;0;) (canon resource.drop $x)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/22.print b/tests/snapshots/local/component-model/resources.wast/22.print new file mode 100644 index 0000000000..bc99af6f9c --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/22.print @@ -0,0 +1,19 @@ +(component + (type (;0;) + (component + (type (;0;) + (instance + (export (;0;) "t" (type (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (result "x" 1))) + (export (;0;) "f" (func (type 2))) + ) + ) + (import "x" (instance (;0;) (type 0))) + (alias export 0 "t" (type (;1;))) + (type (;2;) (own 1)) + (type (;3;) (func (result "x" 2))) + (export (;0;) "f" (func (type 3))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/23.print b/tests/snapshots/local/component-model/resources.wast/23.print new file mode 100644 index 0000000000..134180571c --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/23.print @@ -0,0 +1,17 @@ +(component + (type (;0;) + (instance + (type (;0;) + (instance + (export (;0;) "file" (type (sub resource))) + ) + ) + (export (;0;) "fs" (instance (type 0))) + (alias export 0 "file" (type (;1;))) + (type (;2;) (borrow 1)) + (type (;3;) (func (param "f" 2))) + (export (;0;) "fancy-op" (func (type 3))) + ) + ) + (import "fancy-fs" (instance $fancy-fs (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/24.print b/tests/snapshots/local/component-model/resources.wast/24.print new file mode 100644 index 0000000000..abae41f6cb --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/24.print @@ -0,0 +1,33 @@ +(component $C + (type (;0;) (tuple string bool)) + (type $T (;1;) (list 0)) + (type $U (;2;) (option $T)) + (type (;3;) (list $T)) + (type $G (;4;) (func (param "x" 3) (result $U))) + (type $D (;5;) + (component + (alias outer $C $T (type (;0;))) + (type (;1;) (list 0)) + (type (;2;) (list u8)) + (type (;3;) (func (param "x" 1) (result 2))) + (import "f" (func (;0;) (type 3))) + (alias outer $C $G (type (;4;))) + (import "g" (func (;1;) (type 4))) + (export (;2;) "g2" (func (type 4))) + (alias outer $C $U (type (;5;))) + (type (;6;) (func (result 5))) + (export (;3;) "h" (func (type 6))) + (import "T" (type (;7;) (sub resource))) + (type (;8;) (own 7)) + (type (;9;) (list 8)) + (type (;10;) (func (param "x" 9))) + (import "i" (func (;4;) (type 10))) + (export (;11;) "T2" (type (eq 7))) + (export (;12;) "U" (type (sub resource))) + (type (;13;) (borrow 11)) + (type (;14;) (own 12)) + (type (;15;) (func (param "x" 13) (result 14))) + (export (;5;) "j" (func (type 15))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/25.print b/tests/snapshots/local/component-model/resources.wast/25.print new file mode 100644 index 0000000000..4f05df7325 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/25.print @@ -0,0 +1,4 @@ +(component + (import "T1" (type $T1 (;0;) (sub resource))) + (import "T2" (type $T2 (;1;) (sub resource))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/26.print b/tests/snapshots/local/component-model/resources.wast/26.print new file mode 100644 index 0000000000..b8ad78ec9a --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/26.print @@ -0,0 +1,11 @@ +(component $C + (import "T1" (type $T1 (;0;) (sub resource))) + (import "T2" (type $T2 (;1;) (sub resource))) + (import "T3" (type $T3 (;2;) (eq $T2))) + (type (;3;) (own $T1)) + (type $ListT1 (;4;) (list 3)) + (type (;5;) (own $T2)) + (type $ListT2 (;6;) (list 5)) + (type (;7;) (own $T3)) + (type $ListT3 (;8;) (list 7)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/27.print b/tests/snapshots/local/component-model/resources.wast/27.print new file mode 100644 index 0000000000..f3a96193db --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/27.print @@ -0,0 +1,16 @@ +(component + (import "T" (type $T (;0;) (sub resource))) + (import "U" (type $U (;1;) (sub resource))) + (type $Own1 (;2;) (own $T)) + (type $Own2 (;3;) (own $T)) + (type $Own3 (;4;) (own $U)) + (type $ListOwn1 (;5;) (list $Own1)) + (type $ListOwn2 (;6;) (list $Own2)) + (type $ListOwn3 (;7;) (list $Own3)) + (type $Borrow1 (;8;) (borrow $T)) + (type $Borrow2 (;9;) (borrow $T)) + (type $Borrow3 (;10;) (borrow $U)) + (type $ListBorrow1 (;11;) (list $Borrow1)) + (type $ListBorrow2 (;12;) (list $Borrow2)) + (type $ListBorrow3 (;13;) (list $Borrow3)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/28.print b/tests/snapshots/local/component-model/resources.wast/28.print new file mode 100644 index 0000000000..907c924449 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/28.print @@ -0,0 +1,14 @@ +(component + (type (;0;) + (component + (export (;0;) "T1" (type (sub resource))) + (export (;1;) "T2" (type (sub resource))) + (export (;2;) "T3" (type (eq 1))) + ) + ) + (import "C" (component $C (;0;) (type 0))) + (instance $c (;0;) (instantiate $C)) + (alias export $c "T1" (type $T1 (;1;))) + (alias export $c "T2" (type $T2 (;2;))) + (alias export $c "T3" (type $T3 (;3;))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/29.print b/tests/snapshots/local/component-model/resources.wast/29.print new file mode 100644 index 0000000000..855c66d8f0 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/29.print @@ -0,0 +1,14 @@ +(component + (component $C (;0;) + (type $r1 (;0;) (resource (rep i32))) + (type $r2 (;1;) (resource (rep i32))) + (export (;2;) "r1" (type $r1)) + (export (;3;) "r2" (type $r2)) + ) + (instance $c1 (;0;) (instantiate $C)) + (instance $c2 (;1;) (instantiate $C)) + (alias export $c1 "r1" (type $c1r1 (;0;))) + (alias export $c1 "r2" (type $c1r2 (;1;))) + (alias export $c2 "r1" (type $c2r1 (;2;))) + (alias export $c2 "r2" (type $c2r2 (;3;))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/3.print b/tests/snapshots/local/component-model/resources.wast/3.print new file mode 100644 index 0000000000..b1aaacf507 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/3.print @@ -0,0 +1,11 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param i32)) + (export "dtor" (func 0)) + ) + (core instance $m (;0;) (instantiate $m)) + (alias core export $m "dtor" (core func (;0;))) + (type $x (;0;) (resource (rep i32) (dtor (func 0)))) + (core func (;1;) (canon resource.new $x)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/30.print b/tests/snapshots/local/component-model/resources.wast/30.print new file mode 100644 index 0000000000..b305726736 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/30.print @@ -0,0 +1,5 @@ +(component + (type $r (;0;) (resource (rep i32))) + (export (;1;) "r1" (type $r)) + (export (;2;) "r2" (type $r)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/31.print b/tests/snapshots/local/component-model/resources.wast/31.print new file mode 100644 index 0000000000..4609e78967 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/31.print @@ -0,0 +1,8 @@ +(component + (type (;0;) + (component + (export (;0;) "r1" (type (sub resource))) + (export (;1;) "r2" (type (sub resource))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/32.print b/tests/snapshots/local/component-model/resources.wast/32.print new file mode 100644 index 0000000000..b42a70b550 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/32.print @@ -0,0 +1,5 @@ +(component + (type $r (;0;) (resource (rep i32))) + (export $r1 (;1;) "r1" (type $r)) + (export (;2;) "r2" (type $r1)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/33.print b/tests/snapshots/local/component-model/resources.wast/33.print new file mode 100644 index 0000000000..d92b729213 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/33.print @@ -0,0 +1,8 @@ +(component + (type (;0;) + (component + (export (;0;) "r1" (type (sub resource))) + (export (;1;) "r2" (type (eq 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/34.print b/tests/snapshots/local/component-model/resources.wast/34.print new file mode 100644 index 0000000000..aeb37ae215 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/34.print @@ -0,0 +1,31 @@ +(component $P + (type (;0;) + (component + (import "T" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (param "t" 1))) + (export (;0;) "foo" (func (type 2))) + ) + ) + (import "C1" (component $C1 (;0;) (type 0))) + (type (;1;) + (component + (import "T" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (param "t" 1))) + (import "foo" (func (;0;) (type 2))) + ) + ) + (import "C2" (component $C2 (;1;) (type 1))) + (type $R (;2;) (resource (rep i32))) + (instance $c1 (;0;) (instantiate $C1 + (with "T" (type $R)) + ) + ) + (alias export $c1 "foo" (func (;0;))) + (instance $c2 (;1;) (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func 0)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/35.print b/tests/snapshots/local/component-model/resources.wast/35.print new file mode 100644 index 0000000000..ad6e67dba6 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/35.print @@ -0,0 +1,37 @@ +(component + (type (;0;) + (component + (import "T1" (type (;0;) (sub resource))) + (import "T2" (type (;1;) (sub resource))) + (type (;2;) (own 0)) + (type (;3;) (own 1)) + (type (;4;) (tuple 2 3)) + (type (;5;) (func (param "t" 4))) + (export (;0;) "foo" (func (type 5))) + ) + ) + (import "C1" (component $C1 (;0;) (type 0))) + (type (;1;) + (component + (import "T" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (own 0)) + (type (;3;) (tuple 1 2)) + (type (;4;) (func (param "t" 3))) + (export (;0;) "foo" (func (type 4))) + ) + ) + (import "C2" (component $C2 (;1;) (type 1))) + (type $R (;2;) (resource (rep i32))) + (instance $c1 (;0;) (instantiate $C1 + (with "T1" (type $R)) + (with "T2" (type $R)) + ) + ) + (alias export $c1 "foo" (func (;0;))) + (instance $c2 (;1;) (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func 0)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/37.print b/tests/snapshots/local/component-model/resources.wast/37.print new file mode 100644 index 0000000000..10a8fd0968 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/37.print @@ -0,0 +1,9 @@ +(component + (component $C (;0;) + (type $R (;0;) (resource (rep i32))) + (export (;1;) "R" (type $R)) + ) + (instance $c (;0;) (instantiate $C)) + (alias export $c "R" (type $R (;0;))) + (core func (;0;) (canon resource.drop $R)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/38.print b/tests/snapshots/local/component-model/resources.wast/38.print new file mode 100644 index 0000000000..bdb2e28204 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/38.print @@ -0,0 +1,17 @@ +(component + (component $C1 (;0;) + (import "X" (type (;0;) (sub resource))) + ) + (component $C2 (;1;) + (type (;0;) + (component + (import "X" (type (;0;) (sub resource))) + ) + ) + (import "C1" (component (;0;) (type 0))) + ) + (instance $c (;0;) (instantiate $C2 + (with "C1" (component $C1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/39.print b/tests/snapshots/local/component-model/resources.wast/39.print new file mode 100644 index 0000000000..bf2b9723a6 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/39.print @@ -0,0 +1,27 @@ +(component + (component $C1 (;0;) + (import "X" (type $X (;0;) (sub resource))) + (type (;1;) (own $X)) + (type (;2;) (func (result 1))) + (import "f" (func $f (;0;) (type 2))) + (export (;1;) "g" (func $f)) + ) + (component $C2 (;1;) + (type (;0;) + (component + (import "X" (type (;0;) (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (import "f" (func (;0;) (type 2))) + (type (;3;) (own 0)) + (type (;4;) (func (result 3))) + (export (;1;) "g" (func (type 4))) + ) + ) + (import "C1" (component (;0;) (type 0))) + ) + (instance $c (;0;) (instantiate $C2 + (with "C1" (component $C1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/4.print b/tests/snapshots/local/component-model/resources.wast/4.print new file mode 100644 index 0000000000..f96121c22a --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/4.print @@ -0,0 +1,22 @@ +(component + (type $x (;0;) (resource (rep i32))) + (core func $f1 (;0;) (canon resource.new $x)) + (core func $f2 (;1;) (canon resource.rep $x)) + (core func $f3 (;2;) (canon resource.drop $x)) + (core module $m (;0;) + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32))) + (import "" "f1" (func (;0;) (type 0))) + (import "" "f2" (func (;1;) (type 0))) + (import "" "f3" (func (;2;) (type 1))) + ) + (core instance (;0;) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + ) + (core instance (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/40.print b/tests/snapshots/local/component-model/resources.wast/40.print new file mode 100644 index 0000000000..6d9a7009ce --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/40.print @@ -0,0 +1,25 @@ +(component + (component $C1 (;0;) + (type $X' (;0;) (resource (rep i32))) + (export $X (;1;) "X" (type $X')) + (core func $f (;0;) (canon resource.drop $X)) + (type (;2;) (own $X)) + (type (;3;) (func (param "X" 2))) + (func (;0;) (type 3) (canon lift (core func $f))) + (export (;1;) "f" (func 0)) + ) + (instance $c1 (;0;) (instantiate $C1)) + (component $C2 (;1;) + (import "X" (type $X (;0;) (sub resource))) + (type (;1;) (own $X)) + (type (;2;) (func (param "X" 1))) + (import "f" (func (;0;) (type 2))) + ) + (alias export $c1 "X" (type (;0;))) + (alias export $c1 "f" (func (;0;))) + (instance $c2 (;1;) (instantiate $C2 + (with "X" (type 0)) + (with "f" (func 0)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/42.print b/tests/snapshots/local/component-model/resources.wast/42.print new file mode 100644 index 0000000000..01b51a4ae0 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/42.print @@ -0,0 +1,37 @@ +(component + (component $C1 (;0;) + (type $X (;0;) (resource (rep i32))) + (export $X1 (;1;) "X1" (type $X)) + (export $X2 (;2;) "X2" (type $X)) + (core func $f (;0;) (canon resource.drop $X)) + (type (;3;) (own $X1)) + (type (;4;) (func (param "X" 3))) + (func (;0;) (type 4) (canon lift (core func $f))) + (type (;5;) (own $X2)) + (type (;6;) (func (param "X" 5))) + (func (;1;) (type 6) (canon lift (core func $f))) + (export (;2;) "f1" (func 0)) + (export (;3;) "f2" (func 1)) + ) + (instance $c1 (;0;) (instantiate $C1)) + (component $C2 (;1;) + (import "X" (type $X (;0;) (sub resource))) + (type (;1;) (own $X)) + (type (;2;) (func (param "X" 1))) + (import "f" (func (;0;) (type 2))) + ) + (alias export $c1 "X1" (type (;0;))) + (alias export $c1 "f1" (func (;0;))) + (instance $c2 (;1;) (instantiate $C2 + (with "X" (type 0)) + (with "f" (func 0)) + ) + ) + (alias export $c1 "X2" (type (;1;))) + (alias export $c1 "f2" (func (;1;))) + (instance $c3 (;2;) (instantiate $C2 + (with "X" (type 1)) + (with "f" (func 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/43.print b/tests/snapshots/local/component-model/resources.wast/43.print new file mode 100644 index 0000000000..2ff17b5c73 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/43.print @@ -0,0 +1,37 @@ +(component + (component $C1 (;0;) + (type $X (;0;) (resource (rep i32))) + (export $X1 (;1;) "X1" (type $X)) + (export $X2 (;2;) "X2" (type $X)) + (core func $f (;0;) (canon resource.drop $X)) + (type (;3;) (own $X1)) + (type (;4;) (func (param "X" 3))) + (func (;0;) (type 4) (canon lift (core func $f))) + (type (;5;) (own $X2)) + (type (;6;) (func (param "X" 5))) + (func (;1;) (type 6) (canon lift (core func $f))) + (export (;2;) "f1" (func 0)) + (export (;3;) "f2" (func 1)) + ) + (instance $c1 (;0;) (instantiate $C1)) + (component $C2 (;1;) + (import "X" (type $X (;0;) (sub resource))) + (type (;1;) (own $X)) + (type (;2;) (func (param "X" 1))) + (import "f" (func (;0;) (type 2))) + ) + (alias export $c1 "X1" (type (;0;))) + (alias export $c1 "f2" (func (;0;))) + (instance $c2 (;1;) (instantiate $C2 + (with "X" (type 0)) + (with "f" (func 0)) + ) + ) + (alias export $c1 "X2" (type (;1;))) + (alias export $c1 "f1" (func (;1;))) + (instance $c3 (;2;) (instantiate $C2 + (with "X" (type 1)) + (with "f" (func 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/47.print b/tests/snapshots/local/component-model/resources.wast/47.print new file mode 100644 index 0000000000..618277894f --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/47.print @@ -0,0 +1,13 @@ +(component + (type $x (;0;) (resource (rep i32))) + (component $c (;0;) + (import "x" (type $t (;0;) (sub resource))) + (export (;1;) "y" (type $t)) + ) + (instance $c (;0;) (instantiate $c + (with "x" (type $x)) + ) + ) + (alias export $c "y" (type $x2 (;1;))) + (core func (;0;) (canon resource.rep $x2)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/51.print b/tests/snapshots/local/component-model/resources.wast/51.print new file mode 100644 index 0000000000..e4d762562f --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/51.print @@ -0,0 +1,9 @@ +(component + (type $r' (;0;) (resource (rep i32))) + (export $r (;1;) "r" (type $r')) + (core func $f (;0;) (canon resource.drop $r)) + (type (;2;) (own $r)) + (type (;3;) (func (param "x" 2))) + (func (;0;) (type 3) (canon lift (core func $f))) + (export (;1;) "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/52.print b/tests/snapshots/local/component-model/resources.wast/52.print new file mode 100644 index 0000000000..4b11fca3c9 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/52.print @@ -0,0 +1,13 @@ +(component + (type $r' (;0;) (resource (rep i32))) + (instance $i' (;0;) + (export "r" (type $r')) + ) + (export $i (;1;) "i" (instance $i')) + (alias export $i "r" (type $r (;1;))) + (core func $f (;0;) (canon resource.drop $r)) + (type (;2;) (own $r)) + (type (;3;) (func (param "x" 2))) + (func (;0;) (type 3) (canon lift (core func $f))) + (export (;1;) "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/53.print b/tests/snapshots/local/component-model/resources.wast/53.print new file mode 100644 index 0000000000..102fba049f --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/53.print @@ -0,0 +1,17 @@ +(component + (type $r' (;0;) (resource (rep i32))) + (instance $i' (;0;) + (export "r" (type $r')) + ) + (instance $i2' (;1;) + (export "i" (instance $i')) + ) + (export $i2 (;2;) "i2" (instance $i2')) + (alias export $i2 "i" (instance $i (;3;))) + (alias export $i "r" (type $r (;1;))) + (core func $f (;0;) (canon resource.drop $r)) + (type (;2;) (own $r)) + (type (;3;) (func (param "x" 2))) + (func (;0;) (type 3) (canon lift (core func $f))) + (export (;1;) "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/54.print b/tests/snapshots/local/component-model/resources.wast/54.print new file mode 100644 index 0000000000..5028a69626 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/54.print @@ -0,0 +1,18 @@ +(component + (type $r' (;0;) (resource (rep i32))) + (component $C (;0;) + (import "x" (type $x (;0;) (sub resource))) + (export (;1;) "y" (type $x)) + ) + (instance $c' (;0;) (instantiate $C + (with "x" (type $r')) + ) + ) + (export $c (;1;) "c" (instance $c')) + (alias export $c "y" (type $r (;1;))) + (core func $f (;0;) (canon resource.drop $r)) + (type (;2;) (own $r)) + (type (;3;) (func (param "x" 2))) + (func (;0;) (type 3) (canon lift (core func $f))) + (export (;1;) "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/55.print b/tests/snapshots/local/component-model/resources.wast/55.print new file mode 100644 index 0000000000..ff95441c58 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/55.print @@ -0,0 +1,49 @@ +(component + (type $r' (;0;) (resource (rep i32))) + (component $C (;0;) + (import "x" (type $x (;0;) (sub resource))) + (export (;1;) "y" (type $x)) + ) + (instance $c (;0;) (instantiate $C + (with "x" (type $r')) + ) + ) + (alias export $c "y" (type (;1;))) + (instance $i (;1;) + (export "x" (type 1)) + ) + (component $C2 (;1;) + (type (;0;) + (instance + (type (;0;) + (instance + (export (;0;) "i2" (type (sub resource))) + ) + ) + (export (;0;) "i1" (instance (type 0))) + ) + ) + (import "x" (instance $i (;0;) (type 0))) + (alias export $i "i1" (instance (;1;))) + (alias export 1 "i2" (type (;1;))) + (export (;2;) "y" (type 1)) + ) + (alias export $i "x" (type (;2;))) + (instance $i2 (;2;) + (export "i2" (type 2)) + ) + (instance $i1 (;3;) + (export "i1" (instance $i2)) + ) + (instance $c2 (;4;) (instantiate $C2 + (with "x" (instance $i1)) + ) + ) + (alias export $c2 "y" (type (;3;))) + (export $r (;4;) "x" (type 3)) + (core func $f (;0;) (canon resource.drop $r)) + (type (;5;) (own $r)) + (type (;6;) (func (param "x" 5))) + (func (;0;) (type 6) (canon lift (core func $f))) + (export (;1;) "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/56.print b/tests/snapshots/local/component-model/resources.wast/56.print new file mode 100644 index 0000000000..2bc66c3e85 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/56.print @@ -0,0 +1,27 @@ +(component + (type $r' (;0;) (resource (rep i32))) + (component $C (;0;) + (type (;0;) + (instance + (export (;0;) "t" (type (sub resource))) + ) + ) + (import "x" (instance $x (;0;) (type 0))) + (export (;1;) "y" (instance $x)) + ) + (instance (;0;) + (export "t" (type $r')) + ) + (instance $c' (;1;) (instantiate $C + (with "x" (instance 0)) + ) + ) + (export $c (;2;) "c" (instance $c')) + (alias export $c "y" (instance $y (;3;))) + (alias export $y "t" (type $r (;1;))) + (core func $f (;0;) (canon resource.drop $r)) + (type (;2;) (own $r)) + (type (;3;) (func (param "x" 2))) + (func (;0;) (type 3) (canon lift (core func $f))) + (export (;1;) "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/57.print b/tests/snapshots/local/component-model/resources.wast/57.print new file mode 100644 index 0000000000..04e5d0f993 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/57.print @@ -0,0 +1,32 @@ +(component + (type $i (;0;) + (instance + (export (;0;) "r" (type (sub resource))) + (type (;1;) (own 0)) + (type (;2;) (func (result 1))) + (export (;0;) "f" (func (type 2))) + ) + ) + (import "i1" (instance $i1 (;0;) (type $i))) + (import "i2" (instance $i2 (;1;) (type $i))) + (component $c (;0;) + (import "r" (type $t (;0;) (sub resource))) + (type (;1;) (own $t)) + (type (;2;) (func (result 1))) + (import "f" (func (;0;) (type 2))) + ) + (alias export $i1 "r" (type (;1;))) + (alias export $i1 "f" (func (;0;))) + (instance (;2;) (instantiate $c + (with "r" (type 1)) + (with "f" (func 0)) + ) + ) + (alias export $i2 "r" (type (;2;))) + (alias export $i2 "f" (func (;1;))) + (instance (;3;) (instantiate $c + (with "r" (type 2)) + (with "f" (func 1)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/59.print b/tests/snapshots/local/component-model/resources.wast/59.print new file mode 100644 index 0000000000..e4dbe70571 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/59.print @@ -0,0 +1,28 @@ +(component + (type $t (;0;) (resource (rep i32))) + (component $c (;0;) + (import "x" (type $t (;0;) (sub resource))) + (export (;1;) "y" (type $t)) + ) + (instance $c1 (;0;) (instantiate $c + (with "x" (type $t)) + ) + ) + (instance $c2 (;1;) (instantiate $c + (with "x" (type $t)) + ) + ) + (component $c2 (;1;) + (import "x1" (type $t (;0;) (sub resource))) + (import "x2" (type (;1;) (eq $t))) + (import "x3" (type (;2;) (eq $t))) + ) + (alias export $c1 "y" (type (;1;))) + (alias export $c2 "y" (type (;2;))) + (instance (;2;) (instantiate $c2 + (with "x1" (type $t)) + (with "x2" (type 1)) + (with "x3" (type 2)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/63.print b/tests/snapshots/local/component-model/resources.wast/63.print new file mode 100644 index 0000000000..a0e0b93e46 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/63.print @@ -0,0 +1,35 @@ +(component $A + (type $C (;0;) + (component + (import "x" (type (;0;) (sub resource))) + (type (;1;) + (component + (alias outer 1 0 (type (;0;))) + (import "x" (type (;1;) (eq 0))) + ) + ) + (import "y" (component (;0;) (type 1))) + (export (;1;) "z" (component (type 1))) + ) + ) + (type $t (;1;) (resource (rep i32))) + (alias outer $A $t (type $other-t (;2;))) + (type (;3;) + (instance + (alias outer $A $t (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (type (;4;) + (component + (alias outer $A $t (type (;0;))) + (export (;1;) "t" (type (eq 0))) + ) + ) + (type (;5;) + (component + (alias outer $A $t (type (;0;))) + (import "t" (type (;1;) (eq 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/71.print b/tests/snapshots/local/component-model/resources.wast/71.print new file mode 100644 index 0000000000..8dd02bbcc7 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/71.print @@ -0,0 +1,36 @@ +(component + (component $X (;0;) + (type $t (;0;) (resource (rep i32))) + (export (;1;) "t" (type $t)) + ) + (component $F (;1;) + (type (;0;) + (instance + (export (;0;) "t" (type (sub resource))) + ) + ) + (import "x" (instance $i (;0;) (type 0))) + (alias export $i "t" (type $t (;1;))) + (export (;2;) "t" (type $t)) + ) + (instance $x1 (;0;) (instantiate $X)) + (instance $f1 (;1;) (instantiate $F + (with "x" (instance $x1)) + ) + ) + (instance $f2 (;2;) (instantiate $F + (with "x" (instance $x1)) + ) + ) + (alias export $f1 "t" (type $t1 (;0;))) + (alias export $f2 "t" (type $t2 (;1;))) + (component $T (;2;) + (import "x" (type $x (;0;) (sub resource))) + (import "y" (type (;1;) (eq $x))) + ) + (instance $test (;3;) (instantiate $T + (with "x" (type $t1)) + (with "y" (type $t2)) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/78.print b/tests/snapshots/local/component-model/resources.wast/78.print new file mode 100644 index 0000000000..c011b878c3 --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/78.print @@ -0,0 +1,6 @@ +(component + (import "a" (type $a (;0;) (sub resource))) + (type (;1;) (own $a)) + (type (;2;) (func (result 1))) + (import "[constructor]a" (func (;0;) (type 2))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/79.print b/tests/snapshots/local/component-model/resources.wast/79.print new file mode 100644 index 0000000000..8609a2e30e --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/79.print @@ -0,0 +1,6 @@ +(component + (import "a" (type $a (;0;) (sub resource))) + (type (;1;) (own $a)) + (type (;2;) (func (param "x" u32) (result 1))) + (import "[constructor]a" (func (;0;) (type 2))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/90.print b/tests/snapshots/local/component-model/resources.wast/90.print new file mode 100644 index 0000000000..6df38e456d --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/90.print @@ -0,0 +1,6 @@ +(component + (import "a" (type $T (;0;) (sub resource))) + (type (;1;) (borrow $T)) + (type (;2;) (func (param "self" 1))) + (import "[method]a.b" (func (;0;) (type 2))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/resources.wast/98.print b/tests/snapshots/local/component-model/resources.wast/98.print new file mode 100644 index 0000000000..1ecbe067eb --- /dev/null +++ b/tests/snapshots/local/component-model/resources.wast/98.print @@ -0,0 +1,5 @@ +(component + (import "a" (type (;0;) (sub resource))) + (type (;1;) (func)) + (import "[static]a.b" (func (;0;) (type 1))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/start.wast/4.print b/tests/snapshots/local/component-model/start.wast/4.print new file mode 100644 index 0000000000..5141103b25 --- /dev/null +++ b/tests/snapshots/local/component-model/start.wast/4.print @@ -0,0 +1,7 @@ +(component + (type (;0;) (func (param "z" string) (param "a" string))) + (import "a" (func $f (;0;) (type 0))) + (import "b" (value $v (;0;) string)) + (import "c" (value $v2 (;1;) string)) + (start $f (value $v) (value $v2)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/start.wast/5.print b/tests/snapshots/local/component-model/start.wast/5.print new file mode 100644 index 0000000000..f55f70d077 --- /dev/null +++ b/tests/snapshots/local/component-model/start.wast/5.print @@ -0,0 +1,6 @@ +(component + (type (;0;) (func (result string))) + (import "a" (func $f (;0;) (type 0))) + (start $f (result (value (;0;)))) + (export (;1;) "b" (value 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/start.wast/6.print b/tests/snapshots/local/component-model/start.wast/6.print new file mode 100644 index 0000000000..2bddfe6359 --- /dev/null +++ b/tests/snapshots/local/component-model/start.wast/6.print @@ -0,0 +1,9 @@ +(component + (type (;0;) (func (param "a" string) (param "b" string) (result "c" s32) (result "d" s32))) + (import "a" (func $f (;0;) (type 0))) + (import "b" (value $v (;0;) string)) + (import "c" (value $v2 (;1;) string)) + (start $f (value $v) (value $v2) (result (value (;2;))) (result (value (;3;)))) + (export (;4;) "d" (value 2)) + (export (;5;) "e" (value 3)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/string.wast/0.print b/tests/snapshots/local/component-model/string.wast/0.print new file mode 100644 index 0000000000..6f48a4a27b --- /dev/null +++ b/tests/snapshots/local/component-model/string.wast/0.print @@ -0,0 +1,39 @@ +(component + (import "name" (value $name (;0;) string)) + (core type (;0;) + (module + (export "memory" (memory 1)) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (export "realloc" (func (type 0))) + (type (;1;) (func (param i32 i32 i32))) + (export "free" (func (type 1))) + (type (;2;) (func (param i32 i32 i32 i32) (result i32))) + (export "canonical_abi_realloc" (func (type 2))) + ) + ) + (import "libc" (core module $Libc (;0;) (type 0))) + (core instance $libc (;0;) (instantiate $Libc)) + (core module $Main (;1;) + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i32))) + (import "libc" "memory" (memory (;0;) 1)) + (func (;0;) (type 0) (param i32 i32) (result i32) + unreachable + ) + (func (;1;) (type 1) (param i32)) + (export "start" (func 0)) + (export "start-post-return" (func 1)) + ) + (core instance $main (;1;) (instantiate $Main + (with "libc" (instance $libc)) + ) + ) + (alias core export $main "start" (core func $main_func (;0;))) + (type (;0;) (func (param "p1" string) (result string))) + (alias core export $libc "memory" (core memory (;0;))) + (alias core export $libc "canonical_abi_realloc" (core func (;1;))) + (alias core export $main "start-post-return" (core func (;2;))) + (func $start (;0;) (type 0) (canon lift (core func $main_func) (memory 0) (realloc 1) (post-return 2))) + (start $start (value $name) (result (value (;1;)))) + (export (;2;) "greeting" (value 1)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/11.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/11.print new file mode 100644 index 0000000000..dbc5d0a4f1 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/11.print @@ -0,0 +1,14 @@ +(component + (type (;0;) (tuple u32)) + (type $t1 (;1;) (tuple 0)) + (export (;2;) "t1" (type $t1)) + (type (;3;) (list u8)) + (type (;4;) (list u32)) + (type (;5;) (option string)) + (type (;6;) (result 4 (error 5))) + (type (;7;) (tuple 3 6)) + (type $t2 (;8;) (option 7)) + (export (;9;) "t2" (type $t2)) + (type $t3 (;10;) u32) + (export (;11;) "t3" (type $t3)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/12.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/12.print new file mode 100644 index 0000000000..5e020ad7bc --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/12.print @@ -0,0 +1,6 @@ +(component + (type $t' (;0;) (record (field "f" u32))) + (export $t (;1;) "t" (type $t')) + (type $t2 (;2;) (record (field "x" $t))) + (export (;3;) "t2" (type $t2)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/14.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/14.print new file mode 100644 index 0000000000..cf0a54b235 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/14.print @@ -0,0 +1,6 @@ +(component + (type $t (;0;) (record (field "f" u32))) + (import "t" (type $t' (;1;) (eq $t))) + (type $t2 (;2;) (record (field "f" $t'))) + (import "x" (type (;3;) (eq $t2))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/19.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/19.print new file mode 100644 index 0000000000..2d5760f067 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/19.print @@ -0,0 +1,7 @@ +(component + (type $t (;0;) (record (field "f" u32))) + (type $f (;1;) (record (field "t" $t))) + (instance (;0;) + (export "f" (type $f)) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/24.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/24.print new file mode 100644 index 0000000000..743400253a --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/24.print @@ -0,0 +1,18 @@ +(component + (type $t' (;0;) (record (field "f" u32))) + (instance $i' (;0;) + (export "t" (type $t')) + ) + (export $i (;1;) "i" (instance $i')) + (alias export $i "t" (type $t (;1;))) + (core module $m (;0;) + (type (;0;) (func (param i32))) + (func $f (;0;) (type 0) (param i32)) + (export "f" (func $f)) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;2;) (func (param "f" $t))) + (alias core export $i "f" (core func (;0;))) + (func $f (;0;) (type 2) (canon lift (core func 0))) + (export (;1;) "f" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/25.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/25.print new file mode 100644 index 0000000000..e316f360cb --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/25.print @@ -0,0 +1,19 @@ +(component + (component $C (;0;) + (type $t (;0;) (record (field "f" u32))) + (export (;1;) "t" (type $t)) + ) + (instance $i' (;0;) (instantiate $C)) + (export $i (;1;) "i" (instance $i')) + (alias export $i "t" (type $t (;0;))) + (core module $m (;0;) + (type (;0;) (func (param i32))) + (func $f (;0;) (type 0) (param i32)) + (export "f" (func $f)) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;1;) (func (param "f" $t))) + (alias core export $i "f" (core func (;0;))) + (func $f (;0;) (type 1) (canon lift (core func 0))) + (export (;1;) "f" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/26.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/26.print new file mode 100644 index 0000000000..f818e93274 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/26.print @@ -0,0 +1,15 @@ +(component + (type $t (;0;) (record (field "f" u32))) + (core module $m (;0;) + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param i32)) + (export "f" (func 0)) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;1;) (func (param "x" $t))) + (alias core export $i "f" (core func (;0;))) + (func $f (;0;) (type 1) (canon lift (core func 0))) + (export $t' (;2;) "t" (type $t)) + (type (;3;) (func (param "x" $t'))) + (export (;1;) "f" (func $f) (func (type 3))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/28.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/28.print new file mode 100644 index 0000000000..18224ea676 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/28.print @@ -0,0 +1,5 @@ +(component + (type $t1 (;0;) (record (field "f" u32))) + (import "t1" (type $t2 (;1;) (eq $t1))) + (export (;2;) "e-t1" (type $t2)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/29.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/29.print new file mode 100644 index 0000000000..865cd64603 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/29.print @@ -0,0 +1,7 @@ +(component + (type $t1 (;0;) (record (field "f" u32))) + (import "t1" (type $t2 (;1;) (eq $t1))) + (type (;2;) (func (result $t2))) + (import "i" (func $f (;0;) (type 2))) + (export (;1;) "e-i" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/32.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/32.print new file mode 100644 index 0000000000..efd6175dbd --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/32.print @@ -0,0 +1,31 @@ +(component + (type $c (;0;) + (component) + ) + (type (;1;) + (component + (alias outer 1 $c (type (;0;))) + (import "c" (component (;0;) (type 0))) + ) + ) + (component (;0;) + (alias outer 1 $c (type $c (;0;))) + (import "c" (component (;0;) (type $c))) + ) + (type $i (;2;) + (instance) + ) + (type (;3;) + (component + (alias outer 1 $i (type (;0;))) + (import "c" (instance (;0;) (type 0))) + ) + ) + (type $r (;4;) (resource (rep i32))) + (type (;5;) + (component + (alias outer 1 $r (type (;0;))) + (import "r" (type (;1;) (eq 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/33.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/33.print new file mode 100644 index 0000000000..28a28baaaa --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/33.print @@ -0,0 +1,5 @@ +(component + (type (;0;) (func)) + (import "r" (func $r (;0;) (type 0))) + (export (;1;) "r2" (func $r)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/34.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/34.print new file mode 100644 index 0000000000..dbc77a83b9 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/34.print @@ -0,0 +1,5 @@ +(component + (type $t (;0;) (record (field "f" u32))) + (import "r" (type $r (;1;) (eq $t))) + (export (;2;) "r2" (type $r)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/35.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/35.print new file mode 100644 index 0000000000..e5c7bf1cb9 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/35.print @@ -0,0 +1,7 @@ +(component + (type (;0;) + (instance) + ) + (import "r" (instance $r (;0;) (type 0))) + (export (;1;) "r2" (instance $r)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/36.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/36.print new file mode 100644 index 0000000000..7682001d91 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/36.print @@ -0,0 +1,4 @@ +(component + (import "r" (type $r (;0;) (sub resource))) + (export (;1;) "r2" (type $r)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/38.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/38.print new file mode 100644 index 0000000000..fee1b8105d --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/38.print @@ -0,0 +1,9 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "f" u32))) + (type (;1;) (func (param "x" 0))) + (export (;0;) "f" (func (type 1))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/40.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/40.print new file mode 100644 index 0000000000..bc70837e42 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/40.print @@ -0,0 +1,21 @@ +(component $C + (type (;0;) + (instance + (type (;0;) (record (field "f" u32))) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "baz" 1))) + (export (;3;) "bar" (type (eq 2))) + ) + ) + (import "foo" (instance $i (;0;) (type 0))) + (alias export $i "bar" (type $bar (;1;))) + (type (;2;) + (instance + (alias outer $C $bar (type (;0;))) + (export (;1;) "bar" (type (eq 0))) + (type (;2;) (func (result 1))) + (export (;0;) "a" (func (type 2))) + ) + ) + (import "bar" (instance (;1;) (type 2))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/41.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/41.print new file mode 100644 index 0000000000..f729c15db5 --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/41.print @@ -0,0 +1,16 @@ +(component + (type $r' (;0;) (record (field "f" u32))) + (import "r" (type $r (;1;) (eq $r'))) + (component $C (;0;) + (type $r' (;0;) (record (field "f" u32))) + (import "r" (type $r (;1;) (eq $r'))) + (type $r2' (;2;) (record (field "r" $r))) + (export (;3;) "r2" (type $r2')) + ) + (instance $c (;0;) (instantiate $C + (with "r" (type $r)) + ) + ) + (alias export $c "r2" (type (;2;))) + (export (;3;) "r2" (type 2)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/type-export-restrictions.wast/46.print b/tests/snapshots/local/component-model/type-export-restrictions.wast/46.print new file mode 100644 index 0000000000..da10c90bde --- /dev/null +++ b/tests/snapshots/local/component-model/type-export-restrictions.wast/46.print @@ -0,0 +1,43 @@ +(component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1))) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component (;0;) + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1))) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component (;0;) + (type (;0;) (enum "qux")) + (import "import-type-baz" (type (;1;) (eq 0))) + (type (;2;) (record (field "bar" 1))) + (import "import-type-bar" (type (;3;) (eq 2))) + (export (;4;) "foo" (type 3)) + ) + (alias export 0 "baz" (type (;1;))) + (alias export 0 "foo" (type (;2;))) + (instance (;1;) (instantiate 0 + (with "import-type-baz" (type 1)) + (with "import-type-bar" (type 2)) + ) + ) + (export (;2;) (interface "demo:component/types") (instance 1)) + ) + (instance (;1;) (instantiate 0 + (with "demo:component/types" (instance 0)) + ) + ) + (alias export 1 "demo:component/types" (instance (;2;))) + (export (;3;) (interface "demo:component/types") (instance 2)) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/types.wast/29.print b/tests/snapshots/local/component-model/types.wast/29.print new file mode 100644 index 0000000000..766e363cee --- /dev/null +++ b/tests/snapshots/local/component-model/types.wast/29.print @@ -0,0 +1,5 @@ +(component + (type (;0;) (list u8)) + (type (;1;) (tuple 0 u32)) + (type $t (;2;) (func (result 1))) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/types.wast/30.print b/tests/snapshots/local/component-model/types.wast/30.print new file mode 100644 index 0000000000..320b26784e --- /dev/null +++ b/tests/snapshots/local/component-model/types.wast/30.print @@ -0,0 +1,9 @@ +(component $C + (core type $t (;0;) (func)) + (core type (;1;) + (module + (alias outer $C $t (type (;0;))) + (import "" "" (func (type 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/types.wast/31.print b/tests/snapshots/local/component-model/types.wast/31.print new file mode 100644 index 0000000000..e4203ea370 --- /dev/null +++ b/tests/snapshots/local/component-model/types.wast/31.print @@ -0,0 +1,11 @@ +(component $C + (component $C2 (;0;) + (core type $t (;0;) (func)) + (core type (;1;) + (module + (alias outer $C2 $t (type (;0;))) + (import "" "" (func (type 0))) + ) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/types.wast/33.print b/tests/snapshots/local/component-model/types.wast/33.print new file mode 100644 index 0000000000..89831c36c9 --- /dev/null +++ b/tests/snapshots/local/component-model/types.wast/33.print @@ -0,0 +1,8 @@ +(component + (type (;0;) + (instance + (type (;0;) string) + (export (;1;) "a" (type (eq 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/types.wast/34.print b/tests/snapshots/local/component-model/types.wast/34.print new file mode 100644 index 0000000000..27e740b64b --- /dev/null +++ b/tests/snapshots/local/component-model/types.wast/34.print @@ -0,0 +1,9 @@ +(component + (type (;0;) + (component + (type (;0;) string) + (import "a" (type (;1;) (eq 0))) + (export (;2;) "b" (type (eq 0))) + ) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/component-model/virtualize.wast/0.print b/tests/snapshots/local/component-model/virtualize.wast/0.print new file mode 100644 index 0000000000..9da97c9cb4 --- /dev/null +++ b/tests/snapshots/local/component-model/virtualize.wast/0.print @@ -0,0 +1,171 @@ +(component + (core module $libc (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (memory (;0;) 0) + (export "mem" (memory 0)) + (export "realloc" (func 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (component $child (;0;) + (type (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (func (param "count" u32) (result 0))) + (export (;0;) "read" (func (type 1))) + (type (;2;) (list u8)) + (type (;3;) (func (param "bytes" 2) (result u32))) + (export (;1;) "write" (func (type 3))) + ) + ) + (import "wasi-file" (instance $wasi-file (;0;) (type 0))) + (alias outer 1 $libc (core module $libc (;0;))) + (core instance $libc (;0;) (instantiate $libc)) + (core module $m (;1;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func)) + (import "wasi-file" "read" (func $read (;0;) (type 0))) + (func $play (;1;) (type 1) + unreachable + ) + (export "play" (func $play)) + ) + (alias export $wasi-file "read" (func (;0;))) + (alias core export $libc "mem" (core memory (;0;))) + (alias core export $libc "realloc" (core func (;0;))) + (core func $wasi_file_read (;1;) (canon lower (func 0) (memory 0) (realloc 0))) + (core instance (;1;) + (export "read" (func $wasi_file_read)) + ) + (core instance $i (;2;) (instantiate $m + (with "wasi-file" (instance 1)) + ) + ) + (type (;1;) (func)) + (alias core export $i "play" (core func (;2;))) + (func (;1;) (type 1) (canon lift (core func 2))) + (export (;2;) "play" (func 1)) + ) + (component $virtualize (;1;) + (type (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (func (param "len" u32) (result 0))) + (export (;0;) "read" (func (type 1))) + (type (;2;) (list u8)) + (type (;3;) (func (param "buf" 2) (result u32))) + (export (;1;) "write" (func (type 3))) + ) + ) + (import "wasi-file" (instance $wasi-file (;0;) (type 0))) + (alias export $wasi-file "read" (func (;0;))) + (export (;1;) "read" (func 0)) + (alias export $wasi-file "write" (func (;2;))) + (export (;3;) "write" (func 2)) + ) + (component (;2;) + (type $WasiFile (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (func (param "len" u32) (result 0))) + (export (;0;) "read" (func (type 1))) + (type (;2;) (list u8)) + (type (;3;) (func (param "buf" 2) (result u32))) + (export (;1;) "write" (func (type 3))) + ) + ) + (import "wasi-file" (instance $real-wasi (;0;) (type $WasiFile))) + (type (;1;) + (component + (alias outer 1 $WasiFile (type (;0;))) + (import "wasi-file" (instance (;0;) (type 0))) + (type (;1;) (list u8)) + (type (;2;) (func (param "len" u32) (result 1))) + (export (;0;) "read" (func (type 2))) + (type (;3;) (list u8)) + (type (;4;) (func (param "buf" 3) (result u32))) + (export (;1;) "write" (func (type 4))) + ) + ) + (import "virtualize" (component $VIRTUALIZE (;0;) (type 1))) + (type (;2;) + (component + (alias outer 1 $WasiFile (type (;0;))) + (import "wasi-file" (instance (;0;) (type 0))) + (type (;1;) (func)) + (export (;0;) "play" (func (type 1))) + ) + ) + (import "child" (component $CHILD (;1;) (type 2))) + (instance $virt-wasi (;1;) (instantiate $VIRTUALIZE + (with "wasi-file" (instance $real-wasi)) + ) + ) + (instance $child (;2;) (instantiate $CHILD + (with "wasi-file" (instance $virt-wasi)) + ) + ) + (alias export $child "play" (func (;0;))) + (export (;1;) "work" (func 0)) + ) + (component (;3;) + (type $WasiFile (;0;) + (instance + (type (;0;) (list u8)) + (type (;1;) (func (param "len" u32) (result 0))) + (export (;0;) "read" (func (type 1))) + (type (;2;) (list u8)) + (type (;3;) (func (param "buf" 2) (result u32))) + (export (;1;) "write" (func (type 3))) + ) + ) + (import "wasi-file" (instance $real-wasi (;0;) (type $WasiFile))) + (alias outer 1 $libc (core module $libc (;0;))) + (core instance $libc (;0;) (instantiate $libc)) + (core module $CHILD (;1;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func)) + (import "wasi-file" "read" (func $wasi-file (;0;) (type 0))) + (func $play (;1;) (type 1) + unreachable + ) + (export "play" (func $play)) + ) + (core module $VIRTUALIZE (;2;) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32 i32))) + (import "wasi-file" "read" (func (;0;) (type 0))) + (func (;1;) (type 0) (param i32 i32) + unreachable + ) + (func (;2;) (type 1) (param i32 i32 i32) + unreachable + ) + (export "read" (func 1)) + (export "write" (func 2)) + ) + (alias export $real-wasi "read" (func (;0;))) + (alias core export $libc "mem" (core memory (;0;))) + (alias core export $libc "realloc" (core func (;0;))) + (core func $real-wasi-read (;1;) (canon lower (func 0) (memory 0) (realloc 0))) + (core instance (;1;) + (export "read" (func $real-wasi-read)) + ) + (core instance $virt-wasi (;2;) (instantiate $VIRTUALIZE + (with "wasi-file" (instance 1)) + ) + ) + (core instance $child (;3;) (instantiate $CHILD + (with "wasi-file" (instance $virt-wasi)) + ) + ) + (type (;1;) (func)) + (alias core export $child "play" (core func (;2;))) + (alias core export $libc "mem" (core memory (;1;))) + (alias core export $libc "realloc" (core func (;3;))) + (func (;1;) (type 1) (canon lift (core func 2) (memory 1) (realloc 3))) + (export (;2;) "work" (func 1)) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/convert-sat.wat.print b/tests/snapshots/local/convert-sat.wat.print new file mode 100644 index 0000000000..5b3dd4e3b6 --- /dev/null +++ b/tests/snapshots/local/convert-sat.wat.print @@ -0,0 +1,29 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x0p+0 (;=0;) + i32.trunc_sat_f32_s + drop + f32.const 0x0p+0 (;=0;) + i32.trunc_sat_f32_u + drop + f64.const 0x0p+0 (;=0;) + i32.trunc_sat_f64_s + drop + f64.const 0x0p+0 (;=0;) + i32.trunc_sat_f64_u + drop + f32.const 0x0p+0 (;=0;) + i64.trunc_sat_f32_s + drop + f32.const 0x0p+0 (;=0;) + i64.trunc_sat_f32_u + drop + f64.const 0x0p+0 (;=0;) + i64.trunc_sat_f64_s + drop + f64.const 0x0p+0 (;=0;) + i64.trunc_sat_f64_u + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/dummy.wat.print b/tests/snapshots/local/dummy.wat.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/local/dummy.wat.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/0.print b/tests/snapshots/local/dylink0.wast/0.print new file mode 100644 index 0000000000..c9739591a0 --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/0.print @@ -0,0 +1,3 @@ +(module + (@dylink.0) +) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/1.print b/tests/snapshots/local/dylink0.wast/1.print new file mode 100644 index 0000000000..6684feb7e5 --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/1.print @@ -0,0 +1,4 @@ +(module + (@dylink.0) + (@dylink.0) +) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/2.print b/tests/snapshots/local/dylink0.wast/2.print new file mode 100644 index 0000000000..94a6185343 --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/2.print @@ -0,0 +1,8 @@ +(module + (@dylink.0 + (mem-info) + (mem-info (memory 1 1)) + (mem-info (table 1 1)) + (mem-info (memory 1 1) (table 1 1)) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/3.print b/tests/snapshots/local/dylink0.wast/3.print new file mode 100644 index 0000000000..79d2bf46c0 --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/3.print @@ -0,0 +1,7 @@ +(module + (@dylink.0 + (needed) + (needed "a" "b") + (needed "a") + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/4.print b/tests/snapshots/local/dylink0.wast/4.print new file mode 100644 index 0000000000..5cc8a7591b --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/4.print @@ -0,0 +1,6 @@ +(module + (@dylink.0 + (export-info "a") + (export-info "b" binding-weak) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/5.print b/tests/snapshots/local/dylink0.wast/5.print new file mode 100644 index 0000000000..d80348c124 --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/5.print @@ -0,0 +1,6 @@ +(module + (@dylink.0 + (import-info "a" "a") + (import-info "b" "b" binding-weak) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/6.print b/tests/snapshots/local/dylink0.wast/6.print new file mode 100644 index 0000000000..3777c848d8 --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/6.print @@ -0,0 +1,9 @@ +(module + (@dylink.0 + (mem-info (memory 1 1)) + (needed "a" "b") + (export-info "a") + (import-info "a" "a") + (import-info "b" "b" binding-weak) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/7.print b/tests/snapshots/local/dylink0.wast/7.print new file mode 100644 index 0000000000..c1422cae64 --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/7.print @@ -0,0 +1,12 @@ +(module + (@dylink.0 + (export-info "a") + (import-info "a" "a") + (export-info "a") + (export-info "a") + (import-info "a" "a") + (import-info "a" "a") + (export-info "a") + (import-info "a" "a") + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/dylink0.wast/8.print b/tests/snapshots/local/dylink0.wast/8.print new file mode 100644 index 0000000000..c11f43cbbd --- /dev/null +++ b/tests/snapshots/local/dylink0.wast/8.print @@ -0,0 +1,7 @@ +(module + (@dylink.0 + (export-info "a" binding-weak binding-local visibility-hidden undefined exported explicit-name no-strip 0xffffff08) + (export-info "a" binding-local) + (export-info "a" binding-weak binding-local undefined) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/elem.wast/0.print b/tests/snapshots/local/elem.wast/0.print new file mode 100644 index 0000000000..8a1d5a60c6 --- /dev/null +++ b/tests/snapshots/local/elem.wast/0.print @@ -0,0 +1,8 @@ +(module + (table (;0;) 1 funcref) + (elem (;0;) (i32.const 0) funcref) + (elem (;1;) (i32.const 0) funcref) + (elem (;2;) (offset i32.const 0 i32.const 0 i32.add) funcref) + (elem (;3;) (offset i32.const 0 i32.const 0 i32.add) funcref) + (elem (;4;) (offset i32.const 0 i32.const 0 i32.add) funcref) +) \ No newline at end of file diff --git a/tests/snapshots/local/empty-elem.wast/0.print b/tests/snapshots/local/empty-elem.wast/0.print new file mode 100644 index 0000000000..ee4a9b98d6 --- /dev/null +++ b/tests/snapshots/local/empty-elem.wast/0.print @@ -0,0 +1,12 @@ +(module + (table (;0;) 1 funcref) + (table (;1;) 1 funcref) + (elem (;0;) (i32.const 0) func) + (elem (;1;) func) + (elem (;2;) (table 1) (i32.const 0) func) + (elem (;3;) declare func) + (elem (;4;) (i32.const 0) funcref) + (elem (;5;) funcref) + (elem (;6;) (table 1) (i32.const 0) funcref) + (elem (;7;) declare funcref) +) \ No newline at end of file diff --git a/tests/snapshots/local/exception-handling.wast/0.print b/tests/snapshots/local/exception-handling.wast/0.print new file mode 100644 index 0000000000..52d4eb2d95 --- /dev/null +++ b/tests/snapshots/local/exception-handling.wast/0.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func (param i32 i64))) + (type (;1;) (func (param i32))) + (type (;2;) (func)) + (type (;3;) (func (result i32 i64))) + (type (;4;) (func (param i32) (result i32 i64))) + (import "m" "t" (tag (;0;) (type 0) (param i32 i64))) + (func $check-throw (;0;) (type 2) + i32.const 1 + i64.const 2 + throw 0 + ) + (func $check-try-catch-rethrow (;1;) (type 2) + try (type 3) (result i32 i64) ;; label = @1 + call $check-throw + unreachable + catch 0 + catch 1 + i64.const 2 + catch_all + rethrow 0 (;@1;) + end + drop + drop + ) + (func $try-with-params (;2;) (type 2) + i32.const 0 + try (type 4) (param i32) (result i32 i64) ;; label = @1 + i32.popcnt + drop + call $check-throw + unreachable + catch 1 + i64.const 2 + catch_all + i32.const 0 + i64.const 2 + end + drop + drop + ) + (tag (;1;) (type 1) (param i32)) +) \ No newline at end of file diff --git a/tests/snapshots/local/externref-elem-segment.wast/0.print b/tests/snapshots/local/externref-elem-segment.wast/0.print new file mode 100644 index 0000000000..bb946b9e60 --- /dev/null +++ b/tests/snapshots/local/externref-elem-segment.wast/0.print @@ -0,0 +1,4 @@ +(module + (elem $a (;0;) externref) + (elem $b (;1;) externref (ref.null extern)) +) \ No newline at end of file diff --git a/tests/snapshots/local/floate2.wat.print b/tests/snapshots/local/floate2.wat.print new file mode 100644 index 0000000000..d5134bea23 --- /dev/null +++ b/tests/snapshots/local/floate2.wat.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-148 (;=0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-reference-structural-matching.wat.print b/tests/snapshots/local/function-reference-structural-matching.wat.print new file mode 100644 index 0000000000..37145f53d1 --- /dev/null +++ b/tests/snapshots/local/function-reference-structural-matching.wat.print @@ -0,0 +1,14 @@ +(module + (type $t1 (;0;) (func)) + (type $t2_a (;1;) (func (param (ref 0) (ref 0)))) + (type $t2_b (;2;) (func (param (ref 0) (ref 0)))) + (type (;3;) (func (param (ref 1)))) + (type (;4;) (func (param (ref 2)))) + (func $f (;0;) (type 3) (param (ref 1)) + nop + ) + (func $g (;1;) (type 4) (param (ref 2)) + local.get 0 + call $f + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/0.print b/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/0.print new file mode 100644 index 0000000000..534e7f5dbd --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/0.print @@ -0,0 +1,52 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + block $l (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + i32.const -1 + return + end + call_ref $t + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + block $l (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + i32.const -1 + return + end + call_ref $t + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + block $l ;; label = @1 + unreachable + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/5.print b/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/5.print new file mode 100644 index 0000000000..e8ef804e8e --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/5.print @@ -0,0 +1,30 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref null 0)))) + (type (;2;) (func (param funcref))) + (type (;3;) (func (param externref))) + (func (;0;) (type 1) (param $r (ref null 0)) + block (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) + (func (;1;) (type 2) (param $r funcref) + block (result (ref func)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) + (func (;2;) (type 3) (param $r externref) + block (result (ref extern)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/6.print b/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/6.print new file mode 100644 index 0000000000..e370706479 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/br_on_non_null.wast/6.print @@ -0,0 +1,32 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 (ref null 0)) (result i32))) + (type (;2;) (func (result i32 (ref 0)))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $a (;1;) (type 1) (param $n i32) (param $r (ref null 0)) (result i32) + block $l (type 2) (result i32 (ref 0)) ;; label = @1 + local.get $n + local.get $r + br_on_non_null 0 (;@1;) + return + end + call_ref $t + ) + (func (;2;) (type $t) (param $n i32) (result i32) + local.get $n + ref.null 0 + call $a + ) + (func (;3;) (type $t) (param $n i32) (result i32) + local.get $n + ref.func $f + call $a + ) + (export "args-null" (func 2)) + (export "args-f" (func 3)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/br_on_null.wast/0.print b/tests/snapshots/local/function-references/call_ref/br_on_null.wast/0.print new file mode 100644 index 0000000000..fdfd989b2e --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/br_on_null.wast/0.print @@ -0,0 +1,52 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + block $l ;; label = @1 + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + block $l ;; label = @1 + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + block $l ;; label = @1 + unreachable + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/br_on_null.wast/5.print b/tests/snapshots/local/function-references/call_ref/br_on_null.wast/5.print new file mode 100644 index 0000000000..4dc0b2d305 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/br_on_null.wast/5.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref null 0)))) + (type (;2;) (func (param funcref))) + (type (;3;) (func (param externref))) + (func (;0;) (type 1) (param $r (ref null 0)) + local.get $r + br_on_null 0 (;@0;) + drop + ) + (func (;1;) (type 2) (param $r funcref) + local.get $r + br_on_null 0 (;@0;) + drop + ) + (func (;2;) (type 3) (param $r externref) + local.get $r + br_on_null 0 (;@0;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/br_on_null.wast/6.print b/tests/snapshots/local/function-references/call_ref/br_on_null.wast/6.print new file mode 100644 index 0000000000..8be1657f4f --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/br_on_null.wast/6.print @@ -0,0 +1,31 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 (ref null 0)) (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $a (;1;) (type 1) (param $n i32) (param $r (ref null 0)) (result i32) + block $l (result i32) ;; label = @1 + local.get $n + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + ) + (func (;2;) (type $t) (param $n i32) (result i32) + local.get $n + ref.null 0 + call $a + ) + (func (;3;) (type $t) (param $n i32) (result i32) + local.get $n + ref.func $f + call $a + ) + (export "args-null" (func 2)) + (export "args-f" (func 3)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/call_ref.wast/0.print b/tests/snapshots/local/function-references/call_ref/call_ref.wast/0.print new file mode 100644 index 0000000000..b5339eab8e --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/call_ref.wast/0.print @@ -0,0 +1,133 @@ +(module + (type $ii (;0;) (func (param i32) (result i32))) + (type $ll (;1;) (func (param i64) (result i64))) + (type $lll (;2;) (func (param i64 i64) (result i64))) + (type (;3;) (func (param (ref 0) i32) (result i32))) + (type (;4;) (func (result i32))) + (func $apply (;0;) (type 3) (param $f (ref 0)) (param $x i32) (result i32) + local.get $x + local.get $f + call_ref $ii + ) + (func $f (;1;) (type $ii) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $g (;2;) (type $ii) (param i32) (result i32) + i32.const 0 + local.get 0 + i32.sub + ) + (func (;3;) (type $ii) (param $x i32) (result i32) + (local $rf (ref null 0)) (local $rg (ref null 0)) + ref.func $f + local.set $rf + ref.func $g + local.set $rg + local.get $x + local.get $rf + call_ref $ii + local.get $rg + call_ref $ii + ) + (func (;4;) (type 4) (result i32) + i32.const 1 + ref.null 0 + call_ref $ii + ) + (func $fac (;5;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + local.get 0 + i64.const 1 + i64.sub + global.get $fac + call_ref $ll + i64.mul + end + ) + (func $fac-acc (;6;) (type $lll) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + global.get $fac-acc + call_ref $lll + end + ) + (func $fib (;7;) (type $ll) (param i64) (result i64) + local.get 0 + i64.const 1 + i64.le_u + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + i64.const 2 + i64.sub + global.get $fib + call_ref $ll + local.get 0 + i64.const 1 + i64.sub + global.get $fib + call_ref $ll + i64.add + end + ) + (func $even (;8;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 44 + else + local.get 0 + i64.const 1 + i64.sub + global.get $odd + call_ref $ll + end + ) + (func $odd (;9;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 99 + else + local.get 0 + i64.const 1 + i64.sub + global.get $even + call_ref $ll + end + ) + (global $fac (;0;) (ref 1) ref.func $fac) + (global $fac-acc (;1;) (ref 2) ref.func $fac-acc) + (global $fib (;2;) (ref 1) ref.func $fib) + (global $even (;3;) (ref 1) ref.func $even) + (global $odd (;4;) (ref 1) ref.func $odd) + (export "run" (func 3)) + (export "null" (func 4)) + (export "fac" (func $fac)) + (export "fac-acc" (func $fac-acc)) + (export "fib" (func $fib)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) declare func $f $g) + (elem (;1;) declare func $fac) + (elem (;2;) declare func $fac-acc) + (elem (;3;) declare func $fib) + (elem (;4;) declare func $even $odd) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/call_ref.wast/25.print b/tests/snapshots/local/function-references/call_ref/call_ref.wast/25.print new file mode 100644 index 0000000000..9b733d4659 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/call_ref.wast/25.print @@ -0,0 +1,9 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (result i32))) + (func (;0;) (type 1) (result i32) + unreachable + call_ref $t + ) + (export "unreachable" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/call_ref.wast/27.print b/tests/snapshots/local/function-references/call_ref/call_ref.wast/27.print new file mode 100644 index 0000000000..3f690c6fbc --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/call_ref.wast/27.print @@ -0,0 +1,14 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + ref.func $f + call_ref $t + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/call_ref.wast/29.print b/tests/snapshots/local/function-references/call_ref/call_ref.wast/29.print new file mode 100644 index 0000000000..89b7ecc289 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/call_ref.wast/29.print @@ -0,0 +1,17 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + i32.const 0 + ref.func $f + call_ref $t + drop + i32.const 0 + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/ref_as_non_null.wast/0.print b/tests/snapshots/local/function-references/call_ref/ref_as_non_null.wast/0.print new file mode 100644 index 0000000000..d1387d3fa2 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/ref_as_non_null.wast/0.print @@ -0,0 +1,40 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + local.get $r + ref.as_non_null + call_ref $t + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + local.get $r + ref.as_non_null + call_ref $t + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + unreachable + ref.as_non_null + call $nn + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/ref_as_non_null.wast/6.print b/tests/snapshots/local/function-references/call_ref/ref_as_non_null.wast/6.print new file mode 100644 index 0000000000..84c6c3f322 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/ref_as_non_null.wast/6.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref 0)))) + (type (;2;) (func (param (ref func)))) + (type (;3;) (func (param (ref extern)))) + (func (;0;) (type 1) (param $r (ref 0)) + local.get $r + ref.as_non_null + drop + ) + (func (;1;) (type 2) (param $r (ref func)) + local.get $r + ref.as_non_null + drop + ) + (func (;2;) (type 3) (param $r (ref extern)) + local.get $r + ref.as_non_null + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/0.print b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/0.print new file mode 100644 index 0000000000..fb2a39b0d2 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/0.print @@ -0,0 +1,209 @@ +(module + (type $proc (;0;) (func)) + (type $-i32 (;1;) (func (result i32))) + (type $-i64 (;2;) (func (result i64))) + (type $-f32 (;3;) (func (result f32))) + (type $-f64 (;4;) (func (result f64))) + (type $i32-i32 (;5;) (func (param i32) (result i32))) + (type $i64-i64 (;6;) (func (param i64) (result i64))) + (type $f32-f32 (;7;) (func (param f32) (result f32))) + (type $f64-f64 (;8;) (func (param f64) (result f64))) + (type $f32-i32 (;9;) (func (param f32 i32) (result i32))) + (type $i32-i64 (;10;) (func (param i32 i64) (result i64))) + (type $f64-f32 (;11;) (func (param f64 f32) (result f32))) + (type $i64-f64 (;12;) (func (param i64 f64) (result f64))) + (type $i64i64-i64 (;13;) (func (param i64 i64) (result i64))) + (func $const-i32 (;0;) (type $-i32) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type $-i64) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type $-f32) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type $-f64) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type $i32-i32) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type $i64-i64) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type $f32-f32) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type $f64-f64) (param f64) (result f64) + local.get 0 + ) + (func $f32-i32 (;8;) (type $f32-i32) (param f32 i32) (result i32) + local.get 1 + ) + (func $i32-i64 (;9;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + ) + (func $f64-f32 (;10;) (type $f64-f32) (param f64 f32) (result f32) + local.get 1 + ) + (func $i64-f64 (;11;) (type $i64-f64) (param i64 f64) (result f64) + local.get 1 + ) + (func (;12;) (type $-i32) (result i32) + global.get $const-i32 + return_call_ref $-i32 + ) + (func (;13;) (type $-i64) (result i64) + global.get $const-i64 + return_call_ref $-i64 + ) + (func (;14;) (type $-f32) (result f32) + global.get $const-f32 + return_call_ref $-f32 + ) + (func (;15;) (type $-f64) (result f64) + global.get $const-f64 + return_call_ref $-f64 + ) + (func (;16;) (type $-i32) (result i32) + i32.const 32 + global.get $id-i32 + return_call_ref $i32-i32 + ) + (func (;17;) (type $-i64) (result i64) + i64.const 64 + global.get $id-i64 + return_call_ref $i64-i64 + ) + (func (;18;) (type $-f32) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + global.get $id-f32 + return_call_ref $f32-f32 + ) + (func (;19;) (type $-f64) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + global.get $id-f64 + return_call_ref $f64-f64 + ) + (func (;20;) (type $-i32) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + global.get $f32-i32 + return_call_ref $f32-i32 + ) + (func (;21;) (type $-i64) (result i64) + i32.const 32 + i64.const 64 + global.get $i32-i64 + return_call_ref $i32-i64 + ) + (func (;22;) (type $-f32) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + global.get $f64-f32 + return_call_ref $f64-f32 + ) + (func (;23;) (type $-f64) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + global.get $i64-f64 + return_call_ref $i64-f64 + ) + (func (;24;) (type $proc) + ref.null 0 + return_call_ref $proc + ) + (func $fac-acc (;25;) (type $i64i64-i64) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + global.get $fac-acc + return_call_ref $i64i64-i64 + end + ) + (func $count (;26;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 0 + else + local.get 0 + i64.const 1 + i64.sub + global.get $count + return_call_ref $i64-i64 + end + ) + (func $even (;27;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 44 + else + local.get 0 + i64.const 1 + i64.sub + global.get $odd + return_call_ref $i64-i64 + end + ) + (func $odd (;28;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 99 + else + local.get 0 + i64.const 1 + i64.sub + global.get $even + return_call_ref $i64-i64 + end + ) + (global $const-i32 (;0;) (ref 1) ref.func $const-i32) + (global $const-i64 (;1;) (ref 2) ref.func $const-i64) + (global $const-f32 (;2;) (ref 3) ref.func $const-f32) + (global $const-f64 (;3;) (ref 4) ref.func $const-f64) + (global $id-i32 (;4;) (ref 5) ref.func $id-i32) + (global $id-i64 (;5;) (ref 6) ref.func $id-i64) + (global $id-f32 (;6;) (ref 7) ref.func $id-f32) + (global $id-f64 (;7;) (ref 8) ref.func $id-f64) + (global $f32-i32 (;8;) (ref 9) ref.func $f32-i32) + (global $i32-i64 (;9;) (ref 10) ref.func $i32-i64) + (global $f64-f32 (;10;) (ref 11) ref.func $f64-f32) + (global $i64-f64 (;11;) (ref 12) ref.func $i64-f64) + (global $fac-acc (;12;) (ref 13) ref.func $fac-acc) + (global $count (;13;) (ref 6) ref.func $count) + (global $even (;14;) (ref 6) ref.func $even) + (global $odd (;15;) (ref 6) ref.func $odd) + (export "type-i32" (func 12)) + (export "type-i64" (func 13)) + (export "type-f32" (func 14)) + (export "type-f64" (func 15)) + (export "type-first-i32" (func 16)) + (export "type-first-i64" (func 17)) + (export "type-first-f32" (func 18)) + (export "type-first-f64" (func 19)) + (export "type-second-i32" (func 20)) + (export "type-second-i64" (func 21)) + (export "type-second-f32" (func 22)) + (export "type-second-f64" (func 23)) + (export "null" (func 24)) + (export "fac-acc" (func $fac-acc)) + (export "count" (func $count)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) 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) + (elem (;1;) declare func $fac-acc) + (elem (;2;) declare func $count) + (elem (;3;) declare func $even) + (elem (;4;) declare func $odd) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/33.print b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/33.print new file mode 100644 index 0000000000..db9c9d6516 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/33.print @@ -0,0 +1,44 @@ +(module + (type $t (;0;) (func)) + (type $t1 (;1;) (func (result (ref 0)))) + (type $t2 (;2;) (func (result (ref null 0)))) + (type $t3 (;3;) (func (result (ref func)))) + (type $t4 (;4;) (func (result funcref))) + (func $f11 (;0;) (type $t1) (result (ref 0)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f21 (;1;) (type $t2) (result (ref null 0)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f22 (;2;) (type $t2) (result (ref null 0)) + ref.func $f22 + return_call_ref $t2 + ) + (func $f31 (;3;) (type $t3) (result (ref func)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f33 (;4;) (type $t3) (result (ref func)) + ref.func $f33 + return_call_ref $t3 + ) + (func $f41 (;5;) (type $t4) (result funcref) + ref.func $f11 + return_call_ref $t1 + ) + (func $f42 (;6;) (type $t4) (result funcref) + ref.func $f22 + return_call_ref $t2 + ) + (func $f43 (;7;) (type $t4) (result funcref) + ref.func $f33 + return_call_ref $t3 + ) + (func $f44 (;8;) (type $t4) (result funcref) + ref.func $f44 + return_call_ref $t4 + ) + (elem (;0;) declare func $f11 $f22 $f33 $f44) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/40.print b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/40.print new file mode 100644 index 0000000000..70ed02cc52 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/40.print @@ -0,0 +1,8 @@ +(module + (type $t (;0;) (func (result i32))) + (func (;0;) (type $t) (result i32) + unreachable + return_call_ref $t + ) + (export "unreachable" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/42.print b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/42.print new file mode 100644 index 0000000000..09c8e10bb9 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/42.print @@ -0,0 +1,14 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + ref.func $f + return_call_ref $t + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/44.print b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/44.print new file mode 100644 index 0000000000..97eaf8fe20 --- /dev/null +++ b/tests/snapshots/local/function-references/call_ref/return_call_ref.wast/44.print @@ -0,0 +1,16 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + i32.const 0 + ref.func $f + return_call_ref $t + i32.const 0 + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/function-references/table-nonnull.wast/0.print b/tests/snapshots/local/function-references/table-nonnull.wast/0.print new file mode 100644 index 0000000000..6c03c849a0 --- /dev/null +++ b/tests/snapshots/local/function-references/table-nonnull.wast/0.print @@ -0,0 +1,24 @@ +(module + (type $dummy (;0;) (func)) + (type (;1;) (func (result funcref))) + (func $dummy (;0;) (type $dummy)) + (func (;1;) (type 1) (result funcref) + i32.const 1 + table.get $t1 + ) + (func (;2;) (type 1) (result funcref) + i32.const 4 + table.get $t2 + ) + (func (;3;) (type 1) (result funcref) + i32.const 7 + table.get $t3 + ) + (table $t1 (;0;) 10 funcref) + (table $t2 (;1;) 10 funcref ref.func $dummy) + (table $t3 (;2;) 10 (ref 0) ref.func $dummy) + (table $t4 (;3;) 10 (ref func) ref.func $dummy) + (export "get1" (func 1)) + (export "get2" (func 2)) + (export "get3" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/local/fuzz1.wat.print b/tests/snapshots/local/fuzz1.wat.print new file mode 100644 index 0000000000..f06c3653da --- /dev/null +++ b/tests/snapshots/local/fuzz1.wat.print @@ -0,0 +1,251 @@ +(module + (type $FUNCSIG$i (;0;) (func (result i32))) + (type $FUNCSIG$vi (;1;) (func (param i32))) + (type $FUNCSIG$vj (;2;) (func (param i64))) + (type $FUNCSIG$vf (;3;) (func (param f32))) + (type $FUNCSIG$vd (;4;) (func (param f64))) + (type $FUNCSIG$j (;5;) (func (result i64))) + (type (;6;) (func)) + (import "fuzzing-support" "log-i32" (func $log-i32 (;0;) (type $FUNCSIG$vi))) + (import "fuzzing-support" "log-i64" (func $log-i64 (;1;) (type $FUNCSIG$vj))) + (import "fuzzing-support" "log-f32" (func $log-f32 (;2;) (type $FUNCSIG$vf))) + (import "fuzzing-support" "log-f64" (func $log-f64 (;3;) (type $FUNCSIG$vd))) + (func $hashMemory (;4;) (type $FUNCSIG$i) (result i32) + (local $0 i32) + i32.const 5381 + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=1 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=2 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=3 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=4 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=5 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=6 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=7 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=8 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=9 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=10 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=11 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=12 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=13 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=14 + i32.xor + local.set $0 + local.get $0 + i32.const 5 + i32.shl + local.get $0 + i32.add + i32.const 0 + i32.load8_u offset=15 + i32.xor + local.set $0 + local.get $0 + ) + (func $func_5 (;5;) (type $FUNCSIG$j) (result i64) + (local $0 i32) (local $1 i64) + block ;; label = @1 + global.get $hangLimit + i32.eqz + if ;; label = @2 + i64.const 4293531749 + return + end + global.get $hangLimit + i32.const 1 + i32.sub + global.set $hangLimit + end + block $label$0 (result i64) ;; label = @1 + nop + block $label$1 (result i64) ;; label = @2 + i32.const -2147483647 + if (result i32) ;; label = @3 + local.get $0 + else + block $label$4 (result i32) ;; label = @4 + block $label$5 (result i32) ;; label = @5 + loop $label$6 (result i32) ;; label = @6 + block ;; label = @7 + global.get $hangLimit + i32.eqz + if ;; label = @8 + i64.const -32766 + return + end + global.get $hangLimit + i32.const 1 + i32.sub + global.set $hangLimit + end + block (result i32) ;; label = @7 + nop + i32.const 8388608 + i32.eqz + br_if 1 (;@6;) + local.get $0 + end + end + i32.eqz + if (result f32) ;; label = @6 + block $label$7 (result f32) ;; label = @7 + f32.const -nan:0x7fffda (;=NaN;) + end + else + f32.const 0x1p+32 (;=4294967300;) + end + call $log-f32 + i32.const -2147483648 + end + if (result i32) ;; label = @5 + i32.const -1073741824 + else + local.get $0 + end + global.get $global$0 + i32.eqz + br_if 0 (;@4;) + end + end + local.tee $0 + local.set $0 + i64.const 255 + end + local.tee $1 + end + ) + (func $hangLimitInitializer (;6;) (type 6) + i32.const 10 + global.set $hangLimit + ) + (table $0 (;0;) 0 0 funcref) + (memory $0 (;0;) 1 1) + (global $global$0 (;0;) (mut i32) i32.const -65536) + (global $global$1 (;1;) (mut f32) f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;)) + (global $global$2 (;2;) (mut f32) f32.const -0x1.744e6cp+117 (;=-241640630000000000000000000000000000;)) + (global $global$3 (;3;) (mut f64) f64.const -nan:0xfffffffffac1b (;=NaN;)) + (global $hangLimit (;4;) (mut i32) i32.const 10) + (export "hashMemory" (func $hashMemory)) + (export "memory" (memory $0)) + (export "func_5" (func $func_5)) + (export "hangLimitInitializer" (func $hangLimitInitializer)) + (data (;0;) (i32.const 0) "\00\00\00\00") +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/gc-array-types.wat.print b/tests/snapshots/local/gc/gc-array-types.wat.print new file mode 100644 index 0000000000..d3fa5f753f --- /dev/null +++ b/tests/snapshots/local/gc/gc-array-types.wat.print @@ -0,0 +1,7 @@ +(module + (type $a (;0;) (array i32)) + (type $b (;1;) (array (mut i32))) + (type $c (;2;) (array (mut (ref null 1)))) + (type $d (;3;) (array i8)) + (type $e (;4;) (array (mut i16))) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/gc-heaptypes.wat.print b/tests/snapshots/local/gc/gc-heaptypes.wat.print new file mode 100644 index 0000000000..1fc5f440e0 --- /dev/null +++ b/tests/snapshots/local/gc/gc-heaptypes.wat.print @@ -0,0 +1,22 @@ +(module + (type (;0;) (func (param funcref (ref func) funcref))) + (type (;1;) (func (param externref (ref extern) externref))) + (type (;2;) (func (param anyref (ref any) anyref))) + (type (;3;) (func (param eqref (ref eq) eqref))) + (type (;4;) (func (param i31ref (ref i31) i31ref))) + (type (;5;) (func (param structref (ref struct) structref))) + (type (;6;) (func (param arrayref (ref array) arrayref))) + (type (;7;) (func (param nullfuncref (ref nofunc) nullfuncref))) + (type (;8;) (func (param nullexternref (ref noextern) nullexternref))) + (type (;9;) (func (param nullref (ref none) nullref))) + (func (;0;) (type 0) (param funcref (ref func) funcref)) + (func (;1;) (type 1) (param externref (ref extern) externref)) + (func (;2;) (type 2) (param anyref (ref any) anyref)) + (func (;3;) (type 3) (param eqref (ref eq) eqref)) + (func (;4;) (type 4) (param i31ref (ref i31) i31ref)) + (func (;5;) (type 5) (param structref (ref struct) structref)) + (func (;6;) (type 6) (param arrayref (ref array) arrayref)) + (func (;7;) (type 7) (param nullfuncref (ref nofunc) nullfuncref)) + (func (;8;) (type 8) (param nullexternref (ref noextern) nullexternref)) + (func (;9;) (type 9) (param nullref (ref none) nullref)) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/gc-i31.wat.print b/tests/snapshots/local/gc/gc-i31.wat.print new file mode 100644 index 0000000000..7f89e0c9be --- /dev/null +++ b/tests/snapshots/local/gc/gc-i31.wat.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (result i32 i32))) + (func $f (;0;) (type 0) (result i32 i32) + (local $a (ref i31)) (local $b i31ref) (local $c i31ref) + i32.const 42 + ref.i31 + local.set $a + i32.const 0 + ref.i31 + local.set $b + local.get $a + i31.get_u + local.get $b + i31.get_s + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/gc-ref-global-import.wat.print b/tests/snapshots/local/gc/gc-ref-global-import.wat.print new file mode 100644 index 0000000000..0a72b9aa1d --- /dev/null +++ b/tests/snapshots/local/gc/gc-ref-global-import.wat.print @@ -0,0 +1,4 @@ +(module + (type $a (;0;) (struct)) + (import "" "" (global (;0;) (ref 0))) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/gc-ref.wat.print b/tests/snapshots/local/gc/gc-ref.wat.print new file mode 100644 index 0000000000..2a4872df07 --- /dev/null +++ b/tests/snapshots/local/gc/gc-ref.wat.print @@ -0,0 +1,74 @@ +(module + (type $a (;0;) (struct)) + (type $b (;1;) (struct)) + (type $f1 (;2;) (func (param (ref 0)))) + (type $f2 (;3;) (func (result (ref 1)))) + (type (;4;) (func (param (ref 0)))) + (type (;5;) (func (result (ref 0)))) + (type (;6;) (func)) + (func (;0;) (type $f1) (param (ref 0))) + (func (;1;) (type 4) (param (ref 0))) + (func (;2;) (type $f1) (param (ref 0))) + (func (;3;) (type $f1) (param (ref 0))) + (func (;4;) (type 5) (result (ref 0)) + unreachable + ) + (func (;5;) (type 6) + (local (ref 0)) + ) + (func (;6;) (type 6) + unreachable + unreachable + i32.const 0 + select (result (ref 0)) + block (type $f1) (param (ref 0)) ;; label = @1 + unreachable + end + block (result (ref 1)) ;; label = @1 + unreachable + end + block $f1 (type $f1) (param (ref 0)) ;; label = @1 + unreachable + end + block $f2 (result (ref 1)) ;; label = @1 + unreachable + end + loop (type $f1) (param (ref 0)) ;; label = @1 + unreachable + end + loop (result (ref 1)) ;; label = @1 + unreachable + end + loop $f1 (type $f1) (param (ref 0)) ;; label = @1 + unreachable + end + loop $f2 (result (ref 1)) ;; label = @1 + unreachable + end + drop + if (type $f1) (param (ref 0)) ;; label = @1 + unreachable + else + unreachable + end + if (result (ref 1)) ;; label = @1 + unreachable + else + unreachable + end + drop + if $f1 (type $f1) (param (ref 0)) ;; label = @1 + unreachable + else + unreachable + end + if $f2 (result (ref 1)) ;; label = @1 + unreachable + else + unreachable + end + drop + ) + (global (;0;) (ref null 0) ref.null 0) + (global (;1;) (ref null 1) ref.null 1) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/gc-struct-types.wat.print b/tests/snapshots/local/gc/gc-struct-types.wat.print new file mode 100644 index 0000000000..04db0585fb --- /dev/null +++ b/tests/snapshots/local/gc/gc-struct-types.wat.print @@ -0,0 +1,21 @@ +(module + (type (;0;) (struct)) + (type (;1;) (struct (field i32))) + (type (;2;) (struct (field (mut i32)))) + (type (;3;) (struct (field i32) (field i32))) + (type (;4;) (struct (field i32) (field (mut i32)))) + (type (;5;) (struct (field (mut i32)) (field (mut i32)))) + (type $a (;6;) (struct (field f32))) + (type $b (;7;) (struct (field f32))) + (type (;8;) (struct (field externref))) + (type (;9;) (struct (field externref) (field funcref))) + (type (;10;) (struct)) + (type (;11;) (struct (field i32) (field i32))) + (type (;12;) (struct (field i32) (field (mut i32)))) + (type (;13;) (struct (field (mut i32)) (field i32))) + (type (;14;) (struct (field (mut i32)) (field (mut i32)))) + (type (;15;) (struct (field i32) (field f32) (field f32) (field f32))) + (type (;16;) (struct (field i32) (field (ref null 6)) (field (mut (ref null 7))))) + (type (;17;) (struct (field i32) (field (ref null 6)) (field (mut (ref null 7))))) + (type (;18;) (struct (field i32) (field i64) (field i8) (field i31ref) (field anyref))) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/gc-subtypes.wat.print b/tests/snapshots/local/gc/gc-subtypes.wat.print new file mode 100644 index 0000000000..205de1c3ee --- /dev/null +++ b/tests/snapshots/local/gc/gc-subtypes.wat.print @@ -0,0 +1,75 @@ +(module + (type $a (;0;) (sub (func))) + (type $b (;1;) (sub $a (;0;) (func))) + (type $c (;2;) (sub $b (;1;) (func))) + (type $b1 (;3;) (sub final $a (;0;) (func))) + (type $d (;4;) (sub (struct))) + (type $e (;5;) (sub $d (;4;) (struct (field (mut (ref null 4)))))) + (type $f (;6;) (sub final $e (;5;) (struct (field (ref 5))))) + (type $g (;7;) (sub (func (param (ref 5)) (result (ref 5))))) + (type $h (;8;) (sub $g (;7;) (func (param (ref 4)) (result (ref 6))))) + (type $j (;9;) (sub (func (param (ref 1)) (result (ref 1))))) + (type $k (;10;) (sub $j (;9;) (func (param (ref 0)) (result (ref 2))))) + (type $l (;11;) (sub $j (;9;) (func (param (ref 2)) (result (ref 0))))) + (type $m (;12;) (sub (array (mut i32)))) + (type $n (;13;) (sub $m (;12;) (array i32))) + (type $o (;14;) (sub (array i32))) + (type $p (;15;) (sub $o (;14;) (array i32))) + (type $o1 (;16;) (sub (array i64))) + (type $p1 (;17;) (sub $o1 (;16;) (array i64))) + (type $q (;18;) (sub (array (mut anyref)))) + (type $q0 (;19;) (sub $q (;18;) (array (ref any)))) + (type $q1 (;20;) (sub $q (;18;) (array (mut eqref)))) + (type $q2 (;21;) (sub $q1 (;20;) (array (mut (ref eq))))) + (type $q3 (;22;) (sub $q2 (;21;) (array (ref eq)))) + (type $r (;23;) (sub $q (;18;) (array i31ref))) + (type $r1 (;24;) (sub $q1 (;20;) (array i31ref))) + (type $s (;25;) (sub $r (;23;) (array (ref i31)))) + (type $s1 (;26;) (sub $q1 (;20;) (array (ref i31)))) + (type $s2 (;27;) (sub $q2 (;21;) (array (ref i31)))) + (type $rr (;28;) (sub $q (;18;) (array arrayref))) + (type $rr1 (;29;) (sub $q1 (;20;) (array arrayref))) + (type $ss (;30;) (sub $rr (;28;) (array (ref array)))) + (type $ss0 (;31;) (sub $ss (;30;) (array (ref 28)))) + (type $ss1 (;32;) (sub $q1 (;20;) (array (ref array)))) + (type (;33;) (sub $q1 (;20;) (array (ref 28)))) + (type $ss2 (;34;) (sub $q2 (;21;) (array (ref array)))) + (type (;35;) (sub $q2 (;21;) (array (ref 28)))) + (type $rrr (;36;) (sub $q (;18;) (array structref))) + (type $rrr1 (;37;) (sub $q1 (;20;) (array structref))) + (type $sss (;38;) (sub $rrr (;36;) (array (ref struct)))) + (type $sss0 (;39;) (sub $rrr (;36;) (array (ref null 4)))) + (type $sss1 (;40;) (sub $q1 (;20;) (array (ref struct)))) + (type (;41;) (sub $q1 (;20;) (array (ref 4)))) + (type $sss2 (;42;) (sub $q2 (;21;) (array (ref struct)))) + (type (;43;) (sub $q2 (;21;) (array (ref 4)))) + (type $z1 (;44;) (sub $q (;18;) (array (mut nullref)))) + (type $z2 (;45;) (sub $q0 (;19;) (array (ref none)))) + (type $z3 (;46;) (sub $z1 (;44;) (array (mut (ref none))))) + (type $z4 (;47;) (sub $z1 (;44;) (array nullref))) + (type (;48;) (sub $q1 (;20;) (array nullref))) + (type (;49;) (sub $r (;23;) (array nullref))) + (type (;50;) (sub $rr (;28;) (array nullref))) + (type (;51;) (sub $rrr (;36;) (array nullref))) + (type (;52;) (sub $q1 (;20;) (array (ref none)))) + (type (;53;) (sub $r (;23;) (array (ref none)))) + (type (;54;) (sub $rr (;28;) (array (ref none)))) + (type (;55;) (sub $rrr (;36;) (array (ref none)))) + (type $t (;56;) (sub (array (mut funcref)))) + (type $u (;57;) (sub $t (;56;) (array funcref))) + (type $v (;58;) (sub $u (;57;) (array (ref func)))) + (type $w (;59;) (sub $v (;58;) (array (ref 0)))) + (type $x (;60;) (sub $t (;56;) (array (ref null 0)))) + (type $y (;61;) (sub $w (;59;) (array (ref nofunc)))) + (type $z (;62;) (sub $x (;60;) (array nullfuncref))) + (type $t0 (;63;) (sub (array (mut externref)))) + (type $u0 (;64;) (sub $t0 (;63;) (array externref))) + (type $v0 (;65;) (sub $u0 (;64;) (array (ref extern)))) + (type $y0 (;66;) (sub $v0 (;65;) (array (ref noextern)))) + (type $y01 (;67;) (sub $u0 (;64;) (array (ref noextern)))) + (type $z0 (;68;) (sub $u0 (;64;) (array nullexternref))) + (type $A (;69;) (sub (struct (field (mut i32))))) + (type $B (;70;) (sub $A (;69;) (struct (field (mut i32))))) + (type (;71;) (sub $A (;69;) (struct (field (mut i32))))) + (type (;72;) (sub $A (;69;) (struct (field (mut i32)) (field (mut i64))))) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/0.print b/tests/snapshots/local/gc/type-equivalence.wast/0.print new file mode 100644 index 0000000000..e6e986b450 --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/0.print @@ -0,0 +1,14 @@ +(module + (type $t1 (;0;) (func (param f32 f32) (result f32))) + (type $t2 (;1;) (func (param f32 f32) (result f32))) + (type (;2;) (func (param (ref 0)))) + (type (;3;) (func (param (ref 1)))) + (func $f1 (;0;) (type 2) (param $r (ref 0)) + local.get $r + call $f2 + ) + (func $f2 (;1;) (type 3) (param $r (ref 1)) + local.get $r + call $f1 + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/1.print b/tests/snapshots/local/gc/type-equivalence.wast/1.print new file mode 100644 index 0000000000..4677912b11 --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/1.print @@ -0,0 +1,17 @@ +(module + (type $s0 (;0;) (func (param i32) (result f32))) + (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $t1 (;3;) (func (param (ref 1)) (result (ref 2)))) + (type $t2 (;4;) (func (param (ref 2)) (result (ref 1)))) + (type (;5;) (func (param (ref 3)))) + (type (;6;) (func (param (ref 4)))) + (func $f1 (;0;) (type 5) (param $r (ref 3)) + local.get $r + call $f2 + ) + (func $f2 (;1;) (type 6) (param $r (ref 4)) + local.get $r + call $f1 + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/10.print b/tests/snapshots/local/gc/type-equivalence.wast/10.print new file mode 100644 index 0000000000..ff5f8b66a0 --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/10.print @@ -0,0 +1,5 @@ +(module + (type $t2 (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param (ref 0)))) + (import "M" "f" (func (;0;) (type 1))) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/11.print b/tests/snapshots/local/gc/type-equivalence.wast/11.print new file mode 100644 index 0000000000..8dce052a31 --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/11.print @@ -0,0 +1,12 @@ +(module + (type $s0 (;0;) (func (param i32) (result f32))) + (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $t1 (;3;) (func (param (ref 1)) (result (ref 2)))) + (type $t2 (;4;) (func (param (ref 2)) (result (ref 1)))) + (type (;5;) (func (param (ref 3)))) + (func (;0;) (type 5) (param (ref 3))) + (func (;1;) (type 5) (param (ref 3))) + (export "f1" (func 0)) + (export "f2" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/13.print b/tests/snapshots/local/gc/type-equivalence.wast/13.print new file mode 100644 index 0000000000..bc2fc84891 --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/13.print @@ -0,0 +1,13 @@ +(module + (type $s0 (;0;) (func (param i32) (result f32))) + (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $t1 (;3;) (func (param (ref 1)) (result (ref 2)))) + (type $t2 (;4;) (func (param (ref 2)) (result (ref 1)))) + (type (;5;) (func (param (ref 3)))) + (type (;6;) (func (param (ref 4)))) + (import "M" "f1" (func (;0;) (type 5))) + (import "M" "f1" (func (;1;) (type 6))) + (import "M" "f2" (func (;2;) (type 5))) + (import "M" "f2" (func (;3;) (type 5))) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/2.print b/tests/snapshots/local/gc/type-equivalence.wast/2.print new file mode 100644 index 0000000000..b063e70829 --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/2.print @@ -0,0 +1,3 @@ +(module + (type $t (;0;) (func (result (ref 0)))) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/4.print b/tests/snapshots/local/gc/type-equivalence.wast/4.print new file mode 100644 index 0000000000..51cfc60256 --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/4.print @@ -0,0 +1,20 @@ +(module + (type $t1 (;0;) (func (param f32 f32))) + (type $t2 (;1;) (func (param f32 f32))) + (type (;2;) (func)) + (func $f1 (;0;) (type $t1) (param f32 f32)) + (func $f2 (;1;) (type $t2) (param f32 f32)) + (func (;2;) (type 2) + f32.const 0x1p+0 (;=1;) + f32.const 0x1p+1 (;=2;) + i32.const 1 + call_indirect (type $t1) + f32.const 0x1p+0 (;=1;) + f32.const 0x1p+1 (;=2;) + i32.const 0 + call_indirect (type $t2) + ) + (table (;0;) 2 2 funcref) + (export "run" (func 2)) + (elem (;0;) (i32.const 0) func $f1 $f2) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/6.print b/tests/snapshots/local/gc/type-equivalence.wast/6.print new file mode 100644 index 0000000000..790198e78d --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/6.print @@ -0,0 +1,41 @@ +(module + (type $s0 (;0;) (func (param i32))) + (type $s1 (;1;) (func (param i32 (ref 0)))) + (type $s2 (;2;) (func (param i32 (ref 0)))) + (type $t1 (;3;) (func (param (ref 1)))) + (type $t2 (;4;) (func (param (ref 2)))) + (type (;5;) (func)) + (func $s1 (;0;) (type $s1) (param i32 (ref 0))) + (func $s2 (;1;) (type $s2) (param i32 (ref 0))) + (func $f1 (;2;) (type $t1) (param (ref 1))) + (func $f2 (;3;) (type $t2) (param (ref 2))) + (func (;4;) (type 5) + ref.func $s1 + i32.const 0 + call_indirect (type $t1) + ref.func $s1 + i32.const 1 + call_indirect (type $t1) + ref.func $s2 + i32.const 0 + call_indirect (type $t1) + ref.func $s2 + i32.const 1 + call_indirect (type $t1) + ref.func $s1 + i32.const 0 + call_indirect (type $t2) + ref.func $s1 + i32.const 1 + call_indirect (type $t2) + ref.func $s2 + i32.const 0 + call_indirect (type $t2) + ref.func $s2 + i32.const 1 + call_indirect (type $t2) + ) + (table (;0;) 4 4 funcref) + (export "run" (func 4)) + (elem (;0;) (i32.const 0) func $f1 $f2 $s1 $s2) +) \ No newline at end of file diff --git a/tests/snapshots/local/gc/type-equivalence.wast/8.print b/tests/snapshots/local/gc/type-equivalence.wast/8.print new file mode 100644 index 0000000000..018898abd6 --- /dev/null +++ b/tests/snapshots/local/gc/type-equivalence.wast/8.print @@ -0,0 +1,6 @@ +(module + (type $t1 (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param (ref 0)))) + (func (;0;) (type 1) (param (ref 0))) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/if-else-parsing.wast/0.print b/tests/snapshots/local/if-else-parsing.wast/0.print new file mode 100644 index 0000000000..56cbd49587 --- /dev/null +++ b/tests/snapshots/local/if-else-parsing.wast/0.print @@ -0,0 +1,29 @@ +(module + (type (;0;) (func)) + (func $a1 (;0;) (type 0) + i32.const 0 + if ;; label = @1 + else + end + ) + (func $a2 (;1;) (type 0) + i32.const 1 + i32.eqz + if ;; label = @1 + else + end + ) + (func $a3 (;2;) (type 0) + i32.const 1 + i32.eqz + if ;; label = @1 + end + ) + (func $a4 (;3;) (type 0) + i32.const 1 + i32.eqz + if ;; label = @1 + nop + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/if-multi-unreachable.wat.print b/tests/snapshots/local/if-multi-unreachable.wat.print new file mode 100644 index 0000000000..1aa8ce4bb2 --- /dev/null +++ b/tests/snapshots/local/if-multi-unreachable.wat.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func (result i32 i32))) + (func (;0;) (type 0) (result i32 i32) + unreachable + select + if (type 0) (result i32 i32) ;; label = @1 + unreachable + else + unreachable + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/issue126.wat.print b/tests/snapshots/local/issue126.wat.print new file mode 100644 index 0000000000..7d889afe15 --- /dev/null +++ b/tests/snapshots/local/issue126.wat.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 1 + block ;; label = @1 + block ;; label = @2 + unreachable + if ;; label = @3 + return + end + end + unreachable + select + drop + end + unreachable + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/issue192.wast/0.print b/tests/snapshots/local/issue192.wast/0.print new file mode 100644 index 0000000000..ad41d26714 --- /dev/null +++ b/tests/snapshots/local/issue192.wast/0.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) + unreachable + block (type 1) (param i32) ;; label = @1 + drop + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/issue194.wast/0.print b/tests/snapshots/local/issue194.wast/0.print new file mode 100644 index 0000000000..0172137190 --- /dev/null +++ b/tests/snapshots/local/issue194.wast/0.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param i32) + (local i32) + i32.const -64 + loop (type 0) (param i32) ;; label = @1 + local.set 0 + i32.const 0 + local.get 0 + br_if 0 (;@1;) + drop + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/memory-discard.wat.print b/tests/snapshots/local/memory-discard.wat.print new file mode 100644 index 0000000000..4b4087732c --- /dev/null +++ b/tests/snapshots/local/memory-discard.wat.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.const 65536 + memory.discard + ) + (func (;1;) (type 0) + i32.const 0 + i32.const 65536 + memory.discard + ) + (func (;2;) (type 0) + i32.const 0 + i32.const 65536 + memory.discard + ) + (memory $m (;0;) 2) +) \ No newline at end of file diff --git a/tests/snapshots/local/memory64.wast/0.print b/tests/snapshots/local/memory64.wast/0.print new file mode 100644 index 0000000000..c5c0812a21 --- /dev/null +++ b/tests/snapshots/local/memory64.wast/0.print @@ -0,0 +1,404 @@ +(module + (type (;0;) (func (result i64))) + (type (;1;) (func (param i64) (result i64))) + (type (;2;) (func)) + (func (;0;) (type 0) (result i64) + memory.size + ) + (func (;1;) (type 1) (param i64) (result i64) + local.get 0 + memory.grow + ) + (func (;2;) (type 2) + i64.const 0 + i64.const 0 + i64.const 0 + memory.copy + i64.const 0 + i32.const 0 + i64.const 0 + memory.fill + i64.const 0 + i32.const 0 + i32.const 0 + memory.init $seg + memory.size + i32.load + drop + i64.const 0 + memory.grow + i64.load + drop + i64.const 0 + i32.load offset=281474976710655 + drop + i64.const 0 + i32.load + drop + i64.const 0 + i64.load + drop + i64.const 0 + f32.load + drop + i64.const 0 + f64.load + drop + i64.const 0 + i32.load8_s + drop + i64.const 0 + i32.load8_u + drop + i64.const 0 + i32.load16_s + drop + i64.const 0 + i32.load16_u + drop + i64.const 0 + i64.load8_s + drop + i64.const 0 + i64.load8_u + drop + i64.const 0 + i64.load16_s + drop + i64.const 0 + i64.load16_u + drop + i64.const 0 + i64.load32_s + drop + i64.const 0 + i64.load32_u + drop + i64.const 0 + i32.const 0 + i32.store + i64.const 0 + i64.const 0 + i64.store + i64.const 0 + f32.const 0x0p+0 (;=0;) + f32.store + i64.const 0 + f64.const 0x0p+0 (;=0;) + f64.store + i64.const 0 + i32.const 0 + i32.store8 + i64.const 0 + i32.const 0 + i32.store16 + i64.const 0 + i64.const 0 + i64.store8 + i64.const 0 + i64.const 0 + i64.store16 + i64.const 0 + i64.const 0 + i64.store32 + i64.const 0 + i32.const 0 + memory.atomic.notify + drop + i64.const 0 + i32.const 0 + i64.const 0 + memory.atomic.wait32 + drop + i64.const 0 + i64.const 0 + i64.const 0 + memory.atomic.wait64 + drop + i64.const 0 + i32.atomic.load + drop + i64.const 0 + i64.atomic.load + drop + i64.const 0 + i32.atomic.load8_u + drop + i64.const 0 + i32.atomic.load16_u + drop + i64.const 0 + i64.atomic.load8_u + drop + i64.const 0 + i64.atomic.load16_u + drop + i64.const 0 + i64.atomic.load32_u + drop + i64.const 0 + i32.const 0 + i32.atomic.store + i64.const 0 + i64.const 0 + i64.atomic.store + i64.const 0 + i32.const 0 + i32.atomic.store8 + i64.const 0 + i32.const 0 + i32.atomic.store16 + i64.const 0 + i64.const 0 + i64.atomic.store8 + i64.const 0 + i64.const 0 + i64.atomic.store16 + i64.const 0 + i64.const 0 + i64.atomic.store32 + i64.const 0 + i32.const 0 + i32.atomic.rmw.add + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw.add + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw8.add_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw16.add_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw8.add_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw16.add_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw32.add_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw.sub + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw.sub + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw8.sub_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw16.sub_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw8.sub_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw16.sub_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw32.sub_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw.and + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw.and + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw8.and_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw16.and_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw8.and_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw16.and_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw32.and_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw.or + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw.or + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw8.or_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw16.or_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw8.or_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw16.or_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw32.or_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw.xor + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw.xor + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw8.xor_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw16.xor_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw8.xor_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw16.xor_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw32.xor_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw.xchg + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw.xchg + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw8.xchg_u + drop + i64.const 0 + i32.const 0 + i32.atomic.rmw16.xchg_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw8.xchg_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw16.xchg_u + drop + i64.const 0 + i64.const 0 + i64.atomic.rmw32.xchg_u + drop + i64.const 0 + i32.const 0 + i32.const 0 + i32.atomic.rmw.cmpxchg + drop + i64.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw.cmpxchg + drop + i64.const 0 + i32.const 0 + i32.const 0 + i32.atomic.rmw8.cmpxchg_u + drop + i64.const 0 + i32.const 0 + i32.const 0 + i32.atomic.rmw16.cmpxchg_u + drop + i64.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw8.cmpxchg_u + drop + i64.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw16.cmpxchg_u + drop + i64.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw32.cmpxchg_u + drop + i64.const 0 + v128.load + drop + i64.const 0 + v128.load8x8_s + drop + i64.const 0 + v128.load8x8_u + drop + i64.const 0 + v128.load16x4_s + drop + i64.const 0 + v128.load16x4_u + drop + i64.const 0 + v128.load32x2_s + drop + i64.const 0 + v128.load32x2_u + drop + i64.const 0 + v128.load8_splat + drop + i64.const 0 + v128.load16_splat + drop + i64.const 0 + v128.load32_splat + drop + i64.const 0 + v128.load64_splat + drop + i64.const 0 + i32.const 0 + i8x16.splat + v128.store + ) + (memory (;0;) i64 1) + (data (;0;) (i64.const 0) "..") + (data $seg (;1;) "..") +) \ No newline at end of file diff --git a/tests/snapshots/local/missing-features/issue540.wast/0.print b/tests/snapshots/local/missing-features/issue540.wast/0.print new file mode 100644 index 0000000000..b72c3758cd --- /dev/null +++ b/tests/snapshots/local/missing-features/issue540.wast/0.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 112 38368) + (data (;0;) (i32.const 1994) "") +) \ No newline at end of file diff --git a/tests/snapshots/local/missing-features/issue540.wast/1.print b/tests/snapshots/local/missing-features/issue540.wast/1.print new file mode 100644 index 0000000000..b72c3758cd --- /dev/null +++ b/tests/snapshots/local/missing-features/issue540.wast/1.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 112 38368) + (data (;0;) (i32.const 1994) "") +) \ No newline at end of file diff --git a/tests/snapshots/local/missing-features/issue540.wast/2.print b/tests/snapshots/local/missing-features/issue540.wast/2.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/local/missing-features/issue540.wast/2.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/local/multi-memory.wast/0.print b/tests/snapshots/local/multi-memory.wast/0.print new file mode 100644 index 0000000000..935c256675 --- /dev/null +++ b/tests/snapshots/local/multi-memory.wast/0.print @@ -0,0 +1,464 @@ +(module + (type (;0;) (func)) + (func $foo (;0;) (type 0) + i32.const 0 + i32.load + drop + i32.const 0 + i32.load + drop + i32.const 0 + i32.load $b + drop + i32.const 0 + i32.load + drop + i32.const 0 + i32.load $b + drop + i32.const 0 + i32.const 0 + i32.store + i32.const 0 + i32.const 0 + i32.store $b + i32.const 0 + i32.const 0 + i32.store + i32.const 0 + i32.const 0 + i32.store $b + i32.const 0 + i32.const 0 + i32.const 0 + memory.copy $a $b + i32.const 0 + i32.const 0 + i32.const 0 + memory.copy $b $a + i32.const 0 + i32.const 0 + i32.const 0 + memory.fill + i32.const 0 + i32.const 0 + i32.const 0 + memory.fill $b + i32.const 0 + i32.const 0 + i32.const 0 + memory.init $b $seg + memory.size + drop + memory.size $b + drop + i32.const 0 + memory.grow + drop + i32.const 0 + memory.grow $b + drop + i32.const 0 + i32.load + drop + i32.const 0 + i64.load $b + drop + i32.const 0 + f32.load $b + drop + i32.const 0 + f64.load $b + drop + i32.const 0 + i32.load8_s $b + drop + i32.const 0 + i32.load8_u $b + drop + i32.const 0 + i32.load16_s $b + drop + i32.const 0 + i32.load16_u $b + drop + i32.const 0 + i64.load8_s $b + drop + i32.const 0 + i64.load8_u $b + drop + i32.const 0 + i64.load16_s $b + drop + i32.const 0 + i64.load16_u $b + drop + i32.const 0 + i64.load32_s $b + drop + i32.const 0 + i64.load32_u $b + drop + i32.const 0 + i32.const 0 + i32.store $b + i32.const 0 + i64.const 0 + i64.store $b + i32.const 0 + f32.const 0x0p+0 (;=0;) + f32.store $b + i32.const 0 + f64.const 0x0p+0 (;=0;) + f64.store $b + i32.const 0 + i32.const 0 + i32.store8 $b + i32.const 0 + i32.const 0 + i32.store16 $b + i32.const 0 + i64.const 0 + i64.store8 $b + i32.const 0 + i64.const 0 + i64.store16 $b + i32.const 0 + i64.const 0 + i64.store32 $b + i32.const 0 + i32.const 0 + memory.atomic.notify $b + drop + i32.const 0 + i32.const 0 + i64.const 0 + memory.atomic.wait32 $b + drop + i32.const 0 + i64.const 0 + i64.const 0 + memory.atomic.wait64 $b + drop + i32.const 0 + i32.atomic.load $b + drop + i32.const 0 + i64.atomic.load $b + drop + i32.const 0 + i32.atomic.load8_u $b + drop + i32.const 0 + i32.atomic.load16_u $b + drop + i32.const 0 + i64.atomic.load8_u $b + drop + i32.const 0 + i64.atomic.load16_u $b + drop + i32.const 0 + i64.atomic.load32_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.store $b + i32.const 0 + i64.const 0 + i64.atomic.store $b + i32.const 0 + i32.const 0 + i32.atomic.store8 $b + i32.const 0 + i32.const 0 + i32.atomic.store16 $b + i32.const 0 + i64.const 0 + i64.atomic.store8 $b + i32.const 0 + i64.const 0 + i64.atomic.store16 $b + i32.const 0 + i64.const 0 + i64.atomic.store32 $b + i32.const 0 + i32.const 0 + i32.atomic.rmw.add $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw.add $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw8.add_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw16.add_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw8.add_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw16.add_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw32.add_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw.sub $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw.sub $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw8.sub_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw16.sub_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw8.sub_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw16.sub_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw32.sub_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw.and $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw.and $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw8.and_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw16.and_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw8.and_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw16.and_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw32.and_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw.or $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw.or $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw8.or_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw16.or_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw8.or_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw16.or_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw32.or_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw.xor $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw.xor $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw8.xor_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw16.xor_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw8.xor_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw16.xor_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw32.xor_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw.xchg $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw.xchg $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw8.xchg_u $b + drop + i32.const 0 + i32.const 0 + i32.atomic.rmw16.xchg_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw8.xchg_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw16.xchg_u $b + drop + i32.const 0 + i64.const 0 + i64.atomic.rmw32.xchg_u $b + drop + i32.const 0 + i32.const 0 + i32.const 0 + i32.atomic.rmw.cmpxchg $b + drop + i32.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw.cmpxchg $b + drop + i32.const 0 + i32.const 0 + i32.const 0 + i32.atomic.rmw8.cmpxchg_u $b + drop + i32.const 0 + i32.const 0 + i32.const 0 + i32.atomic.rmw16.cmpxchg_u $b + drop + i32.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw8.cmpxchg_u $b + drop + i32.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw16.cmpxchg_u $b + drop + i32.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw32.cmpxchg_u $b + drop + i32.const 0 + v128.load $b + drop + i32.const 0 + v128.load8x8_s $b + drop + i32.const 0 + v128.load8x8_u $b + drop + i32.const 0 + v128.load16x4_s $b + drop + i32.const 0 + v128.load16x4_u $b + drop + i32.const 0 + v128.load32x2_s $b + drop + i32.const 0 + v128.load32x2_u $b + drop + i32.const 0 + v128.load8_splat $b + drop + i32.const 0 + v128.load16_splat $b + drop + i32.const 0 + v128.load32_splat $b + drop + i32.const 0 + v128.load64_splat $b + drop + i32.const 0 + v128.load32_zero $b + drop + i32.const 0 + v128.load64_zero $b + drop + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.load8_lane $b 0 + drop + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.load16_lane $b 0 + drop + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.load32_lane $b 0 + drop + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.load64_lane $b 0 + drop + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store8_lane $b 0 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store16_lane $b 0 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store32_lane $b 0 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store64_lane $b 0 + i32.const 0 + i32.const 0 + i8x16.splat + v128.store $b + ) + (memory $a (;0;) 0) + (memory $b (;1;) 0) + (data $seg (;0;) "") +) \ No newline at end of file diff --git a/tests/snapshots/local/multi-memory.wast/3.print b/tests/snapshots/local/multi-memory.wast/3.print new file mode 100644 index 0000000000..c0e2e1eec9 --- /dev/null +++ b/tests/snapshots/local/multi-memory.wast/3.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 1) + (memory $m (;1;) 1) + (data (;0;) (memory $m) (i32.const 0) "...") +) \ No newline at end of file diff --git a/tests/snapshots/local/multi-memory64.wast/0.print b/tests/snapshots/local/multi-memory64.wast/0.print new file mode 100644 index 0000000000..c224351312 --- /dev/null +++ b/tests/snapshots/local/multi-memory64.wast/0.print @@ -0,0 +1,23 @@ +(module $copy_between_memories + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.const 0 + i32.const 0 + memory.copy $m32 $m32 + i64.const 0 + i32.const 0 + i32.const 0 + memory.copy $m64 $m32 + i32.const 0 + i64.const 0 + i32.const 0 + memory.copy $m32 $m64 + i64.const 0 + i64.const 0 + i64.const 0 + memory.copy + ) + (memory $m64 (;0;) i64 1) + (memory $m32 (;1;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/local/multi-memory64.wast/1.print b/tests/snapshots/local/multi-memory64.wast/1.print new file mode 100644 index 0000000000..0991e50429 --- /dev/null +++ b/tests/snapshots/local/multi-memory64.wast/1.print @@ -0,0 +1,20 @@ +(module $copy_between_memories + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.load + drop + i32.const 0 + i32.load $b + drop + i64.const 0 + i32.load $c + drop + ) + (memory $a (;0;) 1 1) + (memory $b (;1;) 1 1) + (memory $c (;2;) i64 1 1) + (data (;0;) (i32.const 0) "...") + (data (;1;) (memory $b) (i32.const 0) "...") + (data (;2;) (memory $c) (i64.const 0) "...") +) \ No newline at end of file diff --git a/tests/snapshots/local/names.wast/0.print b/tests/snapshots/local/names.wast/0.print new file mode 100644 index 0000000000..008b26aa6a --- /dev/null +++ b/tests/snapshots/local/names.wast/0.print @@ -0,0 +1 @@ +(module $#module0<> (@name "")) \ No newline at end of file diff --git a/tests/snapshots/local/names.wast/1.print b/tests/snapshots/local/names.wast/1.print new file mode 100644 index 0000000000..e5206e4655 --- /dev/null +++ b/tests/snapshots/local/names.wast/1.print @@ -0,0 +1 @@ +(module $a) \ No newline at end of file diff --git a/tests/snapshots/local/names.wast/2.print b/tests/snapshots/local/names.wast/2.print new file mode 100644 index 0000000000..315a98a45d --- /dev/null +++ b/tests/snapshots/local/names.wast/2.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $foo (;0;) (type 0)) + (func $#func1 (@name "foo") (;1;) (type 0)) + (func $foo_1 (;2;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/names.wast/3.print b/tests/snapshots/local/names.wast/3.print new file mode 100644 index 0000000000..9ef1bfa57b --- /dev/null +++ b/tests/snapshots/local/names.wast/3.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local $foo i32) (local $#local1 (@name "foo") i32) (local $foo_1 i32) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/names.wast/4.print b/tests/snapshots/local/names.wast/4.print new file mode 100644 index 0000000000..755ca8e5cc --- /dev/null +++ b/tests/snapshots/local/names.wast/4.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func $#func0<> (@name "") (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/names.wast/5.print b/tests/snapshots/local/names.wast/5.print new file mode 100644 index 0000000000..8b97349c0a --- /dev/null +++ b/tests/snapshots/local/names.wast/5.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local $#local0<> (@name "") i32) + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/naming.wat.print b/tests/snapshots/local/naming.wat.print new file mode 100644 index 0000000000..4750920bef --- /dev/null +++ b/tests/snapshots/local/naming.wat.print @@ -0,0 +1,164 @@ +(module + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func (param i32))) + (type (;4;) (func)) + (import "env" "DYNAMICTOP_PTR" (global (;0;) i32)) + (import "env" "tempDoublePtr" (global (;1;) i32)) + (import "env" "ABORT" (global (;2;) i32)) + (import "env" "STACKTOP" (global (;3;) i32)) + (import "env" "STACK_MAX" (global (;4;) i32)) + (import "env" "gb" (global (;5;) i32)) + (import "env" "fb" (global (;6;) i32)) + (import "global" "NaN" (global (;7;) f64)) + (import "global" "Infinity" (global (;8;) f64)) + (import "env" "memory" (memory (;0;) 256 256)) + (import "env" "table" (table (;0;) 0 0 funcref)) + (import "env" "memoryBase" (global (;9;) i32)) + (import "env" "tableBase" (global (;10;) i32)) + (func $stackAlloc (;0;) (type 1) (param i32) (result i32) + (local i32) + block ;; label = @1 + global.get 14 + local.set 1 + global.get 14 + local.get 0 + i32.add + global.set 14 + global.get 14 + i32.const 15 + i32.add + i32.const -16 + i32.and + global.set 14 + local.get 1 + return + unreachable + end + unreachable + ) + (func $stackSave (;1;) (type 2) (result i32) + global.get 14 + return + ) + (func $stackRestore (;2;) (type 3) (param i32) + local.get 0 + global.set 14 + ) + (func $establishStackSpace (;3;) (type 0) (param i32 i32) + block ;; label = @1 + local.get 0 + global.set 14 + local.get 1 + global.set 15 + end + ) + (func $setThrew (;4;) (type 0) (param i32 i32) + global.get 18 + i32.const 0 + i32.eq + if ;; label = @1 + local.get 0 + global.set 18 + local.get 1 + global.set 19 + end + ) + (func $_fib (;5;) (type 1) (param i32) (result i32) + (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) + block ;; label = @1 + global.get 14 + local.set 11 + local.get 0 + i32.const 0 + i32.gt_s + local.set 6 + local.get 6 + if ;; label = @2 + i32.const 0 + local.set 1 + i32.const 1 + local.set 5 + i32.const 0 + local.set 8 + else + i32.const 1 + local.set 4 + local.get 4 + return + end + loop ;; label = @2 + block ;; label = @3 + local.get 5 + local.get 1 + i32.add + local.set 3 + local.get 8 + i32.const 1 + i32.add + local.set 9 + local.get 9 + local.get 0 + i32.eq + local.set 7 + local.get 7 + if ;; label = @4 + local.get 3 + local.set 4 + br 1 (;@3;) + else + local.get 5 + local.set 2 + local.get 3 + local.set 5 + local.get 9 + local.set 8 + local.get 2 + local.set 1 + end + br 1 (;@2;) + end + end + local.get 4 + return + unreachable + end + unreachable + ) + (func $runPostSets (;6;) (type 4) + (local i32) + nop + ) + (global (;11;) (mut i32) global.get 0) + (global (;12;) (mut i32) global.get 1) + (global (;13;) (mut i32) global.get 2) + (global (;14;) (mut i32) global.get 3) + (global (;15;) (mut i32) global.get 4) + (global (;16;) (mut i32) global.get 5) + (global (;17;) (mut i32) global.get 6) + (global (;18;) (mut i32) i32.const 0) + (global (;19;) (mut i32) i32.const 0) + (global (;20;) (mut i32) i32.const 0) + (global (;21;) (mut i32) i32.const 0) + (global (;22;) (mut f64) global.get 7) + (global (;23;) (mut f64) global.get 8) + (global (;24;) (mut i32) i32.const 0) + (global (;25;) (mut i32) i32.const 0) + (global (;26;) (mut i32) i32.const 0) + (global (;27;) (mut i32) i32.const 0) + (global (;28;) (mut f64) f64.const 0x0p+0 (;=0;)) + (global (;29;) (mut i32) i32.const 0) + (global (;30;) (mut i32) i32.const 0) + (global (;31;) (mut i32) i32.const 0) + (global (;32;) (mut f64) f64.const 0x0p+0 (;=0;)) + (global (;33;) (mut i32) i32.const 0) + (global (;34;) (mut f64) f64.const 0x0p+0 (;=0;)) + (export "setThrew" (func $setThrew)) + (export "runPostSets" (func $runPostSets)) + (export "establishStackSpace" (func $establishStackSpace)) + (export "stackSave" (func $stackSave)) + (export "stackRestore" (func $stackRestore)) + (export "_fib" (func $_fib)) + (export "stackAlloc" (func $stackAlloc)) +) \ No newline at end of file diff --git a/tests/snapshots/local/param-names.wat.print b/tests/snapshots/local/param-names.wat.print new file mode 100644 index 0000000000..a487cf46d4 --- /dev/null +++ b/tests/snapshots/local/param-names.wat.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32 i32))) + (func (;0;) (type 0) (param i32) (param $b i32)) +) \ No newline at end of file diff --git a/tests/snapshots/local/producers.wast/0.print b/tests/snapshots/local/producers.wast/0.print new file mode 100644 index 0000000000..88ad199b7e --- /dev/null +++ b/tests/snapshots/local/producers.wast/0.print @@ -0,0 +1,3 @@ +(module + (@producers) +) \ No newline at end of file diff --git a/tests/snapshots/local/producers.wast/1.print b/tests/snapshots/local/producers.wast/1.print new file mode 100644 index 0000000000..2f14e514ed --- /dev/null +++ b/tests/snapshots/local/producers.wast/1.print @@ -0,0 +1,5 @@ +(module + (@producers + (language "foo" "bar") + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/producers.wast/2.print b/tests/snapshots/local/producers.wast/2.print new file mode 100644 index 0000000000..d8f701c287 --- /dev/null +++ b/tests/snapshots/local/producers.wast/2.print @@ -0,0 +1,8 @@ +(module + (@producers + (language "foo" "bar") + (language "foo" "bar") + (sdk "foo" "bar") + (processed-by "foo" "bar") + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/producers.wast/3.print b/tests/snapshots/local/producers.wast/3.print new file mode 100644 index 0000000000..ba77a0548b --- /dev/null +++ b/tests/snapshots/local/producers.wast/3.print @@ -0,0 +1,6 @@ +(module + (@producers) + (@producers + (sdk "foo" "bar") + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/producers.wast/5.print b/tests/snapshots/local/producers.wast/5.print new file mode 100644 index 0000000000..f26da787f1 --- /dev/null +++ b/tests/snapshots/local/producers.wast/5.print @@ -0,0 +1,4 @@ +(module + ;; failed to parse custom section `producers`: unexpected end-of-file (at offset 0x15) + + ) \ No newline at end of file diff --git a/tests/snapshots/local/producers.wast/6.print b/tests/snapshots/local/producers.wast/6.print new file mode 100644 index 0000000000..d61f51e0fc --- /dev/null +++ b/tests/snapshots/local/producers.wast/6.print @@ -0,0 +1,5 @@ +(module + ;; failed to parse custom section `producers`: invalid producers field name: `a + ;; a` (at offset 0x15) + + ) \ No newline at end of file diff --git a/tests/snapshots/local/ref.wat.print b/tests/snapshots/local/ref.wat.print new file mode 100644 index 0000000000..6d26fb0043 --- /dev/null +++ b/tests/snapshots/local/ref.wat.print @@ -0,0 +1,58 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param funcref))) + (func (;0;) (type 0) + (local externref funcref) + ref.null extern + local.set 0 + ref.null func + local.set 1 + ) + (func (;1;) (type 1) (param funcref) + global.get 0 + ref.is_null + drop + local.get 0 + ref.is_null + drop + ) + (func $select-join (;2;) (type 0) + ref.null func + ref.null func + i32.const 0 + select (result funcref) + drop + ref.null extern + ref.null extern + i32.const 0 + select (result externref) + drop + block ;; label = @1 + unreachable + select (result externref) + drop + end + block ;; label = @1 + unreachable + i32.const 0 + select (result externref) + drop + end + block ;; label = @1 + unreachable + ref.null extern + i32.const 0 + select (result externref) + drop + end + block ;; label = @1 + unreachable + ref.null extern + ref.null extern + i32.const 0 + select (result externref) + drop + end + ) + (global (;0;) externref ref.null extern) +) \ No newline at end of file diff --git a/tests/snapshots/local/relaxed-simd.wast/0.print b/tests/snapshots/local/relaxed-simd.wast/0.print new file mode 100644 index 0000000000..bda81d95d8 --- /dev/null +++ b/tests/snapshots/local/relaxed-simd.wast/0.print @@ -0,0 +1,110 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (type (;2;) (func (param v128 v128 v128) (result v128))) + (func $swizzle (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.relaxed_swizzle + ) + (func $i32x4_trunc_f32x4_s (;1;) (type 1) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f32x4_s + ) + (func $i32x4_trunc_f32x4_u (;2;) (type 1) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f32x4_u + ) + (func $i32x4.trunc_f64x2_s_zero (;3;) (type 1) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f64x2_s_zero + ) + (func $i32x4.trunc_f64x2_u_zero (;4;) (type 1) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f64x2_u_zero + ) + (func $f32x4_fma (;5;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f32x4.relaxed_madd + ) + (func $f32x4_fnma (;6;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f32x4.relaxed_nmadd + ) + (func $f64x2_fma (;7;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f64x2.relaxed_madd + ) + (func $f64x2_fnma (;8;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f64x2.relaxed_nmadd + ) + (func $i8x16_laneselect (;9;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i8x16.relaxed_laneselect + ) + (func $i16x8_laneselect (;10;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i16x8.relaxed_laneselect + ) + (func $i32x4_laneselect (;11;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_laneselect + ) + (func $i64x2_laneselect (;12;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i64x2.relaxed_laneselect + ) + (func $f32x4_min (;13;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.relaxed_min + ) + (func $f32x4_max (;14;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.relaxed_max + ) + (func $f64x2_min (;15;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.relaxed_min + ) + (func $f64x2_max (;16;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.relaxed_max + ) + (func $i16x8_q15mulr_s (;17;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.relaxed_q15mulr_s + ) + (func $i16x8_dot_i8x16_i7x16_s (;18;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.relaxed_dot_i8x16_i7x16_s + ) + (func $i32x4_dot_i8x16_i7x16_add_s (;19;) (type 2) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_dot_i8x16_i7x16_add_s + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/select-interesting.wat.print b/tests/snapshots/local/select-interesting.wat.print new file mode 100644 index 0000000000..5bbf3074b0 --- /dev/null +++ b/tests/snapshots/local/select-interesting.wat.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + unreachable + select (result i32) + ) + (func (;1;) (type 0) (result i32) + unreachable + select (result i32) + select + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/select_v128.wat.print b/tests/snapshots/local/select_v128.wat.print new file mode 100644 index 0000000000..e158b1eca6 --- /dev/null +++ b/tests/snapshots/local/select_v128.wat.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32.const 0 + select + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/simd.wat.print b/tests/snapshots/local/simd.wat.print new file mode 100644 index 0000000000..def275610d --- /dev/null +++ b/tests/snapshots/local/simd.wat.print @@ -0,0 +1,259 @@ +(module + (type (;0;) (func (result v128))) + (type (;1;) (func)) + (func (;0;) (type 0) (result v128) + i32.const 4 + v128.load + ) + (func (;1;) (type 0) (result v128) + i32.const 4 + v128.const i32x4 0x11223344 0x55667788 0x99aabbcc 0xddeeff00 + v128.store + i32.const 4 + v128.load + ) + (func (;2;) (type 0) (result v128) + v128.const i32x4 0x0000789a 0xff880330 0x0000ffff 0x0000017f + f64.const 0x1.2p+2 (;=4.5;) + f64x2.replace_lane 0 + ) + (func (;3;) (type 0) (result v128) + v128.const i32x4 0xff00ff01 0xff00ff0f 0xff00ffff 0xff00ff7f + v128.const i32x4 0x00550055 0x00550055 0x00550055 0x00550155 + i8x16.shuffle 16 1 18 3 20 5 22 7 24 9 26 11 28 13 30 15 + ) + (func (;4;) (type 1) + i32.const 0 + v128.load32_zero + drop + i32.const 0 + v128.load64_zero + drop + ) + (func (;5;) (type 1) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.extmul_low_i8x16_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.extmul_high_i8x16_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.extmul_low_i8x16_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.extmul_high_i8x16_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.extmul_low_i16x8_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.extmul_low_i16x8_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.extmul_high_i16x8_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.extmul_high_i16x8_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.extmul_low_i32x4_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.extmul_low_i32x4_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.extmul_high_i32x4_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.extmul_high_i32x4_u + i8x16.neg + drop + i32.const 0 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.load8_lane 15 + i8x16.neg + drop + i32.const 0 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.load16_lane 7 + i8x16.neg + drop + i32.const 0 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.load32_lane 3 + i8x16.neg + drop + i32.const 0 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.load64_lane 1 + i8x16.neg + drop + i32.const 0 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.store8_lane 15 + i32.const 0 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.store16_lane 7 + i32.const 0 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.store32_lane 3 + i32.const 0 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.store64_lane 1 + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + v128.any_true + i32.eqz + drop + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + i8x16.all_true + i32.eqz + drop + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + i16x8.all_true + i32.eqz + drop + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + i32x4.all_true + i32.eqz + drop + v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004 + i64x2.all_true + i32.eqz + drop + v128.const i32x4 0x00000001 0x00000000 0x00000002 0x00000000 + i64x2.bitmask + i32.eqz + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.extend_low_i32x4_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.extend_high_i32x4_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.extend_low_i32x4_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.extend_high_i32x4_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.eq + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.ne + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.lt_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.gt_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.le_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.ge_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.q15mulr_sat_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + f32x4.demote_f64x2_zero + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + f64x2.promote_low_f32x4 + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + f64x2.convert_low_i32x4_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + f64x2.convert_low_i32x4_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.trunc_sat_f64x2_s_zero + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.trunc_sat_f64x2_u_zero + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64x2.abs + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i8x16.popcnt + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.extadd_pairwise_i8x16_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.extadd_pairwise_i8x16_u + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.extadd_pairwise_i16x8_s + i8x16.neg + drop + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.extadd_pairwise_i16x8_u + i8x16.neg + drop + ) + (memory (;0;) 1) + (export "v128_load_0" (func 0)) + (export "v128_store_0" (func 1)) + (export "func_f64x2_replace_lane_0" (func 2)) + (export "func_i8x16_shuffle_0" (func 3)) + (data (;0;) (i32.const 0) "\ff\ff\ff\ff") + (data (;1;) (i32.const 4) "\00\00\ceA") + (data (;2;) (i32.const 8) "\00\00\00\00\00\ff\8f@") + (data (;3;) (i32.const 16) "\ff\ff\ff\ff\ff\ff\ff\ff") +) \ No newline at end of file diff --git a/tests/snapshots/local/simple.wat.print b/tests/snapshots/local/simple.wat.print new file mode 100644 index 0000000000..a05f7992fa --- /dev/null +++ b/tests/snapshots/local/simple.wat.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/table-copy.wat.print b/tests/snapshots/local/table-copy.wat.print new file mode 100644 index 0000000000..2f23c94119 --- /dev/null +++ b/tests/snapshots/local/table-copy.wat.print @@ -0,0 +1,33 @@ +(module $n + (type (;0;) (func (param i32 i32 i32 i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i32 i32) (result i32))) + (import "m" "t" (table $t (;0;) 6 funcref)) + (func $i (;0;) (type 0) (param i32 i32 i32 i32 i32 i32) (result i32) + local.get 3 + ) + (func $j (;1;) (type 0) (param i32 i32 i32 i32 i32 i32) (result i32) + local.get 4 + ) + (func $k (;2;) (type 0) (param i32 i32 i32 i32 i32 i32) (result i32) + local.get 5 + ) + (func (;3;) (type 1) (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + table.copy $t $u + ) + (func (;4;) (type 1) (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + table.copy $u $t + ) + (table $u (;1;) 6 6 funcref) + (export "u" (table $u)) + (export "copy_t_u" (func 3)) + (export "copy_u_t" (func 4)) + (elem (;0;) (table $u) (i32.const 0) func $i $j $k $i $j $k) +) \ No newline at end of file diff --git a/tests/snapshots/local/table-opt-idx.wat.print b/tests/snapshots/local/table-opt-idx.wat.print new file mode 100644 index 0000000000..9f9adb97cb --- /dev/null +++ b/tests/snapshots/local/table-opt-idx.wat.print @@ -0,0 +1,44 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func (;1;) (type 0) + i32.const 0 + table.get 0 + drop + ) + (func (;2;) (type 0) + i32.const 0 + ref.func $f + table.set 0 + ) + (func (;3;) (type 0) + table.size 0 + drop + ) + (func (;4;) (type 0) + ref.func $f + i32.const 0 + table.grow 0 + drop + ) + (func (;5;) (type 0) + i32.const 0 + ref.func $f + i32.const 0 + table.fill 0 + ) + (func (;6;) (type 0) + i32.const 0 + i32.const 0 + i32.const 0 + table.copy + ) + (func (;7;) (type 0) + i32.const 0 + i32.const 0 + i32.const 0 + table.init $a + ) + (table (;0;) 1 funcref) + (elem $a (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/local/try.wat.print b/tests/snapshots/local/try.wat.print new file mode 100644 index 0000000000..e2accdca33 --- /dev/null +++ b/tests/snapshots/local/try.wat.print @@ -0,0 +1,47 @@ +(module $m + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) + try ;; label = @1 + end + ) + (func (;1;) (type 0) + try ;; label = @1 + catch 0 + end + ) + (func (;2;) (type 0) + try ;; label = @1 + catch 0 + rethrow 0 (;@1;) + end + ) + (func (;3;) (type 0) + try ;; label = @1 + catch_all + rethrow 0 (;@1;) + end + ) + (func (;4;) (type 0) + try ;; label = @1 + catch 0 + catch_all + rethrow 0 (;@1;) + end + ) + (func (;5;) (type 0) + try ;; label = @1 + try ;; label = @2 + delegate 0 (;@2;) + catch 0 + end + ) + (func (;6;) (type 1) (result i32) + try (result i32) ;; label = @1 + i32.const 42 + catch 0 + i32.const 42 + end + ) + (tag (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/unreachable-block.wast/0.print b/tests/snapshots/local/unreachable-block.wast/0.print new file mode 100644 index 0000000000..ef70ad1438 --- /dev/null +++ b/tests/snapshots/local/unreachable-block.wast/0.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) + unreachable + i32.const 0 + select + block (type 1) (param i32) ;; label = @1 + unreachable + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/LB.wast/0.print b/tests/snapshots/local/upstream-threads/LB.wast/0.print new file mode 100644 index 0000000000..0c5fc57030 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/LB.wast/0.print @@ -0,0 +1,4 @@ +(module $Mem + (memory (;0;) 1 1 shared) + (export "shared" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/LB.wast/1001.print b/tests/snapshots/local/upstream-threads/LB.wast/1001.print new file mode 100644 index 0000000000..ec4622d267 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/LB.wast/1001.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 10 shared)) + (func (;0;) (type 0) + (local i32) + i32.const 4 + i32.load + local.set 0 + i32.const 0 + i32.const 1 + i32.store + i32.const 24 + local.get 0 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/LB.wast/2001.print b/tests/snapshots/local/upstream-threads/LB.wast/2001.print new file mode 100644 index 0000000000..4d46596968 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/LB.wast/2001.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) + (local i32) + i32.const 0 + i32.load + local.set 0 + i32.const 4 + i32.const 1 + i32.store + i32.const 32 + local.get 0 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/LB.wast/5.print b/tests/snapshots/local/upstream-threads/LB.wast/5.print new file mode 100644 index 0000000000..c5a71158bd --- /dev/null +++ b/tests/snapshots/local/upstream-threads/LB.wast/5.print @@ -0,0 +1,30 @@ +(module $Check + (type (;0;) (func (result i32))) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) (result i32) + (local i32 i32) + i32.const 24 + i32.load + local.set 0 + i32.const 32 + i32.load + local.set 1 + local.get 0 + i32.const 1 + i32.eq + local.get 0 + i32.const 0 + i32.eq + i32.or + local.get 1 + i32.const 1 + i32.eq + local.get 0 + i32.const 0 + i32.eq + i32.or + i32.and + return + ) + (export "check" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/LB_atomic.wast/0.print b/tests/snapshots/local/upstream-threads/LB_atomic.wast/0.print new file mode 100644 index 0000000000..0c5fc57030 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/LB_atomic.wast/0.print @@ -0,0 +1,4 @@ +(module $Mem + (memory (;0;) 1 1 shared) + (export "shared" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/LB_atomic.wast/1001.print b/tests/snapshots/local/upstream-threads/LB_atomic.wast/1001.print new file mode 100644 index 0000000000..970c0227f9 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/LB_atomic.wast/1001.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 10 shared)) + (func (;0;) (type 0) + (local i32) + i32.const 4 + i32.atomic.load + local.set 0 + i32.const 0 + i32.const 1 + i32.atomic.store + i32.const 24 + local.get 0 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/LB_atomic.wast/2001.print b/tests/snapshots/local/upstream-threads/LB_atomic.wast/2001.print new file mode 100644 index 0000000000..30a2619d1b --- /dev/null +++ b/tests/snapshots/local/upstream-threads/LB_atomic.wast/2001.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) + (local i32) + i32.const 0 + i32.atomic.load + local.set 0 + i32.const 4 + i32.const 1 + i32.atomic.store + i32.const 32 + local.get 0 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/LB_atomic.wast/5.print b/tests/snapshots/local/upstream-threads/LB_atomic.wast/5.print new file mode 100644 index 0000000000..e883dc159e --- /dev/null +++ b/tests/snapshots/local/upstream-threads/LB_atomic.wast/5.print @@ -0,0 +1,38 @@ +(module $Check + (type (;0;) (func (result i32))) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) (result i32) + (local i32 i32) + i32.const 24 + i32.load + local.set 0 + i32.const 32 + i32.load + local.set 1 + local.get 0 + i32.const 0 + i32.eq + local.get 1 + i32.const 0 + i32.eq + i32.and + local.get 0 + i32.const 0 + i32.eq + local.get 1 + i32.const 1 + i32.eq + i32.and + local.get 0 + i32.const 1 + i32.eq + local.get 1 + i32.const 0 + i32.eq + i32.and + i32.or + i32.or + return + ) + (export "check" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP.wast/0.print b/tests/snapshots/local/upstream-threads/MP.wast/0.print new file mode 100644 index 0000000000..0c5fc57030 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP.wast/0.print @@ -0,0 +1,4 @@ +(module $Mem + (memory (;0;) 1 1 shared) + (export "shared" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP.wast/1001.print b/tests/snapshots/local/upstream-threads/MP.wast/1001.print new file mode 100644 index 0000000000..b2aa175be7 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP.wast/1001.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 10 shared)) + (func (;0;) (type 0) + i32.const 0 + i32.const 42 + i32.store + i32.const 4 + i32.const 1 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP.wast/2001.print b/tests/snapshots/local/upstream-threads/MP.wast/2001.print new file mode 100644 index 0000000000..48117d8458 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP.wast/2001.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) + (local i32 i32) + i32.const 4 + i32.load + local.set 0 + i32.const 0 + i32.load + local.set 1 + i32.const 24 + local.get 0 + i32.store + i32.const 32 + local.get 1 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP.wast/5.print b/tests/snapshots/local/upstream-threads/MP.wast/5.print new file mode 100644 index 0000000000..f7f4a0a7e3 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP.wast/5.print @@ -0,0 +1,30 @@ +(module $Check + (type (;0;) (func (result i32))) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) (result i32) + (local i32 i32) + i32.const 24 + i32.load + local.set 0 + i32.const 32 + i32.load + local.set 1 + local.get 0 + i32.const 1 + i32.eq + local.get 0 + i32.const 0 + i32.eq + i32.or + local.get 1 + i32.const 42 + i32.eq + local.get 0 + i32.const 0 + i32.eq + i32.or + i32.and + return + ) + (export "check" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP_atomic.wast/0.print b/tests/snapshots/local/upstream-threads/MP_atomic.wast/0.print new file mode 100644 index 0000000000..0c5fc57030 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP_atomic.wast/0.print @@ -0,0 +1,4 @@ +(module $Mem + (memory (;0;) 1 1 shared) + (export "shared" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP_atomic.wast/1001.print b/tests/snapshots/local/upstream-threads/MP_atomic.wast/1001.print new file mode 100644 index 0000000000..1daa6c6003 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP_atomic.wast/1001.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 10 shared)) + (func (;0;) (type 0) + i32.const 0 + i32.const 42 + i32.atomic.store + i32.const 4 + i32.const 1 + i32.atomic.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP_atomic.wast/2001.print b/tests/snapshots/local/upstream-threads/MP_atomic.wast/2001.print new file mode 100644 index 0000000000..746ccf24a9 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP_atomic.wast/2001.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) + (local i32 i32) + i32.const 4 + i32.atomic.load + local.set 0 + i32.const 0 + i32.atomic.load + local.set 1 + i32.const 24 + local.get 0 + i32.store + i32.const 32 + local.get 1 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP_atomic.wast/5.print b/tests/snapshots/local/upstream-threads/MP_atomic.wast/5.print new file mode 100644 index 0000000000..ef8b3cd066 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP_atomic.wast/5.print @@ -0,0 +1,38 @@ +(module $Check + (type (;0;) (func (result i32))) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) (result i32) + (local i32 i32) + i32.const 24 + i32.load + local.set 0 + i32.const 32 + i32.load + local.set 1 + local.get 0 + i32.const 1 + i32.eq + local.get 1 + i32.const 42 + i32.eq + i32.and + local.get 0 + i32.const 0 + i32.eq + local.get 1 + i32.const 0 + i32.eq + i32.and + local.get 0 + i32.const 0 + i32.eq + local.get 1 + i32.const 42 + i32.eq + i32.and + i32.or + i32.or + return + ) + (export "check" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP_wait.wast/0.print b/tests/snapshots/local/upstream-threads/MP_wait.wast/0.print new file mode 100644 index 0000000000..0c5fc57030 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP_wait.wast/0.print @@ -0,0 +1,4 @@ +(module $Mem + (memory (;0;) 1 1 shared) + (export "shared" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP_wait.wast/1001.print b/tests/snapshots/local/upstream-threads/MP_wait.wast/1001.print new file mode 100644 index 0000000000..1daa6c6003 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP_wait.wast/1001.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 10 shared)) + (func (;0;) (type 0) + i32.const 0 + i32.const 42 + i32.atomic.store + i32.const 4 + i32.const 1 + i32.atomic.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP_wait.wast/2001.print b/tests/snapshots/local/upstream-threads/MP_wait.wast/2001.print new file mode 100644 index 0000000000..746ccf24a9 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP_wait.wast/2001.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) + (local i32 i32) + i32.const 4 + i32.atomic.load + local.set 0 + i32.const 0 + i32.atomic.load + local.set 1 + i32.const 24 + local.get 0 + i32.store + i32.const 32 + local.get 1 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/MP_wait.wast/5.print b/tests/snapshots/local/upstream-threads/MP_wait.wast/5.print new file mode 100644 index 0000000000..ef8b3cd066 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/MP_wait.wast/5.print @@ -0,0 +1,38 @@ +(module $Check + (type (;0;) (func (result i32))) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) (result i32) + (local i32 i32) + i32.const 24 + i32.load + local.set 0 + i32.const 32 + i32.load + local.set 1 + local.get 0 + i32.const 1 + i32.eq + local.get 1 + i32.const 42 + i32.eq + i32.and + local.get 0 + i32.const 0 + i32.eq + local.get 1 + i32.const 0 + i32.eq + i32.and + local.get 0 + i32.const 0 + i32.eq + local.get 1 + i32.const 42 + i32.eq + i32.and + i32.or + i32.or + return + ) + (export "check" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/SB.wast/0.print b/tests/snapshots/local/upstream-threads/SB.wast/0.print new file mode 100644 index 0000000000..0c5fc57030 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/SB.wast/0.print @@ -0,0 +1,4 @@ +(module $Mem + (memory (;0;) 1 1 shared) + (export "shared" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/SB.wast/1001.print b/tests/snapshots/local/upstream-threads/SB.wast/1001.print new file mode 100644 index 0000000000..07591f2cd3 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/SB.wast/1001.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 10 shared)) + (func (;0;) (type 0) + (local i32) + i32.const 0 + i32.const 1 + i32.store + i32.const 4 + i32.load + local.set 0 + i32.const 24 + local.get 0 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/SB.wast/2001.print b/tests/snapshots/local/upstream-threads/SB.wast/2001.print new file mode 100644 index 0000000000..c39039b89b --- /dev/null +++ b/tests/snapshots/local/upstream-threads/SB.wast/2001.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) + (local i32) + i32.const 4 + i32.const 1 + i32.store + i32.const 0 + i32.load + local.set 0 + i32.const 32 + local.get 0 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/SB.wast/5.print b/tests/snapshots/local/upstream-threads/SB.wast/5.print new file mode 100644 index 0000000000..c5a71158bd --- /dev/null +++ b/tests/snapshots/local/upstream-threads/SB.wast/5.print @@ -0,0 +1,30 @@ +(module $Check + (type (;0;) (func (result i32))) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) (result i32) + (local i32 i32) + i32.const 24 + i32.load + local.set 0 + i32.const 32 + i32.load + local.set 1 + local.get 0 + i32.const 1 + i32.eq + local.get 0 + i32.const 0 + i32.eq + i32.or + local.get 1 + i32.const 1 + i32.eq + local.get 0 + i32.const 0 + i32.eq + i32.or + i32.and + return + ) + (export "check" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/SB_atomic.wast/0.print b/tests/snapshots/local/upstream-threads/SB_atomic.wast/0.print new file mode 100644 index 0000000000..0c5fc57030 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/SB_atomic.wast/0.print @@ -0,0 +1,4 @@ +(module $Mem + (memory (;0;) 1 1 shared) + (export "shared" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/SB_atomic.wast/1001.print b/tests/snapshots/local/upstream-threads/SB_atomic.wast/1001.print new file mode 100644 index 0000000000..ee37e48867 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/SB_atomic.wast/1001.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 10 shared)) + (func (;0;) (type 0) + (local i32) + i32.const 0 + i32.const 1 + i32.atomic.store + i32.const 4 + i32.atomic.load + local.set 0 + i32.const 24 + local.get 0 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/SB_atomic.wast/2001.print b/tests/snapshots/local/upstream-threads/SB_atomic.wast/2001.print new file mode 100644 index 0000000000..4d51cd1684 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/SB_atomic.wast/2001.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) + (local i32) + i32.const 4 + i32.const 1 + i32.atomic.store + i32.const 0 + i32.atomic.load + local.set 0 + i32.const 32 + local.get 0 + i32.store + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/SB_atomic.wast/5.print b/tests/snapshots/local/upstream-threads/SB_atomic.wast/5.print new file mode 100644 index 0000000000..12c951ddb9 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/SB_atomic.wast/5.print @@ -0,0 +1,38 @@ +(module $Check + (type (;0;) (func (result i32))) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) (result i32) + (local i32 i32) + i32.const 24 + i32.load + local.set 0 + i32.const 32 + i32.load + local.set 1 + local.get 0 + i32.const 1 + i32.eq + local.get 1 + i32.const 1 + i32.eq + i32.and + local.get 0 + i32.const 0 + i32.eq + local.get 1 + i32.const 1 + i32.eq + i32.and + local.get 0 + i32.const 1 + i32.eq + local.get 1 + i32.const 0 + i32.eq + i32.and + i32.or + i32.or + return + ) + (export "check" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/wait_notify.wast/0.print b/tests/snapshots/local/upstream-threads/wait_notify.wast/0.print new file mode 100644 index 0000000000..0c5fc57030 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/wait_notify.wast/0.print @@ -0,0 +1,4 @@ +(module $Mem + (memory (;0;) 1 1 shared) + (export "shared" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/wait_notify.wast/1001.print b/tests/snapshots/local/upstream-threads/wait_notify.wast/1001.print new file mode 100644 index 0000000000..36210b6062 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/wait_notify.wast/1001.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (result i32))) + (import "mem" "shared" (memory (;0;) 1 10 shared)) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.const 0 + i64.const -1 + memory.atomic.wait32 + ) + (export "run" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/local/upstream-threads/wait_notify.wast/2001.print b/tests/snapshots/local/upstream-threads/wait_notify.wast/2001.print new file mode 100644 index 0000000000..4c749f4783 --- /dev/null +++ b/tests/snapshots/local/upstream-threads/wait_notify.wast/2001.print @@ -0,0 +1,22 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (import "mem" "shared" (memory (;0;) 1 1 shared)) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.const 0 + memory.atomic.notify + ) + (func (;1;) (type 1) + loop ;; label = @1 + i32.const 1 + i32.const 0 + i32.const 1 + memory.atomic.notify + i32.ne + br_if 0 (;@1;) + end + ) + (export "notify-0" (func 0)) + (export "notify-1-while" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/local/wat-numerics.wat.print b/tests/snapshots/local/wat-numerics.wat.print new file mode 100644 index 0000000000..4015c24330 --- /dev/null +++ b/tests/snapshots/local/wat-numerics.wat.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 1 1) + (data (;0;) (i32.const 0) "\01\02\03\00\04\00") + (data (;1;) (i32.const 0) "\00\80\ff\00\00\00\80\ff\ff\00\00\00\00\00\00\00\80\ff\ff\ff\ff\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\80\ff\ff\ff\ff\ff\ff\ff\ff\cd\cc\cc=\cd\ccL>\cd\ccL\be\00\00\c0\7f\9a\99\99\99\99\99\b9?\9a\99\99\99\99\99\c9?\9a\99\99\99\99\99\c9\bf\00\00\00\00\00\00\f8\7f\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/address.wast/0.print b/tests/snapshots/testsuite/address.wast/0.print new file mode 100644 index 0000000000..b97b1265e9 --- /dev/null +++ b/tests/snapshots/testsuite/address.wast/0.print @@ -0,0 +1,161 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u + ) + (func (;1;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u + ) + (func (;2;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u offset=1 + ) + (func (;3;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u offset=2 + ) + (func (;4;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u offset=25 + ) + (func (;5;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s + ) + (func (;6;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s + ) + (func (;7;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s offset=1 + ) + (func (;8;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s offset=2 + ) + (func (;9;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s offset=25 + ) + (func (;10;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u + ) + (func (;11;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u align=1 + ) + (func (;12;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u offset=1 align=1 + ) + (func (;13;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u offset=2 + ) + (func (;14;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u offset=25 + ) + (func (;15;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s + ) + (func (;16;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s align=1 + ) + (func (;17;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s offset=1 align=1 + ) + (func (;18;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s offset=2 + ) + (func (;19;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s offset=25 + ) + (func (;20;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load + ) + (func (;21;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load align=1 + ) + (func (;22;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load offset=1 align=1 + ) + (func (;23;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load offset=2 align=2 + ) + (func (;24;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load offset=25 + ) + (func (;25;) (type 1) (param $i i32) + local.get $i + i32.load8_u offset=4294967295 + drop + ) + (func (;26;) (type 1) (param $i i32) + local.get $i + i32.load8_s offset=4294967295 + drop + ) + (func (;27;) (type 1) (param $i i32) + local.get $i + i32.load16_u offset=4294967295 + drop + ) + (func (;28;) (type 1) (param $i i32) + local.get $i + i32.load16_s offset=4294967295 + drop + ) + (func (;29;) (type 1) (param $i i32) + local.get $i + i32.load offset=4294967295 + drop + ) + (memory (;0;) 1) + (export "8u_good1" (func 0)) + (export "8u_good2" (func 1)) + (export "8u_good3" (func 2)) + (export "8u_good4" (func 3)) + (export "8u_good5" (func 4)) + (export "8s_good1" (func 5)) + (export "8s_good2" (func 6)) + (export "8s_good3" (func 7)) + (export "8s_good4" (func 8)) + (export "8s_good5" (func 9)) + (export "16u_good1" (func 10)) + (export "16u_good2" (func 11)) + (export "16u_good3" (func 12)) + (export "16u_good4" (func 13)) + (export "16u_good5" (func 14)) + (export "16s_good1" (func 15)) + (export "16s_good2" (func 16)) + (export "16s_good3" (func 17)) + (export "16s_good4" (func 18)) + (export "16s_good5" (func 19)) + (export "32_good1" (func 20)) + (export "32_good2" (func 21)) + (export "32_good3" (func 22)) + (export "32_good4" (func 23)) + (export "32_good5" (func 24)) + (export "8u_bad" (func 25)) + (export "8s_bad" (func 26)) + (export "16u_bad" (func 27)) + (export "16s_bad" (func 28)) + (export "32_bad" (func 29)) + (data (;0;) (i32.const 0) "abcdefghijklmnopqrstuvwxyz") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/address.wast/220.print b/tests/snapshots/testsuite/address.wast/220.print new file mode 100644 index 0000000000..ccfcc7a769 --- /dev/null +++ b/tests/snapshots/testsuite/address.wast/220.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32) (result f32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load + ) + (func (;1;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load align=1 + ) + (func (;2;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load offset=1 align=1 + ) + (func (;3;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load offset=2 align=2 + ) + (func (;4;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load offset=8 + ) + (func (;5;) (type 1) (param $i i32) + local.get $i + f32.load offset=4294967295 + drop + ) + (memory (;0;) 1) + (export "32_good1" (func 0)) + (export "32_good2" (func 1)) + (export "32_good3" (func 2)) + (export "32_good4" (func 3)) + (export "32_good5" (func 4)) + (export "32_bad" (func 5)) + (data (;0;) (i32.const 0) "\00\00\00\00\00\00\a0\7f\01\00\d0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/address.wast/240.print b/tests/snapshots/testsuite/address.wast/240.print new file mode 100644 index 0000000000..831f78f7ed --- /dev/null +++ b/tests/snapshots/testsuite/address.wast/240.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32) (result f64))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load + ) + (func (;1;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load align=1 + ) + (func (;2;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load offset=1 align=1 + ) + (func (;3;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load offset=2 align=2 + ) + (func (;4;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load offset=18 + ) + (func (;5;) (type 1) (param $i i32) + local.get $i + f64.load offset=4294967295 + drop + ) + (memory (;0;) 1) + (export "64_good1" (func 0)) + (export "64_good2" (func 1)) + (export "64_good3" (func 2)) + (export "64_good4" (func 3)) + (export "64_good5" (func 4)) + (export "64_bad" (func 5)) + (data (;0;) (i32.const 0) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\f4\7f\01\00\00\00\00\00\fc\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/address.wast/93.print b/tests/snapshots/testsuite/address.wast/93.print new file mode 100644 index 0000000000..c976a1180c --- /dev/null +++ b/tests/snapshots/testsuite/address.wast/93.print @@ -0,0 +1,223 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u + ) + (func (;1;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u + ) + (func (;2;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u offset=1 + ) + (func (;3;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u offset=2 + ) + (func (;4;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u offset=25 + ) + (func (;5;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s + ) + (func (;6;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s + ) + (func (;7;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s offset=1 + ) + (func (;8;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s offset=2 + ) + (func (;9;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s offset=25 + ) + (func (;10;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u + ) + (func (;11;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u align=1 + ) + (func (;12;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u offset=1 align=1 + ) + (func (;13;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u offset=2 + ) + (func (;14;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u offset=25 + ) + (func (;15;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s + ) + (func (;16;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s align=1 + ) + (func (;17;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s offset=1 align=1 + ) + (func (;18;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s offset=2 + ) + (func (;19;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s offset=25 + ) + (func (;20;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u + ) + (func (;21;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u align=1 + ) + (func (;22;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u offset=1 align=1 + ) + (func (;23;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u offset=2 align=2 + ) + (func (;24;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u offset=25 + ) + (func (;25;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s + ) + (func (;26;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s align=1 + ) + (func (;27;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s offset=1 align=1 + ) + (func (;28;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s offset=2 align=2 + ) + (func (;29;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s offset=25 + ) + (func (;30;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load + ) + (func (;31;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load align=1 + ) + (func (;32;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load offset=1 align=1 + ) + (func (;33;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load offset=2 align=2 + ) + (func (;34;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load offset=25 + ) + (func (;35;) (type 1) (param $i i32) + local.get $i + i64.load8_u offset=4294967295 + drop + ) + (func (;36;) (type 1) (param $i i32) + local.get $i + i64.load8_s offset=4294967295 + drop + ) + (func (;37;) (type 1) (param $i i32) + local.get $i + i64.load16_u offset=4294967295 + drop + ) + (func (;38;) (type 1) (param $i i32) + local.get $i + i64.load16_s offset=4294967295 + drop + ) + (func (;39;) (type 1) (param $i i32) + local.get $i + i64.load32_u offset=4294967295 + drop + ) + (func (;40;) (type 1) (param $i i32) + local.get $i + i64.load32_s offset=4294967295 + drop + ) + (func (;41;) (type 1) (param $i i32) + local.get $i + i64.load offset=4294967295 + drop + ) + (memory (;0;) 1) + (export "8u_good1" (func 0)) + (export "8u_good2" (func 1)) + (export "8u_good3" (func 2)) + (export "8u_good4" (func 3)) + (export "8u_good5" (func 4)) + (export "8s_good1" (func 5)) + (export "8s_good2" (func 6)) + (export "8s_good3" (func 7)) + (export "8s_good4" (func 8)) + (export "8s_good5" (func 9)) + (export "16u_good1" (func 10)) + (export "16u_good2" (func 11)) + (export "16u_good3" (func 12)) + (export "16u_good4" (func 13)) + (export "16u_good5" (func 14)) + (export "16s_good1" (func 15)) + (export "16s_good2" (func 16)) + (export "16s_good3" (func 17)) + (export "16s_good4" (func 18)) + (export "16s_good5" (func 19)) + (export "32u_good1" (func 20)) + (export "32u_good2" (func 21)) + (export "32u_good3" (func 22)) + (export "32u_good4" (func 23)) + (export "32u_good5" (func 24)) + (export "32s_good1" (func 25)) + (export "32s_good2" (func 26)) + (export "32s_good3" (func 27)) + (export "32s_good4" (func 28)) + (export "32s_good5" (func 29)) + (export "64_good1" (func 30)) + (export "64_good2" (func 31)) + (export "64_good3" (func 32)) + (export "64_good4" (func 33)) + (export "64_good5" (func 34)) + (export "8u_bad" (func 35)) + (export "8s_bad" (func 36)) + (export "16u_bad" (func 37)) + (export "16s_bad" (func 38)) + (export "32u_bad" (func 39)) + (export "32s_bad" (func 40)) + (export "64_bad" (func 41)) + (data (;0;) (i32.const 0) "abcdefghijklmnopqrstuvwxyz") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/0.print b/tests/snapshots/testsuite/align.wast/0.print new file mode 100644 index 0000000000..b979a0af1a --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/0.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.load8_s + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/1.print b/tests/snapshots/testsuite/align.wast/1.print new file mode 100644 index 0000000000..a27c08c4d2 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/1.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.load8_u + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/10.print b/tests/snapshots/testsuite/align.wast/10.print new file mode 100644 index 0000000000..cfe118210f --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/10.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.load32_u + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/106.print b/tests/snapshots/testsuite/align.wast/106.print new file mode 100644 index 0000000000..7608b63f4f --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/106.print @@ -0,0 +1,571 @@ +(module + (type (;0;) (func (param i32) (result f32))) + (type (;1;) (func (param i32) (result f64))) + (type (;2;) (func (param i32 i32) (result i32))) + (type (;3;) (func (param i32 i32) (result i64))) + (func (;0;) (type 0) (param i32) (result f32) + (local f32 f32) + f32.const 0x1.4p+3 (;=10;) + local.set 1 + block $4 ;; label = @1 + block $2 ;; label = @2 + block $1 ;; label = @3 + block $default ;; label = @4 + block $0 ;; label = @5 + local.get 0 + br_table 0 (;@5;) 1 (;@4;) 2 (;@3;) 3 (;@2;) 4 (;@1;) + end + i32.const 0 + local.get 1 + f32.store + i32.const 0 + f32.load + local.set 2 + br 3 (;@1;) + end + i32.const 0 + local.get 1 + f32.store align=1 + i32.const 0 + f32.load align=1 + local.set 2 + br 2 (;@1;) + end + i32.const 0 + local.get 1 + f32.store align=2 + i32.const 0 + f32.load align=2 + local.set 2 + br 1 (;@1;) + end + i32.const 0 + local.get 1 + f32.store + i32.const 0 + f32.load + local.set 2 + end + local.get 2 + ) + (func (;1;) (type 1) (param i32) (result f64) + (local f64 f64) + f64.const 0x1.4p+3 (;=10;) + local.set 1 + block $8 ;; label = @1 + block $4 ;; label = @2 + block $2 ;; label = @3 + block $1 ;; label = @4 + block $default ;; label = @5 + block $0 ;; label = @6 + local.get 0 + br_table 0 (;@6;) 1 (;@5;) 2 (;@4;) 3 (;@3;) 4 (;@2;) 5 (;@1;) + end + i32.const 0 + local.get 1 + f64.store + i32.const 0 + f64.load + local.set 2 + br 4 (;@1;) + end + i32.const 0 + local.get 1 + f64.store align=1 + i32.const 0 + f64.load align=1 + local.set 2 + br 3 (;@1;) + end + i32.const 0 + local.get 1 + f64.store align=2 + i32.const 0 + f64.load align=2 + local.set 2 + br 2 (;@1;) + end + i32.const 0 + local.get 1 + f64.store align=4 + i32.const 0 + f64.load align=4 + local.set 2 + br 1 (;@1;) + end + i32.const 0 + local.get 1 + f64.store + i32.const 0 + f64.load + local.set 2 + end + local.get 2 + ) + (func (;2;) (type 2) (param i32 i32) (result i32) + (local i32 i32) + i32.const 10 + local.set 2 + block $32 ;; label = @1 + block $16u ;; label = @2 + block $16s ;; label = @3 + block $8u ;; label = @4 + block $8s ;; label = @5 + block $0 ;; label = @6 + local.get 0 + br_table 0 (;@6;) 1 (;@5;) 2 (;@4;) 3 (;@3;) 4 (;@2;) 5 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @6 + i32.const 0 + local.get 2 + i32.store8 + i32.const 0 + i32.load8_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @6 + i32.const 0 + local.get 2 + i32.store8 + i32.const 0 + i32.load8_s + local.set 3 + end + br 4 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @5 + i32.const 0 + local.get 2 + i32.store8 + i32.const 0 + i32.load8_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @5 + i32.const 0 + local.get 2 + i32.store8 + i32.const 0 + i32.load8_u + local.set 3 + end + br 3 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @4 + i32.const 0 + local.get 2 + i32.store16 + i32.const 0 + i32.load16_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @4 + i32.const 0 + local.get 2 + i32.store16 align=1 + i32.const 0 + i32.load16_s align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @4 + i32.const 0 + local.get 2 + i32.store16 + i32.const 0 + i32.load16_s + local.set 3 + end + br 2 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @3 + i32.const 0 + local.get 2 + i32.store16 + i32.const 0 + i32.load16_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @3 + i32.const 0 + local.get 2 + i32.store16 align=1 + i32.const 0 + i32.load16_u align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @3 + i32.const 0 + local.get 2 + i32.store16 + i32.const 0 + i32.load16_u + local.set 3 + end + br 1 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i32.store + i32.const 0 + i32.load + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i32.store align=1 + i32.const 0 + i32.load align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i32.store align=2 + i32.const 0 + i32.load align=2 + local.set 3 + end + local.get 1 + i32.const 4 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i32.store + i32.const 0 + i32.load + local.set 3 + end + end + local.get 3 + ) + (func (;3;) (type 3) (param i32 i32) (result i64) + (local i64 i64) + i64.const 10 + local.set 2 + block $64 ;; label = @1 + block $32u ;; label = @2 + block $32s ;; label = @3 + block $16u ;; label = @4 + block $16s ;; label = @5 + block $8u ;; label = @6 + block $8s ;; label = @7 + block $0 ;; label = @8 + local.get 0 + br_table 0 (;@8;) 1 (;@7;) 2 (;@6;) 3 (;@5;) 4 (;@4;) 5 (;@3;) 6 (;@2;) 7 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @8 + i32.const 0 + local.get 2 + i64.store8 + i32.const 0 + i64.load8_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @8 + i32.const 0 + local.get 2 + i64.store8 + i32.const 0 + i64.load8_s + local.set 3 + end + br 6 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @7 + i32.const 0 + local.get 2 + i64.store8 + i32.const 0 + i64.load8_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @7 + i32.const 0 + local.get 2 + i64.store8 + i32.const 0 + i64.load8_u + local.set 3 + end + br 5 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @6 + i32.const 0 + local.get 2 + i64.store16 + i32.const 0 + i64.load16_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @6 + i32.const 0 + local.get 2 + i64.store16 align=1 + i32.const 0 + i64.load16_s align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @6 + i32.const 0 + local.get 2 + i64.store16 + i32.const 0 + i64.load16_s + local.set 3 + end + br 4 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @5 + i32.const 0 + local.get 2 + i64.store16 + i32.const 0 + i64.load16_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @5 + i32.const 0 + local.get 2 + i64.store16 align=1 + i32.const 0 + i64.load16_u align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @5 + i32.const 0 + local.get 2 + i64.store16 + i32.const 0 + i64.load16_u + local.set 3 + end + br 3 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @4 + i32.const 0 + local.get 2 + i64.store32 + i32.const 0 + i64.load32_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @4 + i32.const 0 + local.get 2 + i64.store32 align=1 + i32.const 0 + i64.load32_s align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @4 + i32.const 0 + local.get 2 + i64.store32 align=2 + i32.const 0 + i64.load32_s align=2 + local.set 3 + end + local.get 1 + i32.const 4 + i32.eq + if ;; label = @4 + i32.const 0 + local.get 2 + i64.store32 + i32.const 0 + i64.load32_s + local.set 3 + end + br 2 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @3 + i32.const 0 + local.get 2 + i64.store32 + i32.const 0 + i64.load32_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @3 + i32.const 0 + local.get 2 + i64.store32 align=1 + i32.const 0 + i64.load32_u align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @3 + i32.const 0 + local.get 2 + i64.store32 align=2 + i32.const 0 + i64.load32_u align=2 + local.set 3 + end + local.get 1 + i32.const 4 + i32.eq + if ;; label = @3 + i32.const 0 + local.get 2 + i64.store32 + i32.const 0 + i64.load32_u + local.set 3 + end + br 1 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i64.store + i32.const 0 + i64.load + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i64.store align=1 + i32.const 0 + i64.load align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i64.store align=2 + i32.const 0 + i64.load align=2 + local.set 3 + end + local.get 1 + i32.const 4 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i64.store align=4 + i32.const 0 + i64.load align=4 + local.set 3 + end + local.get 1 + i32.const 8 + i32.eq + if ;; label = @2 + i32.const 0 + local.get 2 + i64.store + i32.const 0 + i64.load + local.set 3 + end + end + local.get 3 + ) + (memory (;0;) 1) + (export "f32_align_switch" (func 0)) + (export "f64_align_switch" (func 1)) + (export "i32_align_switch" (func 2)) + (export "i64_align_switch" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/11.print b/tests/snapshots/testsuite/align.wast/11.print new file mode 100644 index 0000000000..29908f1c42 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/11.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.load + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/12.print b/tests/snapshots/testsuite/align.wast/12.print new file mode 100644 index 0000000000..fa55dfedfd --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/12.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + f32.load + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/13.print b/tests/snapshots/testsuite/align.wast/13.print new file mode 100644 index 0000000000..f2526fb8dc --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/13.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + f64.load + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/14.print b/tests/snapshots/testsuite/align.wast/14.print new file mode 100644 index 0000000000..f49a5f11cc --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/14.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.const 1 + i32.store8 + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/15.print b/tests/snapshots/testsuite/align.wast/15.print new file mode 100644 index 0000000000..cf128860fa --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/15.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.const 1 + i32.store16 + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/153.print b/tests/snapshots/testsuite/align.wast/153.print new file mode 100644 index 0000000000..c1118180d9 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/153.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param i32 i64))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32 i64) + local.get 0 + local.get 1 + i64.store align=4 + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load + ) + (memory (;0;) 1) + (export "store" (func 0)) + (export "load" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/16.print b/tests/snapshots/testsuite/align.wast/16.print new file mode 100644 index 0000000000..aae6567e83 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/16.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.const 1 + i32.store + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/17.print b/tests/snapshots/testsuite/align.wast/17.print new file mode 100644 index 0000000000..64ea912d28 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/17.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.const 1 + i64.store8 + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/18.print b/tests/snapshots/testsuite/align.wast/18.print new file mode 100644 index 0000000000..f5238a0623 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/18.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.const 1 + i64.store16 + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/19.print b/tests/snapshots/testsuite/align.wast/19.print new file mode 100644 index 0000000000..736e855f70 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/19.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.const 1 + i64.store32 + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/2.print b/tests/snapshots/testsuite/align.wast/2.print new file mode 100644 index 0000000000..80ebd09e2f --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/2.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.load16_s + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/20.print b/tests/snapshots/testsuite/align.wast/20.print new file mode 100644 index 0000000000..cde0f603a7 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/20.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.const 1 + i64.store + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/21.print b/tests/snapshots/testsuite/align.wast/21.print new file mode 100644 index 0000000000..58b5c60d84 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/21.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + f32.const 0x1p+0 (;=1;) + f32.store + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/22.print b/tests/snapshots/testsuite/align.wast/22.print new file mode 100644 index 0000000000..31eedeec02 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/22.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + f64.const 0x1p+0 (;=1;) + f64.store + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/3.print b/tests/snapshots/testsuite/align.wast/3.print new file mode 100644 index 0000000000..1fc3265aec --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/3.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.load16_u + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/4.print b/tests/snapshots/testsuite/align.wast/4.print new file mode 100644 index 0000000000..92c45614a8 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/4.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.load + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/5.print b/tests/snapshots/testsuite/align.wast/5.print new file mode 100644 index 0000000000..4629e351eb --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/5.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.load8_s + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/6.print b/tests/snapshots/testsuite/align.wast/6.print new file mode 100644 index 0000000000..34cf5125fa --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/6.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.load8_u + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/7.print b/tests/snapshots/testsuite/align.wast/7.print new file mode 100644 index 0000000000..85e16b29a6 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/7.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.load16_s + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/8.print b/tests/snapshots/testsuite/align.wast/8.print new file mode 100644 index 0000000000..ef4fcee99d --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/8.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.load16_u + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/align.wast/9.print b/tests/snapshots/testsuite/align.wast/9.print new file mode 100644 index 0000000000..d0c13c7172 --- /dev/null +++ b/tests/snapshots/testsuite/align.wast/9.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i64.load32_s + drop + ) + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/0.print b/tests/snapshots/testsuite/binary-leb128.wast/0.print new file mode 100644 index 0000000000..f18cc54f26 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/0.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/1.print b/tests/snapshots/testsuite/binary-leb128.wast/1.print new file mode 100644 index 0000000000..f18cc54f26 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/1.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/10.print b/tests/snapshots/testsuite/binary-leb128.wast/10.print new file mode 100644 index 0000000000..2dce17095d --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/10.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/11.print b/tests/snapshots/testsuite/binary-leb128.wast/11.print new file mode 100644 index 0000000000..2dce17095d --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/11.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/12.print b/tests/snapshots/testsuite/binary-leb128.wast/12.print new file mode 100644 index 0000000000..2dce17095d --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/12.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/13.print b/tests/snapshots/testsuite/binary-leb128.wast/13.print new file mode 100644 index 0000000000..f81d636a1b --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/13.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/14.print b/tests/snapshots/testsuite/binary-leb128.wast/14.print new file mode 100644 index 0000000000..274e55d61c --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/14.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "f1" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/15.print b/tests/snapshots/testsuite/binary-leb128.wast/15.print new file mode 100644 index 0000000000..274e55d61c --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/15.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "f1" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/16.print b/tests/snapshots/testsuite/binary-leb128.wast/16.print new file mode 100644 index 0000000000..f81d636a1b --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/16.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/17.print b/tests/snapshots/testsuite/binary-leb128.wast/17.print new file mode 100644 index 0000000000..e6b79c4e23 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/17.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/18.print b/tests/snapshots/testsuite/binary-leb128.wast/18.print new file mode 100644 index 0000000000..98af8924d4 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/18.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const -1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/19.print b/tests/snapshots/testsuite/binary-leb128.wast/19.print new file mode 100644 index 0000000000..e6b79c4e23 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/19.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/2.print b/tests/snapshots/testsuite/binary-leb128.wast/2.print new file mode 100644 index 0000000000..c7d9da5741 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/2.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 2 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/20.print b/tests/snapshots/testsuite/binary-leb128.wast/20.print new file mode 100644 index 0000000000..98af8924d4 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/20.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const -1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/21.print b/tests/snapshots/testsuite/binary-leb128.wast/21.print new file mode 100644 index 0000000000..78d137b2e3 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/21.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i64 i64.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/22.print b/tests/snapshots/testsuite/binary-leb128.wast/22.print new file mode 100644 index 0000000000..9d1440296d --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/22.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i64 i64.const -1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/23.print b/tests/snapshots/testsuite/binary-leb128.wast/23.print new file mode 100644 index 0000000000..78d137b2e3 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/23.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i64 i64.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/24.print b/tests/snapshots/testsuite/binary-leb128.wast/24.print new file mode 100644 index 0000000000..9d1440296d --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/24.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i64 i64.const -1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/3.print b/tests/snapshots/testsuite/binary-leb128.wast/3.print new file mode 100644 index 0000000000..c7d9da5741 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/3.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 2 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/4.print b/tests/snapshots/testsuite/binary-leb128.wast/4.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/4.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/5.print b/tests/snapshots/testsuite/binary-leb128.wast/5.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/5.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/6.print b/tests/snapshots/testsuite/binary-leb128.wast/6.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/6.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/7.print b/tests/snapshots/testsuite/binary-leb128.wast/7.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/7.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/8.print b/tests/snapshots/testsuite/binary-leb128.wast/8.print new file mode 100644 index 0000000000..7435af94e8 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/8.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32 i64) (result i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/81.print b/tests/snapshots/testsuite/binary-leb128.wast/81.print new file mode 100644 index 0000000000..160d4c8f91 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/81.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + unreachable + i32.trunc_sat_f32_s + unreachable + i32.trunc_sat_f32_u + unreachable + i64.trunc_sat_f64_s + unreachable + i64.trunc_sat_f64_u + unreachable + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/83.print b/tests/snapshots/testsuite/binary-leb128.wast/83.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/83.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/84.print b/tests/snapshots/testsuite/binary-leb128.wast/84.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/84.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/85.print b/tests/snapshots/testsuite/binary-leb128.wast/85.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/85.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/86.print b/tests/snapshots/testsuite/binary-leb128.wast/86.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/86.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/87.print b/tests/snapshots/testsuite/binary-leb128.wast/87.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/87.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/88.print b/tests/snapshots/testsuite/binary-leb128.wast/88.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/88.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/89.print b/tests/snapshots/testsuite/binary-leb128.wast/89.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/89.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary-leb128.wast/9.print b/tests/snapshots/testsuite/binary-leb128.wast/9.print new file mode 100644 index 0000000000..7435af94e8 --- /dev/null +++ b/tests/snapshots/testsuite/binary-leb128.wast/9.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32 i64) (result i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/0.print b/tests/snapshots/testsuite/binary.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/1.print b/tests/snapshots/testsuite/binary.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/103.print b/tests/snapshots/testsuite/binary.wast/103.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/103.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/108.print b/tests/snapshots/testsuite/binary.wast/108.print new file mode 100644 index 0000000000..17f0618fdf --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/108.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 1 + if ;; label = @2 + i32.const 1 + br_table 2 (;@0;) + end + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/110.print b/tests/snapshots/testsuite/binary.wast/110.print new file mode 100644 index 0000000000..a2354a64c3 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/110.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (start 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/2.print b/tests/snapshots/testsuite/binary.wast/2.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/2.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/3.print b/tests/snapshots/testsuite/binary.wast/3.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/3.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/55.print b/tests/snapshots/testsuite/binary.wast/55.print new file mode 100644 index 0000000000..3171d8f4fb --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/55.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local f32 f32) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/60.print b/tests/snapshots/testsuite/binary.wast/60.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/60.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/61.print b/tests/snapshots/testsuite/binary.wast/61.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/61.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/68.print b/tests/snapshots/testsuite/binary.wast/68.print new file mode 100644 index 0000000000..a72fa86b64 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/68.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/69.print b/tests/snapshots/testsuite/binary.wast/69.print new file mode 100644 index 0000000000..8a3ff91247 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/69.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.null func)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/70.print b/tests/snapshots/testsuite/binary.wast/70.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/70.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/73.print b/tests/snapshots/testsuite/binary.wast/73.print new file mode 100644 index 0000000000..c47d05badc --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/73.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/82.print b/tests/snapshots/testsuite/binary.wast/82.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/82.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/87.print b/tests/snapshots/testsuite/binary.wast/87.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/87.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/93.print b/tests/snapshots/testsuite/binary.wast/93.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/93.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/96.print b/tests/snapshots/testsuite/binary.wast/96.print new file mode 100644 index 0000000000..1270a74e97 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/96.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/binary.wast/99.print b/tests/snapshots/testsuite/binary.wast/99.print new file mode 100644 index 0000000000..a0fe812a51 --- /dev/null +++ b/tests/snapshots/testsuite/binary.wast/99.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/block.wast/0.print b/tests/snapshots/testsuite/block.wast/0.print new file mode 100644 index 0000000000..631864b31a --- /dev/null +++ b/tests/snapshots/testsuite/block.wast/0.print @@ -0,0 +1,714 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type $block-sig-1 (;1;) (func)) + (type $block-sig-2 (;2;) (func (result i32))) + (type $block-sig-3 (;3;) (func (param i32))) + (type $block-sig-4 (;4;) (func (param i32 f64 i32) (result i32 f64 i32))) + (type (;5;) (func (result i32 i64 i32))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (result i32 i32))) + (type (;8;) (func (result f32 f32))) + (type (;9;) (func (result i32 i32 i64))) + (type (;10;) (func (param i32 i32) (result i32 i32))) + (func $dummy (;0;) (type $block-sig-1)) + (func (;1;) (type $block-sig-1) + block ;; label = @1 + end + block $l ;; label = @1 + end + ) + (func (;2;) (type $block-sig-2) (result i32) + block ;; label = @1 + nop + end + block (result i32) ;; label = @1 + i32.const 7 + end + ) + (func (;3;) (type $block-sig-2) (result i32) + block ;; label = @1 + call $dummy + call $dummy + call $dummy + call $dummy + end + block (result i32) ;; label = @1 + call $dummy + call $dummy + call $dummy + i32.const 7 + call $dummy + end + drop + block (type 5) (result i32 i64 i32) ;; label = @1 + call $dummy + call $dummy + call $dummy + i32.const 8 + call $dummy + call $dummy + call $dummy + call $dummy + i64.const 7 + call $dummy + call $dummy + call $dummy + call $dummy + i32.const 9 + call $dummy + end + drop + drop + ) + (func (;4;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + block ;; label = @2 + call $dummy + block ;; label = @3 + end + nop + end + block (result i32) ;; label = @2 + call $dummy + i32.const 9 + end + end + ) + (func (;5;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + block (result i32) ;; label = @3 + block (result i32) ;; label = @4 + block (result i32) ;; label = @5 + block (result i32) ;; label = @6 + block (result i32) ;; label = @7 + block (result i32) ;; label = @8 + block (result i32) ;; label = @9 + block (result i32) ;; label = @10 + block (result i32) ;; label = @11 + block (result i32) ;; label = @12 + block (result i32) ;; label = @13 + block (result i32) ;; label = @14 + block (result i32) ;; label = @15 + block (result i32) ;; label = @16 + block (result i32) ;; label = @17 + block (result i32) ;; label = @18 + block (result i32) ;; label = @19 + block (result i32) ;; label = @20 + block (result i32) ;; label = @21 + block (result i32) ;; label = @22 + block (result i32) ;; label = @23 + block (result i32) ;; label = @24 + block (result i32) ;; label = @25 + block (result i32) ;; label = @26 + block (result i32) ;; label = @27 + block (result i32) ;; label = @28 + block (result i32) ;; label = @29 + block (result i32) ;; label = @30 + block (result i32) ;; label = @31 + block (result i32) ;; label = @32 + block (result i32) ;; label = @33 + block (result i32) ;; label = @34 + block (result i32) ;; label = @35 + block (result i32) ;; label = @36 + block (result i32) ;; label = @37 + block (result i32) ;; label = @38 + call $dummy + i32.const 150 + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + ) + (func (;6;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + end + i32.const 2 + i32.const 3 + select + ) + (func (;7;) (type $block-sig-2) (result i32) + i32.const 2 + block (result i32) ;; label = @1 + i32.const 1 + end + i32.const 3 + select + ) + (func (;8;) (type $block-sig-2) (result i32) + i32.const 2 + i32.const 3 + block (result i32) ;; label = @1 + i32.const 1 + end + select + ) + (func (;9;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 1 + end + call $dummy + call $dummy + end + ) + (func (;10;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + block (result i32) ;; label = @2 + i32.const 1 + end + call $dummy + end + ) + (func (;11;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + block (result i32) ;; label = @2 + i32.const 1 + end + end + ) + (func (;12;) (type $block-sig-1) + block (result i32) ;; label = @1 + i32.const 1 + end + if ;; label = @1 + call $dummy + end + ) + (func (;13;) (type $block-sig-2) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 1 + end + else + i32.const 2 + end + ) + (func (;14;) (type $block-sig-2) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 2 + else + block (result i32) ;; label = @2 + i32.const 1 + end + end + ) + (func (;15;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 1 + end + i32.const 2 + br_if 0 (;@1;) + end + ) + (func (;16;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + block (result i32) ;; label = @2 + i32.const 1 + end + br_if 0 (;@1;) + end + ) + (func (;17;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 1 + end + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;18;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + block (result i32) ;; label = @2 + i32.const 1 + end + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;19;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;20;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 1 + end + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;21;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + block (result i32) ;; label = @2 + i32.const 1 + end + i32.const 0 + call_indirect (type $check) + end + ) + (func (;22;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + block (result i32) ;; label = @2 + i32.const 0 + end + call_indirect (type $check) + end + ) + (func (;23;) (type $block-sig-1) + block (result i32) ;; label = @1 + i32.const 1 + end + i32.const 1 + i32.store + ) + (func (;24;) (type $block-sig-1) + i32.const 10 + block (result i32) ;; label = @1 + i32.const 1 + end + i32.store + ) + (func (;25;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + end + memory.grow + ) + (func $f (;26;) (type 6) (param i32) (result i32) + local.get 0 + ) + (func (;27;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + end + call $f + ) + (func (;28;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + end + return + ) + (func (;29;) (type $block-sig-1) + block (result i32) ;; label = @1 + i32.const 1 + end + drop + ) + (func (;30;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 1 + end + br 0 (;@1;) + end + ) + (func (;31;) (type $block-sig-2) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + end + local.set 0 + local.get 0 + ) + (func (;32;) (type $block-sig-2) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + end + local.tee 0 + ) + (func (;33;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + end + global.set $a + global.get $a + ) + (func (;34;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + end + i32.load + ) + (func (;35;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 13 + end + i32.ctz + ) + (func (;36;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 3 + end + block (result i32) ;; label = @1 + call $dummy + i32.const 4 + end + i32.mul + ) + (func (;37;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 13 + end + i32.eqz + ) + (func (;38;) (type $block-sig-2) (result i32) + block (result f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + end + block (result f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + end + f32.gt + ) + (func (;39;) (type $block-sig-2) (result i32) + block (type 7) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + end + i32.mul + ) + (func (;40;) (type $block-sig-2) (result i32) + block (type 8) (result f32 f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + call $dummy + f32.const 0x1.8p+1 (;=3;) + end + f32.gt + ) + (func (;41;) (type $block-sig-2) (result i32) + block (type 7) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + end + i32.const 5 + i32.add + i32.mul + ) + (func (;42;) (type $block-sig-2) (result i32) + block ;; label = @1 + br 0 (;@1;) + unreachable + end + block ;; label = @1 + i32.const 1 + br_if 0 (;@1;) + unreachable + end + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + unreachable + end + block ;; label = @1 + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + unreachable + end + i32.const 19 + ) + (func (;43;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 18 + br 0 (;@1;) + i32.const 19 + end + ) + (func (;44;) (type 9) (result i32 i32 i64) + block (type 9) (result i32 i32 i64) ;; label = @1 + i32.const 18 + i32.const -18 + i64.const 18 + br 0 (;@1;) + i32.const 19 + i32.const -19 + i64.const 19 + end + ) + (func (;45;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 18 + br 0 (;@1;) + i32.const 19 + br 0 (;@1;) + i32.const 20 + i32.const 0 + br_if 0 (;@1;) + drop + i32.const 20 + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 21 + br 0 (;@1;) + i32.const 22 + i32.const 4 + br_table 0 (;@1;) + i32.const 23 + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 21 + end + ) + (func (;46;) (type $block-sig-2) (result i32) + (local i32) + i32.const 0 + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 1 + br 1 (;@1;) + end + end + i32.add + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + block ;; label = @2 + br 0 (;@2;) + end + i32.const 2 + end + i32.add + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + i32.const 4 + br 0 (;@1;) + i32.ctz + end + i32.add + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 8 + br 1 (;@1;) + end + i32.ctz + end + i32.add + local.set 0 + local.get 0 + ) + (func (;47;) (type $block-sig-2) (result i32) + i32.const 1 + block (type 6) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + end + ) + (func (;48;) (type $block-sig-2) (result i32) + i32.const 1 + i32.const 2 + block (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + end + ) + (func (;49;) (type $block-sig-2) (result i32) + i32.const 1 + i32.const 2 + block (type 10) (param i32 i32) (result i32 i32) ;; label = @1 + end + i32.add + ) + (func (;50;) (type $block-sig-2) (result i32) + i32.const 1 + block (type 6) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + br 0 (;@1;) + end + ) + (func (;51;) (type $block-sig-2) (result i32) + i32.const 1 + i32.const 2 + block (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + br 0 (;@1;) + end + ) + (func (;52;) (type $block-sig-2) (result i32) + i32.const 1 + i32.const 2 + block (type 10) (param i32 i32) (result i32 i32) ;; label = @1 + br 0 (;@1;) + end + i32.add + ) + (func (;53;) (type $block-sig-2) (result i32) + (local i32) + block ;; label = @1 + i32.const 1 + local.set 0 + local.get 0 + i32.const 3 + i32.mul + local.set 0 + local.get 0 + i32.const 5 + i32.sub + local.set 0 + local.get 0 + i32.const 7 + i32.mul + local.set 0 + br 0 (;@1;) + local.get 0 + i32.const 100 + i32.mul + local.set 0 + end + local.get 0 + i32.const -14 + i32.eq + ) + (func (;54;) (type $block-sig-1) + block (type $block-sig-1) ;; label = @1 + end + block (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + end + block (type $block-sig-3) (param i32) ;; label = @1 + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + block (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + block (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + end + block (type $block-sig-3) (param i32) ;; label = @1 + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + block (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "empty" (func 1)) + (export "singular" (func 2)) + (export "multi" (func 3)) + (export "nested" (func 4)) + (export "deep" (func 5)) + (export "as-select-first" (func 6)) + (export "as-select-mid" (func 7)) + (export "as-select-last" (func 8)) + (export "as-loop-first" (func 9)) + (export "as-loop-mid" (func 10)) + (export "as-loop-last" (func 11)) + (export "as-if-condition" (func 12)) + (export "as-if-then" (func 13)) + (export "as-if-else" (func 14)) + (export "as-br_if-first" (func 15)) + (export "as-br_if-last" (func 16)) + (export "as-br_table-first" (func 17)) + (export "as-br_table-last" (func 18)) + (export "as-call_indirect-first" (func 20)) + (export "as-call_indirect-mid" (func 21)) + (export "as-call_indirect-last" (func 22)) + (export "as-store-first" (func 23)) + (export "as-store-last" (func 24)) + (export "as-memory.grow-value" (func 25)) + (export "as-call-value" (func 27)) + (export "as-return-value" (func 28)) + (export "as-drop-operand" (func 29)) + (export "as-br-value" (func 30)) + (export "as-local.set-value" (func 31)) + (export "as-local.tee-value" (func 32)) + (export "as-global.set-value" (func 33)) + (export "as-load-operand" (func 34)) + (export "as-unary-operand" (func 35)) + (export "as-binary-operand" (func 36)) + (export "as-test-operand" (func 37)) + (export "as-compare-operand" (func 38)) + (export "as-binary-operands" (func 39)) + (export "as-compare-operands" (func 40)) + (export "as-mixed-operands" (func 41)) + (export "break-bare" (func 42)) + (export "break-value" (func 43)) + (export "break-multi-value" (func 44)) + (export "break-repeated" (func 45)) + (export "break-inner" (func 46)) + (export "param" (func 47)) + (export "params" (func 48)) + (export "params-id" (func 49)) + (export "param-break" (func 50)) + (export "params-break" (func 51)) + (export "params-id-break" (func 52)) + (export "effects" (func 53)) + (export "type-use" (func 54)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/br.wast/0.print b/tests/snapshots/testsuite/br.wast/0.print new file mode 100644 index 0000000000..48ac602c7d --- /dev/null +++ b/tests/snapshots/testsuite/br.wast/0.print @@ -0,0 +1,719 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (type (;4;) (func (result f32))) + (type (;5;) (func (result f64))) + (type (;6;) (func (result f64 f64))) + (type (;7;) (func (result i32 i64))) + (type (;8;) (func (param i32 i32) (result i32))) + (func $dummy (;0;) (type 1)) + (func (;1;) (type 1) + block ;; label = @1 + br 0 (;@1;) + i32.ctz + drop + end + ) + (func (;2;) (type 1) + block ;; label = @1 + br 0 (;@1;) + i64.ctz + drop + end + ) + (func (;3;) (type 1) + block ;; label = @1 + br 0 (;@1;) + f32.neg + drop + end + ) + (func (;4;) (type 1) + block ;; label = @1 + br 0 (;@1;) + f64.neg + drop + end + ) + (func (;5;) (type 1) + block ;; label = @1 + br 0 (;@1;) + i32.add + drop + end + ) + (func (;6;) (type 1) + block ;; label = @1 + br 0 (;@1;) + i64.add + drop + end + ) + (func (;7;) (type 1) + block ;; label = @1 + br 0 (;@1;) + f32.add + drop + end + ) + (func (;8;) (type 1) + block ;; label = @1 + br 0 (;@1;) + f64.add + drop + end + ) + (func (;9;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + br 0 (;@1;) + i32.ctz + end + ) + (func (;10;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 2 + br 0 (;@1;) + i64.ctz + end + ) + (func (;11;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.8p+1 (;=3;) + br 0 (;@1;) + f32.neg + end + ) + (func (;12;) (type 5) (result f64) + block (result f64) ;; label = @1 + f64.const 0x1p+2 (;=4;) + br 0 (;@1;) + f64.neg + end + ) + (func (;13;) (type 6) (result f64 f64) + block (type 6) (result f64 f64) ;; label = @1 + f64.const 0x1p+2 (;=4;) + f64.const 0x1.4p+2 (;=5;) + br 0 (;@1;) + f64.add + f64.const 0x1.8p+2 (;=6;) + end + ) + (func (;14;) (type 1) + block ;; label = @1 + br 0 (;@1;) + call $dummy + end + ) + (func (;15;) (type 1) + block ;; label = @1 + call $dummy + br 0 (;@1;) + call $dummy + end + ) + (func (;16;) (type 1) + block ;; label = @1 + nop + call $dummy + br 0 (;@1;) + end + ) + (func (;17;) (type 2) (result i32) + block (result i32) ;; label = @1 + nop + call $dummy + i32.const 2 + br 0 (;@1;) + end + ) + (func (;18;) (type 2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 3 + br 1 (;@1;) + i32.const 2 + end + end + ) + (func (;19;) (type 2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + call $dummy + i32.const 4 + br 1 (;@1;) + i32.const 2 + end + end + ) + (func (;20;) (type 2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + nop + call $dummy + i32.const 5 + br 1 (;@1;) + end + end + ) + (func (;21;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 9 + br 0 (;@1;) + br 0 (;@1;) + end + ) + (func (;22;) (type 1) + block ;; label = @1 + br 0 (;@1;) + br_if 0 (;@1;) + end + ) + (func (;23;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 8 + br 0 (;@1;) + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;24;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 9 + br 0 (;@1;) + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;25;) (type 1) + block ;; label = @1 + br 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;26;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + br 0 (;@1;) + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;27;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 11 + br 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;28;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 7 + br 0 (;@1;) + return + end + ) + (func (;29;) (type 7) (result i32 i64) + i32.const 2 + block (result i64) ;; label = @1 + i32.const 1 + i64.const 7 + br 0 (;@1;) + return + end + ) + (func (;30;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + br 0 (;@1;) + if (result i32) ;; label = @2 + i32.const 0 + else + i32.const 1 + end + end + ) + (func (;31;) (type 8) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + i32.const 3 + br 1 (;@1;) + else + local.get 1 + end + end + ) + (func (;32;) (type 8) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + local.get 1 + else + i32.const 4 + br 1 (;@1;) + end + end + ) + (func (;33;) (type 8) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + i32.const 5 + br 0 (;@1;) + local.get 0 + local.get 1 + select + end + ) + (func (;34;) (type 8) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + i32.const 6 + br 0 (;@1;) + local.get 1 + select + end + ) + (func (;35;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 7 + br 0 (;@1;) + select + end + ) + (func (;36;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 8 + br 0 (;@1;) + select + end + ) + (func $f (;37;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;38;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 12 + br 0 (;@1;) + i32.const 2 + i32.const 3 + call $f + end + ) + (func (;39;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 13 + br 0 (;@1;) + i32.const 3 + call $f + end + ) + (func (;40;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 14 + br 0 (;@1;) + call $f + end + ) + (func (;41;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 15 + br 0 (;@1;) + call $f + end + ) + (func (;42;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 20 + br 0 (;@1;) + i32.const 1 + i32.const 2 + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;43;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 21 + br 0 (;@1;) + i32.const 2 + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;44;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 22 + br 0 (;@1;) + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;45;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 2 + i32.const 23 + br 0 (;@1;) + call_indirect (type $sig) + end + ) + (func (;46;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 24 + br 0 (;@1;) + call_indirect (type $sig) + end + ) + (func (;47;) (type 2) (result i32) + (local f32) + block (result i32) ;; label = @1 + i32.const 17 + br 0 (;@1;) + local.set 0 + i32.const -1 + end + ) + (func (;48;) (type 2) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + br 0 (;@1;) + local.tee 0 + end + ) + (func (;49;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + br 0 (;@1;) + global.set $a + end + ) + (func (;50;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.b33334p+0 (;=1.7;) + br 0 (;@1;) + f32.load + end + ) + (func (;51;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 30 + br 0 (;@1;) + i64.load8_s + end + ) + (func (;52;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 30 + br 0 (;@1;) + f64.const 0x1.cp+2 (;=7;) + f64.store + i32.const -1 + end + ) + (func (;53;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 31 + br 0 (;@1;) + i64.store + i32.const -1 + end + ) + (func (;54;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 32 + br 0 (;@1;) + i64.store + i32.const -1 + end + ) + (func (;55;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 32 + br 0 (;@1;) + i32.const 7 + i32.store8 + i32.const -1 + end + ) + (func (;56;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 33 + br 0 (;@1;) + i64.store16 + i32.const -1 + end + ) + (func (;57;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 34 + br 0 (;@1;) + i64.store16 + i32.const -1 + end + ) + (func (;58;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.b33334p+1 (;=3.4;) + br 0 (;@1;) + f32.neg + end + ) + (func (;59;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + br 0 (;@1;) + i32.const 10 + i32.add + end + ) + (func (;60;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 10 + i64.const 45 + br 0 (;@1;) + i64.sub + end + ) + (func (;61;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 46 + br 0 (;@1;) + i32.add + end + ) + (func (;62;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 44 + br 0 (;@1;) + i32.eqz + end + ) + (func (;63;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 43 + br 0 (;@1;) + f64.const 0x1.4p+3 (;=10;) + f64.le + end + ) + (func (;64;) (type 2) (result i32) + block (result i32) ;; label = @1 + f32.const 0x1.4p+3 (;=10;) + i32.const 42 + br 0 (;@1;) + f32.ne + end + ) + (func (;65;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 44 + br 0 (;@1;) + f64.le + end + ) + (func (;66;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 41 + br 0 (;@1;) + i32.wrap_i64 + end + ) + (func (;67;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 40 + br 0 (;@1;) + memory.grow + end + ) + (func (;68;) (type 2) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + call $dummy + i32.const 4 + i32.const 8 + br 0 (;@1;) + i32.add + end + i32.add + ) + (func (;69;) (type 2) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + block (result i32) ;; label = @2 + i32.const 4 + drop + i32.const 8 + br 1 (;@1;) + br 0 (;@2;) + end + drop + i32.const 16 + end + i32.add + ) + (func (;70;) (type 2) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + block (result i32) ;; label = @2 + i32.const 4 + drop + i32.const 8 + br 1 (;@1;) + i32.const 1 + br_if 0 (;@2;) + drop + i32.const 32 + end + drop + i32.const 16 + end + i32.add + ) + (func (;71;) (type 2) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + i32.const 4 + i32.const 8 + br 0 (;@1;) + br_if 0 (;@1;) + drop + i32.const 16 + end + i32.add + ) + (func (;72;) (type 2) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + block (result i32) ;; label = @2 + i32.const 4 + drop + i32.const 8 + br 1 (;@1;) + i32.const 1 + br_table 0 (;@2;) + end + drop + i32.const 16 + end + i32.add + ) + (func (;73;) (type 2) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + i32.const 4 + i32.const 8 + br 0 (;@1;) + br_table 0 (;@1;) + i32.const 16 + end + i32.add + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "type-i32" (func 1)) + (export "type-i64" (func 2)) + (export "type-f32" (func 3)) + (export "type-f64" (func 4)) + (export "type-i32-i32" (func 5)) + (export "type-i64-i64" (func 6)) + (export "type-f32-f32" (func 7)) + (export "type-f64-f64" (func 8)) + (export "type-i32-value" (func 9)) + (export "type-i64-value" (func 10)) + (export "type-f32-value" (func 11)) + (export "type-f64-value" (func 12)) + (export "type-f64-f64-value" (func 13)) + (export "as-block-first" (func 14)) + (export "as-block-mid" (func 15)) + (export "as-block-last" (func 16)) + (export "as-block-value" (func 17)) + (export "as-loop-first" (func 18)) + (export "as-loop-mid" (func 19)) + (export "as-loop-last" (func 20)) + (export "as-br-value" (func 21)) + (export "as-br_if-cond" (func 22)) + (export "as-br_if-value" (func 23)) + (export "as-br_if-value-cond" (func 24)) + (export "as-br_table-index" (func 25)) + (export "as-br_table-value" (func 26)) + (export "as-br_table-value-index" (func 27)) + (export "as-return-value" (func 28)) + (export "as-return-values" (func 29)) + (export "as-if-cond" (func 30)) + (export "as-if-then" (func 31)) + (export "as-if-else" (func 32)) + (export "as-select-first" (func 33)) + (export "as-select-second" (func 34)) + (export "as-select-cond" (func 35)) + (export "as-select-all" (func 36)) + (export "as-call-first" (func 38)) + (export "as-call-mid" (func 39)) + (export "as-call-last" (func 40)) + (export "as-call-all" (func 41)) + (export "as-call_indirect-func" (func 42)) + (export "as-call_indirect-first" (func 43)) + (export "as-call_indirect-mid" (func 44)) + (export "as-call_indirect-last" (func 45)) + (export "as-call_indirect-all" (func 46)) + (export "as-local.set-value" (func 47)) + (export "as-local.tee-value" (func 48)) + (export "as-global.set-value" (func 49)) + (export "as-load-address" (func 50)) + (export "as-loadN-address" (func 51)) + (export "as-store-address" (func 52)) + (export "as-store-value" (func 53)) + (export "as-store-both" (func 54)) + (export "as-storeN-address" (func 55)) + (export "as-storeN-value" (func 56)) + (export "as-storeN-both" (func 57)) + (export "as-unary-operand" (func 58)) + (export "as-binary-left" (func 59)) + (export "as-binary-right" (func 60)) + (export "as-binary-both" (func 61)) + (export "as-test-operand" (func 62)) + (export "as-compare-left" (func 63)) + (export "as-compare-right" (func 64)) + (export "as-compare-both" (func 65)) + (export "as-convert-operand" (func 66)) + (export "as-memory.grow-size" (func 67)) + (export "nested-block-value" (func 68)) + (export "nested-br-value" (func 69)) + (export "nested-br_if-value" (func 70)) + (export "nested-br_if-value-cond" (func 71)) + (export "nested-br_table-value" (func 72)) + (export "nested-br_table-value-index" (func 73)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/br_if.wast/0.print b/tests/snapshots/testsuite/br_if.wast/0.print new file mode 100644 index 0000000000..2530d97738 --- /dev/null +++ b/tests/snapshots/testsuite/br_if.wast/0.print @@ -0,0 +1,703 @@ +(module + (type $check (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (type (;4;) (func (result f32))) + (type (;5;) (func (result f64))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (param i32))) + (type (;8;) (func (param i32 i32))) + (func $dummy (;0;) (type 1)) + (func (;1;) (type 1) + block ;; label = @1 + i32.const 0 + i32.const 1 + br_if 0 (;@1;) + i32.ctz + drop + end + ) + (func (;2;) (type 1) + block ;; label = @1 + i64.const 0 + i32.const 1 + br_if 0 (;@1;) + i64.ctz + drop + end + ) + (func (;3;) (type 1) + block ;; label = @1 + f32.const 0x0p+0 (;=0;) + i32.const 1 + br_if 0 (;@1;) + f32.neg + drop + end + ) + (func (;4;) (type 1) + block ;; label = @1 + f64.const 0x0p+0 (;=0;) + i32.const 1 + br_if 0 (;@1;) + f64.neg + drop + end + ) + (func (;5;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_if 0 (;@1;) + i32.ctz + end + ) + (func (;6;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 2 + i32.const 1 + br_if 0 (;@1;) + i64.ctz + end + ) + (func (;7;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.8p+1 (;=3;) + i32.const 1 + br_if 0 (;@1;) + f32.neg + end + ) + (func (;8;) (type 5) (result f64) + block (result f64) ;; label = @1 + f64.const 0x1p+2 (;=4;) + i32.const 1 + br_if 0 (;@1;) + f64.neg + end + ) + (func (;9;) (type 6) (param i32) (result i32) + block ;; label = @1 + local.get 0 + br_if 0 (;@1;) + i32.const 2 + return + end + i32.const 3 + ) + (func (;10;) (type 6) (param i32) (result i32) + block ;; label = @1 + call $dummy + local.get 0 + br_if 0 (;@1;) + i32.const 2 + return + end + i32.const 3 + ) + (func (;11;) (type 7) (param i32) + block ;; label = @1 + call $dummy + call $dummy + local.get 0 + br_if 0 (;@1;) + end + ) + (func (;12;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + local.get 0 + br_if 0 (;@1;) + drop + i32.const 11 + return + end + ) + (func (;13;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 20 + local.get 0 + br_if 0 (;@1;) + drop + i32.const 21 + return + end + ) + (func (;14;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 11 + local.get 0 + br_if 0 (;@1;) + end + ) + (func (;15;) (type 6) (param i32) (result i32) + block ;; label = @1 + loop ;; label = @2 + local.get 0 + br_if 1 (;@1;) + i32.const 2 + return + end + end + i32.const 3 + ) + (func (;16;) (type 6) (param i32) (result i32) + block ;; label = @1 + loop ;; label = @2 + call $dummy + local.get 0 + br_if 1 (;@1;) + i32.const 2 + return + end + end + i32.const 4 + ) + (func (;17;) (type 7) (param i32) + loop ;; label = @1 + call $dummy + local.get 0 + br_if 1 (;@0;) + end + ) + (func (;18;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + br_if 0 (;@1;) + br 0 (;@1;) + end + ) + (func (;19;) (type 1) + block ;; label = @1 + i32.const 1 + i32.const 1 + br_if 0 (;@1;) + br_if 0 (;@1;) + end + ) + (func (;20;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + br_if 0 (;@1;) + i32.const 3 + br_if 0 (;@1;) + drop + i32.const 4 + end + ) + (func (;21;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 1 + local.get 0 + br_if 0 (;@1;) + br_if 0 (;@1;) + drop + i32.const 4 + end + ) + (func (;22;) (type 1) + block ;; label = @1 + i32.const 1 + i32.const 2 + br_if 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;23;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + br_if 0 (;@1;) + i32.const 3 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 4 + end + ) + (func (;24;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 1 + i32.const 3 + br_if 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) + i32.const 4 + end + ) + (func (;25;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 1 + i32.const 2 + br_if 0 (;@1;) + return + end + ) + (func (;26;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + local.get 0 + br_if 0 (;@1;) + if (result i32) ;; label = @2 + i32.const 2 + else + i32.const 3 + end + end + ) + (func (;27;) (type 8) (param i32 i32) + block ;; label = @1 + local.get 0 + if ;; label = @2 + local.get 1 + br_if 1 (;@1;) + else + call $dummy + end + end + ) + (func (;28;) (type 8) (param i32 i32) + block ;; label = @1 + local.get 0 + if ;; label = @2 + call $dummy + else + local.get 1 + br_if 1 (;@1;) + end + end + ) + (func (;29;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + i32.const 10 + br_if 0 (;@1;) + i32.const 2 + local.get 0 + select + end + ) + (func (;30;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 3 + i32.const 10 + br_if 0 (;@1;) + local.get 0 + select + end + ) + (func (;31;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 10 + br_if 0 (;@1;) + select + end + ) + (func $f (;32;) (type $check) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;33;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 12 + i32.const 1 + br_if 0 (;@1;) + i32.const 2 + i32.const 3 + call $f + end + ) + (func (;34;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 13 + i32.const 1 + br_if 0 (;@1;) + i32.const 3 + call $f + end + ) + (func (;35;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 14 + i32.const 1 + br_if 0 (;@1;) + call $f + end + ) + (func $func (;36;) (type $check) (param i32 i32 i32) (result i32) + local.get 0 + ) + (func (;37;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 4 + i32.const 10 + br_if 0 (;@1;) + i32.const 1 + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;38;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 4 + i32.const 10 + br_if 0 (;@1;) + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;39;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 4 + i32.const 10 + br_if 0 (;@1;) + i32.const 0 + call_indirect (type $check) + end + ) + (func (;40;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 4 + i32.const 10 + br_if 0 (;@1;) + call_indirect (type $check) + end + ) + (func (;41;) (type 6) (param i32) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 17 + local.get 0 + br_if 0 (;@1;) + local.set 0 + i32.const -1 + end + ) + (func (;42;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + local.get 0 + br_if 0 (;@1;) + local.tee 0 + i32.const -1 + return + end + ) + (func (;43;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + local.get 0 + br_if 0 (;@1;) + global.set $a + i32.const -1 + return + end + ) + (func (;44;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_if 0 (;@1;) + i32.load + end + ) + (func (;45;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 30 + i32.const 1 + br_if 0 (;@1;) + i32.load8_s + end + ) + (func (;46;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 30 + i32.const 1 + br_if 0 (;@1;) + i32.const 7 + i32.store + i32.const -1 + end + ) + (func (;47;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 31 + i32.const 1 + br_if 0 (;@1;) + i32.store + i32.const -1 + end + ) + (func (;48;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 32 + i32.const 1 + br_if 0 (;@1;) + i32.const 7 + i32.store8 + i32.const -1 + end + ) + (func (;49;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 33 + i32.const 1 + br_if 0 (;@1;) + i32.store16 + i32.const -1 + end + ) + (func (;50;) (type 5) (result f64) + block (result f64) ;; label = @1 + f64.const 0x1p+0 (;=1;) + i32.const 1 + br_if 0 (;@1;) + f64.neg + end + ) + (func (;51;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_if 0 (;@1;) + i32.const 10 + i32.add + end + ) + (func (;52;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 1 + i32.const 1 + br_if 0 (;@1;) + i32.sub + end + ) + (func (;53;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + br_if 0 (;@1;) + i32.eqz + end + ) + (func (;54;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_if 0 (;@1;) + i32.const 10 + i32.le_u + end + ) + (func (;55;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 1 + i32.const 42 + br_if 0 (;@1;) + i32.ne + end + ) + (func (;56;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_if 0 (;@1;) + memory.grow + end + ) + (func (;57;) (type 6) (param i32) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + i32.const 4 + block (result i32) ;; label = @2 + i32.const 8 + local.get 0 + br_if 1 (;@1;) + drop + i32.const 16 + end + i32.add + end + i32.add + ) + (func (;58;) (type 6) (param i32) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + block (result i32) ;; label = @2 + i32.const 8 + local.get 0 + br_if 1 (;@1;) + drop + i32.const 4 + end + br 0 (;@1;) + i32.const 16 + end + i32.add + ) + (func (;59;) (type 6) (param i32) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + block (result i32) ;; label = @2 + i32.const 8 + local.get 0 + br_if 1 (;@1;) + drop + i32.const 4 + end + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 16 + end + i32.add + ) + (func (;60;) (type 6) (param i32) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + i32.const 4 + block (result i32) ;; label = @2 + i32.const 8 + local.get 0 + br_if 1 (;@1;) + drop + i32.const 1 + end + br_if 0 (;@1;) + drop + i32.const 16 + end + i32.add + ) + (func (;61;) (type 6) (param i32) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + block (result i32) ;; label = @2 + i32.const 8 + local.get 0 + br_if 1 (;@1;) + drop + i32.const 4 + end + i32.const 1 + br_table 0 (;@1;) + i32.const 16 + end + i32.add + ) + (func (;62;) (type 6) (param i32) (result i32) + i32.const 1 + block (result i32) ;; label = @1 + i32.const 2 + drop + i32.const 4 + block (result i32) ;; label = @2 + i32.const 8 + local.get 0 + br_if 1 (;@1;) + drop + i32.const 1 + end + br_table 0 (;@1;) + i32.const 16 + end + i32.add + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "type-i32" (func 1)) + (export "type-i64" (func 2)) + (export "type-f32" (func 3)) + (export "type-f64" (func 4)) + (export "type-i32-value" (func 5)) + (export "type-i64-value" (func 6)) + (export "type-f32-value" (func 7)) + (export "type-f64-value" (func 8)) + (export "as-block-first" (func 9)) + (export "as-block-mid" (func 10)) + (export "as-block-last" (func 11)) + (export "as-block-first-value" (func 12)) + (export "as-block-mid-value" (func 13)) + (export "as-block-last-value" (func 14)) + (export "as-loop-first" (func 15)) + (export "as-loop-mid" (func 16)) + (export "as-loop-last" (func 17)) + (export "as-br-value" (func 18)) + (export "as-br_if-cond" (func 19)) + (export "as-br_if-value" (func 20)) + (export "as-br_if-value-cond" (func 21)) + (export "as-br_table-index" (func 22)) + (export "as-br_table-value" (func 23)) + (export "as-br_table-value-index" (func 24)) + (export "as-return-value" (func 25)) + (export "as-if-cond" (func 26)) + (export "as-if-then" (func 27)) + (export "as-if-else" (func 28)) + (export "as-select-first" (func 29)) + (export "as-select-second" (func 30)) + (export "as-select-cond" (func 31)) + (export "as-call-first" (func 33)) + (export "as-call-mid" (func 34)) + (export "as-call-last" (func 35)) + (export "as-call_indirect-func" (func 37)) + (export "as-call_indirect-first" (func 38)) + (export "as-call_indirect-mid" (func 39)) + (export "as-call_indirect-last" (func 40)) + (export "as-local.set-value" (func 41)) + (export "as-local.tee-value" (func 42)) + (export "as-global.set-value" (func 43)) + (export "as-load-address" (func 44)) + (export "as-loadN-address" (func 45)) + (export "as-store-address" (func 46)) + (export "as-store-value" (func 47)) + (export "as-storeN-address" (func 48)) + (export "as-storeN-value" (func 49)) + (export "as-unary-operand" (func 50)) + (export "as-binary-left" (func 51)) + (export "as-binary-right" (func 52)) + (export "as-test-operand" (func 53)) + (export "as-compare-left" (func 54)) + (export "as-compare-right" (func 55)) + (export "as-memory.grow-size" (func 56)) + (export "nested-block-value" (func 57)) + (export "nested-br-value" (func 58)) + (export "nested-br_if-value" (func 59)) + (export "nested-br_if-value-cond" (func 60)) + (export "nested-br_table-value" (func 61)) + (export "nested-br_table-value-index" (func 62)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/br_table.wast/0.print b/tests/snapshots/testsuite/br_table.wast/0.print new file mode 100644 index 0000000000..4e0bef0218 --- /dev/null +++ b/tests/snapshots/testsuite/br_table.wast/0.print @@ -0,0 +1,845 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (type (;4;) (func (result f32))) + (type (;5;) (func (result f64))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (param i32 i32) (result i32))) + (type (;8;) (func (param i32 externref) (result externref))) + (func $dummy (;0;) (type 1)) + (func (;1;) (type 1) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.ctz + drop + end + ) + (func (;2;) (type 1) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i64.ctz + drop + end + ) + (func (;3;) (type 1) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f32.neg + drop + end + ) + (func (;4;) (type 1) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.neg + drop + end + ) + (func (;5;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.ctz + end + ) + (func (;6;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 2 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i64.ctz + end + ) + (func (;7;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.8p+1 (;=3;) + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f32.neg + end + ) + (func (;8;) (type 5) (result f64) + block (result f64) ;; label = @1 + f64.const 0x1p+2 (;=4;) + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.neg + end + ) + (func (;9;) (type 6) (param i32) (result i32) + block ;; label = @1 + local.get 0 + br_table 0 (;@1;) + i32.const 21 + return + end + i32.const 22 + ) + (func (;10;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 33 + local.get 0 + br_table 0 (;@1;) + i32.const 31 + end + ) + (func (;11;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) + i32.const 21 + return + end + i32.const 20 + return + end + i32.const 22 + ) + (func (;12;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 33 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) + i32.const 31 + return + end + drop + i32.const 32 + end + ) + (func (;13;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + local.get 0 + br_table 3 (;@2;) 2 (;@3;) 1 (;@4;) 0 (;@5;) 4 (;@1;) + i32.const 99 + return + end + i32.const 100 + return + end + i32.const 101 + return + end + i32.const 102 + return + end + i32.const 103 + return + end + i32.const 104 + ) + (func (;14;) (type 6) (param i32) (result i32) + (local i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + block (result i32) ;; label = @3 + block (result i32) ;; label = @4 + block (result i32) ;; label = @5 + i32.const 200 + local.get 0 + br_table 3 (;@2;) 2 (;@3;) 1 (;@4;) 0 (;@5;) 4 (;@1;) + local.get 1 + i32.const 99 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 10 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 11 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 12 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 13 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 14 + i32.add + ) + (func (;15;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) + i32.const -1 + return + end + i32.const 0 + return + end + i32.const 1 + return + ) + (func (;16;) (type 1) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + call $dummy + end + ) + (func (;17;) (type 1) + block ;; label = @1 + call $dummy + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + call $dummy + end + ) + (func (;18;) (type 1) + block ;; label = @1 + nop + call $dummy + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;19;) (type 2) (result i32) + block (result i32) ;; label = @1 + nop + call $dummy + i32.const 2 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;20;) (type 2) (result i32) + loop (result i32) ;; label = @1 + i32.const 3 + i32.const 0 + br_table 1 (;@0;) 1 (;@0;) + i32.const 1 + end + ) + (func (;21;) (type 2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 4 + i32.const -1 + br_table 1 (;@0;) 1 (;@0;) 1 (;@0;) + i32.const 2 + end + ) + (func (;22;) (type 2) (result i32) + loop (result i32) ;; label = @1 + nop + call $dummy + i32.const 5 + i32.const 1 + br_table 1 (;@0;) 1 (;@0;) 1 (;@0;) + end + ) + (func (;23;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 9 + i32.const 0 + br_table 0 (;@1;) + br 0 (;@1;) + end + ) + (func (;24;) (type 1) + block ;; label = @1 + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + br_if 0 (;@1;) + end + ) + (func (;25;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 8 + i32.const 0 + br_table 0 (;@1;) + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;26;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 9 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;27;) (type 1) + block ;; label = @1 + i32.const 1 + br_table 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;28;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 0 + br_table 0 (;@1;) + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;29;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 11 + i32.const 1 + br_table 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;30;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 7 + i32.const 0 + br_table 0 (;@1;) + return + end + ) + (func (;31;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + br_table 0 (;@1;) + if (result i32) ;; label = @2 + i32.const 0 + else + i32.const 1 + end + end + ) + (func (;32;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + i32.const 3 + i32.const 0 + br_table 1 (;@1;) + else + local.get 1 + end + end + ) + (func (;33;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + local.get 1 + else + i32.const 4 + i32.const 0 + br_table 1 (;@1;) 0 (;@2;) + end + end + ) + (func (;34;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + i32.const 5 + i32.const 0 + br_table 0 (;@1;) + local.get 0 + local.get 1 + select + end + ) + (func (;35;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + i32.const 6 + i32.const 1 + br_table 0 (;@1;) + local.get 1 + select + end + ) + (func (;36;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 7 + i32.const 1 + br_table 0 (;@1;) + select + end + ) + (func $f (;37;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;38;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 12 + i32.const 1 + br_table 0 (;@1;) + i32.const 2 + i32.const 3 + call $f + end + ) + (func (;39;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 13 + i32.const 1 + br_table 0 (;@1;) + i32.const 3 + call $f + end + ) + (func (;40;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 14 + i32.const 1 + br_table 0 (;@1;) + call $f + end + ) + (func (;41;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 20 + i32.const 1 + br_table 0 (;@1;) + i32.const 1 + i32.const 2 + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;42;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 21 + i32.const 1 + br_table 0 (;@1;) + i32.const 2 + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;43;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 22 + i32.const 1 + br_table 0 (;@1;) + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;44;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 2 + i32.const 23 + i32.const 1 + br_table 0 (;@1;) + call_indirect (type $sig) + end + ) + (func (;45;) (type 2) (result i32) + (local f32) + block (result i32) ;; label = @1 + i32.const 17 + i32.const 1 + br_table 0 (;@1;) + local.set 0 + i32.const -1 + end + ) + (func (;46;) (type 2) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_table 0 (;@1;) + local.set 0 + i32.const -1 + end + ) + (func (;47;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_table 0 (;@1;) + global.set $a + i32.const -1 + end + ) + (func (;48;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.b33334p+0 (;=1.7;) + i32.const 1 + br_table 0 (;@1;) + f32.load + end + ) + (func (;49;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 30 + i32.const 1 + br_table 0 (;@1;) + i64.load8_s + end + ) + (func (;50;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 30 + i32.const 1 + br_table 0 (;@1;) + f64.const 0x1.cp+2 (;=7;) + f64.store + i32.const -1 + end + ) + (func (;51;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 31 + i32.const 1 + br_table 0 (;@1;) + i64.store + i32.const -1 + end + ) + (func (;52;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 32 + i32.const 0 + br_table 0 (;@1;) + i32.const 7 + i32.store8 + i32.const -1 + end + ) + (func (;53;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 33 + i32.const 0 + br_table 0 (;@1;) + i64.store16 + i32.const -1 + end + ) + (func (;54;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.b33334p+1 (;=3.4;) + i32.const 0 + br_table 0 (;@1;) + f32.neg + end + ) + (func (;55;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.const 10 + i32.add + end + ) + (func (;56;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 10 + i64.const 45 + i32.const 0 + br_table 0 (;@1;) + i64.sub + end + ) + (func (;57;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 44 + i32.const 0 + br_table 0 (;@1;) + i32.eqz + end + ) + (func (;58;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 43 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.const 0x1.4p+3 (;=10;) + f64.le + end + ) + (func (;59;) (type 2) (result i32) + block (result i32) ;; label = @1 + f32.const 0x1.4p+3 (;=10;) + i32.const 42 + i32.const 0 + br_table 0 (;@1;) + f32.ne + end + ) + (func (;60;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 41 + i32.const 0 + br_table 0 (;@1;) + i32.wrap_i64 + end + ) + (func (;61;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 40 + i32.const 0 + br_table 0 (;@1;) + memory.grow + end + ) + (func (;62;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const -1 + drop + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + i32.const 16 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.add + end + i32.add + end + i32.add + end + ) + (func (;63;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 2 (;@1;) 1 (;@2;) 0 (;@3;) + br 0 (;@3;) + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;64;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 1 + br_if 0 (;@3;) + drop + i32.const 32 + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;65;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + i32.const 4 + i32.const 8 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) + br_if 0 (;@2;) + drop + i32.const 16 + end + i32.add + end + ) + (func (;66;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 1 + br_table 0 (;@3;) + i32.const 32 + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;67;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + i32.const 4 + i32.const 8 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) + br_table 0 (;@2;) + i32.const 16 + end + i32.add + end + ) + (func (;68;) (type 6) (param i32) (result i32) + loop (result i32) ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 0 (;@2;) + end + i32.const 0 + end + local.set 0 + loop (result i32) ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 1 (;@1;) + end + i32.const 3 + end + ) + (func (;69;) (type 8) (param i32 externref) (result externref) + block $l1 (result externref) ;; label = @1 + block $l2 (result externref) ;; label = @2 + local.get 1 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 1 (;@1;) + end + end + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "type-i32" (func 1)) + (export "type-i64" (func 2)) + (export "type-f32" (func 3)) + (export "type-f64" (func 4)) + (export "type-i32-value" (func 5)) + (export "type-i64-value" (func 6)) + (export "type-f32-value" (func 7)) + (export "type-f64-value" (func 8)) + (export "empty" (func 9)) + (export "empty-value" (func 10)) + (export "singleton" (func 11)) + (export "singleton-value" (func 12)) + (export "multiple" (func 13)) + (export "multiple-value" (func 14)) + (export "large" (func 15)) + (export "as-block-first" (func 16)) + (export "as-block-mid" (func 17)) + (export "as-block-last" (func 18)) + (export "as-block-value" (func 19)) + (export "as-loop-first" (func 20)) + (export "as-loop-mid" (func 21)) + (export "as-loop-last" (func 22)) + (export "as-br-value" (func 23)) + (export "as-br_if-cond" (func 24)) + (export "as-br_if-value" (func 25)) + (export "as-br_if-value-cond" (func 26)) + (export "as-br_table-index" (func 27)) + (export "as-br_table-value" (func 28)) + (export "as-br_table-value-index" (func 29)) + (export "as-return-value" (func 30)) + (export "as-if-cond" (func 31)) + (export "as-if-then" (func 32)) + (export "as-if-else" (func 33)) + (export "as-select-first" (func 34)) + (export "as-select-second" (func 35)) + (export "as-select-cond" (func 36)) + (export "as-call-first" (func 38)) + (export "as-call-mid" (func 39)) + (export "as-call-last" (func 40)) + (export "as-call_indirect-first" (func 41)) + (export "as-call_indirect-mid" (func 42)) + (export "as-call_indirect-last" (func 43)) + (export "as-call_indirect-func" (func 44)) + (export "as-local.set-value" (func 45)) + (export "as-local.tee-value" (func 46)) + (export "as-global.set-value" (func 47)) + (export "as-load-address" (func 48)) + (export "as-loadN-address" (func 49)) + (export "as-store-address" (func 50)) + (export "as-store-value" (func 51)) + (export "as-storeN-address" (func 52)) + (export "as-storeN-value" (func 53)) + (export "as-unary-operand" (func 54)) + (export "as-binary-left" (func 55)) + (export "as-binary-right" (func 56)) + (export "as-test-operand" (func 57)) + (export "as-compare-left" (func 58)) + (export "as-compare-right" (func 59)) + (export "as-convert-operand" (func 60)) + (export "as-memory.grow-size" (func 61)) + (export "nested-block-value" (func 62)) + (export "nested-br-value" (func 63)) + (export "nested-br_if-value" (func 64)) + (export "nested-br_if-value-cond" (func 65)) + (export "nested-br_table-value" (func 66)) + (export "nested-br_table-value-index" (func 67)) + (export "nested-br_table-loop-block" (func 68)) + (export "meet-externref" (func 69)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/0.print b/tests/snapshots/testsuite/bulk.wast/0.print new file mode 100644 index 0000000000..b3d88d122c --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/0.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) "foo") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/1.print b/tests/snapshots/testsuite/bulk.wast/1.print new file mode 100644 index 0000000000..bb2726500e --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/1.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) + (table (;0;) 3 funcref) + (elem (;0;) funcref (ref.func 0) (ref.null func) (ref.func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/18.print b/tests/snapshots/testsuite/bulk.wast/18.print new file mode 100644 index 0000000000..a9cc078805 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/18.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "copy" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 0) "\aa\bb\cc\dd") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/2.print b/tests/snapshots/testsuite/bulk.wast/2.print new file mode 100644 index 0000000000..6197f73e0f --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/2.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + memory.fill + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1) + (export "fill" (func 0)) + (export "load8_u" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/47.print b/tests/snapshots/testsuite/bulk.wast/47.print new file mode 100644 index 0000000000..8638c7841f --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/47.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + memory.init 0 + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1) + (export "init" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) "\aa\bb\cc\dd") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/60.print b/tests/snapshots/testsuite/bulk.wast/60.print new file mode 100644 index 0000000000..94afd55127 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/60.print @@ -0,0 +1,29 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) + data.drop $p + ) + (func (;1;) (type 1) (param $len i32) + i32.const 0 + i32.const 0 + local.get $len + memory.init $p + ) + (func (;2;) (type 0) + data.drop $a + ) + (func (;3;) (type 1) (param $len i32) + i32.const 0 + i32.const 0 + local.get $len + memory.init $a + ) + (memory (;0;) 1) + (export "drop_passive" (func 0)) + (export "init_passive" (func 1)) + (export "drop_active" (func 2)) + (export "init_active" (func 3)) + (data $p (;0;) "x") + (data $a (;1;) (i32.const 0) "x") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/71.print b/tests/snapshots/testsuite/bulk.wast/71.print new file mode 100644 index 0000000000..2070d69d74 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/71.print @@ -0,0 +1,71 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + data.drop 64 + ) + (data (;0;) "") + (data (;1;) "") + (data (;2;) "") + (data (;3;) "") + (data (;4;) "") + (data (;5;) "") + (data (;6;) "") + (data (;7;) "") + (data (;8;) "") + (data (;9;) "") + (data (;10;) "") + (data (;11;) "") + (data (;12;) "") + (data (;13;) "") + (data (;14;) "") + (data (;15;) "") + (data (;16;) "") + (data (;17;) "") + (data (;18;) "") + (data (;19;) "") + (data (;20;) "") + (data (;21;) "") + (data (;22;) "") + (data (;23;) "") + (data (;24;) "") + (data (;25;) "") + (data (;26;) "") + (data (;27;) "") + (data (;28;) "") + (data (;29;) "") + (data (;30;) "") + (data (;31;) "") + (data (;32;) "") + (data (;33;) "") + (data (;34;) "") + (data (;35;) "") + (data (;36;) "") + (data (;37;) "") + (data (;38;) "") + (data (;39;) "") + (data (;40;) "") + (data (;41;) "") + (data (;42;) "") + (data (;43;) "") + (data (;44;) "") + (data (;45;) "") + (data (;46;) "") + (data (;47;) "") + (data (;48;) "") + (data (;49;) "") + (data (;50;) "") + (data (;51;) "") + (data (;52;) "") + (data (;53;) "") + (data (;54;) "") + (data (;55;) "") + (data (;56;) "") + (data (;57;) "") + (data (;58;) "") + (data (;59;) "") + (data (;60;) "") + (data (;61;) "") + (data (;62;) "") + (data (;63;) "") + (data (;64;) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/72.print b/tests/snapshots/testsuite/bulk.wast/72.print new file mode 100644 index 0000000000..887cec49a2 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/72.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + data.drop 0 + ) + (data (;0;) "goodbye") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/73.print b/tests/snapshots/testsuite/bulk.wast/73.print new file mode 100644 index 0000000000..05ee8eb6f6 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/73.print @@ -0,0 +1,25 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32 i32))) + (type (;2;) (func (param i32) (result i32))) + (func $zero (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $one (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 1) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + table.init 0 + ) + (func (;3;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table (;0;) 3 funcref) + (export "init" (func 2)) + (export "call" (func 3)) + (elem (;0;) funcref (ref.func $zero) (ref.func $one) (ref.func $zero) (ref.func $one)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/85.print b/tests/snapshots/testsuite/bulk.wast/85.print new file mode 100644 index 0000000000..87c705fcb8 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/85.print @@ -0,0 +1,30 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (func $f (;0;) (type 0)) + (func (;1;) (type 0) + elem.drop $p + ) + (func (;2;) (type 1) (param $len i32) + i32.const 0 + i32.const 0 + local.get $len + table.init $p + ) + (func (;3;) (type 0) + elem.drop $a + ) + (func (;4;) (type 1) (param $len i32) + i32.const 0 + i32.const 0 + local.get $len + table.init $a + ) + (table (;0;) 1 funcref) + (export "drop_passive" (func 1)) + (export "init_passive" (func 2)) + (export "drop_active" (func 3)) + (export "init_active" (func 4)) + (elem $p (;0;) funcref (ref.func $f)) + (elem $a (;1;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/96.print b/tests/snapshots/testsuite/bulk.wast/96.print new file mode 100644 index 0000000000..658b22a593 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/96.print @@ -0,0 +1,71 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + elem.drop 64 + ) + (elem (;0;) funcref) + (elem (;1;) funcref) + (elem (;2;) funcref) + (elem (;3;) funcref) + (elem (;4;) funcref) + (elem (;5;) funcref) + (elem (;6;) funcref) + (elem (;7;) funcref) + (elem (;8;) funcref) + (elem (;9;) funcref) + (elem (;10;) funcref) + (elem (;11;) funcref) + (elem (;12;) funcref) + (elem (;13;) funcref) + (elem (;14;) funcref) + (elem (;15;) funcref) + (elem (;16;) funcref) + (elem (;17;) funcref) + (elem (;18;) funcref) + (elem (;19;) funcref) + (elem (;20;) funcref) + (elem (;21;) funcref) + (elem (;22;) funcref) + (elem (;23;) funcref) + (elem (;24;) funcref) + (elem (;25;) funcref) + (elem (;26;) funcref) + (elem (;27;) funcref) + (elem (;28;) funcref) + (elem (;29;) funcref) + (elem (;30;) funcref) + (elem (;31;) funcref) + (elem (;32;) funcref) + (elem (;33;) funcref) + (elem (;34;) funcref) + (elem (;35;) funcref) + (elem (;36;) funcref) + (elem (;37;) funcref) + (elem (;38;) funcref) + (elem (;39;) funcref) + (elem (;40;) funcref) + (elem (;41;) funcref) + (elem (;42;) funcref) + (elem (;43;) funcref) + (elem (;44;) funcref) + (elem (;45;) funcref) + (elem (;46;) funcref) + (elem (;47;) funcref) + (elem (;48;) funcref) + (elem (;49;) funcref) + (elem (;50;) funcref) + (elem (;51;) funcref) + (elem (;52;) funcref) + (elem (;53;) funcref) + (elem (;54;) funcref) + (elem (;55;) funcref) + (elem (;56;) funcref) + (elem (;57;) funcref) + (elem (;58;) funcref) + (elem (;59;) funcref) + (elem (;60;) funcref) + (elem (;61;) funcref) + (elem (;62;) funcref) + (elem (;63;) funcref) + (elem (;64;) funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/97.print b/tests/snapshots/testsuite/bulk.wast/97.print new file mode 100644 index 0000000000..5741870806 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/97.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + elem.drop 0 + ) + (elem (;0;) funcref (ref.func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/bulk.wast/98.print b/tests/snapshots/testsuite/bulk.wast/98.print new file mode 100644 index 0000000000..815258c585 --- /dev/null +++ b/tests/snapshots/testsuite/bulk.wast/98.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32 i32))) + (type (;2;) (func (param i32) (result i32))) + (func $zero (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $one (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $two (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 1) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + table.copy + ) + (func (;4;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table (;0;) 10 funcref) + (export "copy" (func 3)) + (export "call" (func 4)) + (elem (;0;) (i32.const 0) func $zero $one $two) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/call.wast/0.print b/tests/snapshots/testsuite/call.wast/0.print new file mode 100644 index 0000000000..7f3b4701c1 --- /dev/null +++ b/tests/snapshots/testsuite/call.wast/0.print @@ -0,0 +1,608 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (result i64))) + (type (;3;) (func (result f32))) + (type (;4;) (func (result f64))) + (type (;5;) (func (result i32 i64))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (param i64) (result i64))) + (type (;8;) (func (param f32) (result f32))) + (type (;9;) (func (param f64) (result f64))) + (type (;10;) (func (param i32 f64) (result i32 f64))) + (type (;11;) (func (param i32 i32) (result i32 i32))) + (type (;12;) (func (param f32 f64) (result f64 f32))) + (type (;13;) (func (param f64 i32) (result i32 f64))) + (type (;14;) (func (param f32 i32) (result i32))) + (type (;15;) (func (param i32 i64) (result i64))) + (type (;16;) (func (param f64 f32) (result f32))) + (type (;17;) (func (param i64 f64) (result f64))) + (type (;18;) (func (result i32 f64))) + (type (;19;) (func (result i32 i32))) + (type (;20;) (func (result f64 f32))) + (type (;21;) (func (param i64 i64) (result i64))) + (type (;22;) (func (param i64) (result i32))) + (type (;23;) (func)) + (type (;24;) (func (param f32 i32 i32 f64 f32 f32 f32 f64 f32 i32 i32 f32 f64 i64 i64 i32 i64 i64 f32 i64 i64 i64 i32 f32 f32 f32 f64 f32 i32 i64 f32 f64 f64 f32 i32 f32 f32 f64 i64 f64 i32 i64 f32 f64 i32 i32 i32 i64 f64 i32 i64 i64 f64 f64 f64 f64 f64 f64 i32 f32 f64 f64 i32 i64 f32 f32 f32 i32 f64 f64 f64 f64 f64 f32 i64 i64 i32 i32 i32 f32 f64 i32 i64 f32 f32 f32 i32 i32 f32 f64 i64 f32 f64 f32 f32 f32 i32 f32 i64 i32) (result i32))) + (func $const-i32 (;0;) (type 1) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type 2) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type 3) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type 4) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $const-i32-i64 (;4;) (type 5) (result i32 i64) + i32.const 306 + i64.const 356 + ) + (func $id-i32 (;5;) (type 6) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;6;) (type 7) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;7;) (type 8) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;8;) (type 9) (param f64) (result f64) + local.get 0 + ) + (func $id-i32-f64 (;9;) (type 10) (param i32 f64) (result i32 f64) + local.get 0 + local.get 1 + ) + (func $swap-i32-i32 (;10;) (type 11) (param i32 i32) (result i32 i32) + local.get 1 + local.get 0 + ) + (func $swap-f32-f64 (;11;) (type 12) (param f32 f64) (result f64 f32) + local.get 1 + local.get 0 + ) + (func $swap-f64-i32 (;12;) (type 13) (param f64 i32) (result i32 f64) + local.get 1 + local.get 0 + ) + (func $f32-i32 (;13;) (type 14) (param f32 i32) (result i32) + local.get 1 + ) + (func $i32-i64 (;14;) (type 15) (param i32 i64) (result i64) + local.get 1 + ) + (func $f64-f32 (;15;) (type 16) (param f64 f32) (result f32) + local.get 1 + ) + (func $i64-f64 (;16;) (type 17) (param i64 f64) (result f64) + local.get 1 + ) + (func (;17;) (type 1) (result i32) + call $const-i32 + ) + (func (;18;) (type 2) (result i64) + call $const-i64 + ) + (func (;19;) (type 3) (result f32) + call $const-f32 + ) + (func (;20;) (type 4) (result f64) + call $const-f64 + ) + (func (;21;) (type 5) (result i32 i64) + call $const-i32-i64 + ) + (func (;22;) (type 1) (result i32) + i32.const 32 + call $id-i32 + ) + (func (;23;) (type 2) (result i64) + i64.const 64 + call $id-i64 + ) + (func (;24;) (type 3) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + call $id-f32 + ) + (func (;25;) (type 4) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + call $id-f64 + ) + (func (;26;) (type 1) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + call $f32-i32 + ) + (func (;27;) (type 2) (result i64) + i32.const 32 + i64.const 64 + call $i32-i64 + ) + (func (;28;) (type 3) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + call $f64-f32 + ) + (func (;29;) (type 4) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + call $i64-f64 + ) + (func (;30;) (type 18) (result i32 f64) + i32.const 32 + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + call $id-i32-f64 + ) + (func (;31;) (type 19) (result i32 i32) + i32.const 1 + i32.const 2 + call $swap-i32-i32 + ) + (func (;32;) (type 20) (result f64 f32) + f32.const 0x1p+0 (;=1;) + f64.const 0x1p+1 (;=2;) + call $swap-f32-f64 + ) + (func (;33;) (type 18) (result i32 f64) + f64.const 0x1p+0 (;=1;) + i32.const 2 + call $swap-f64-i32 + ) + (func (;34;) (type 1) (result i32) + i32.const 3 + i32.const 4 + call $swap-i32-i32 + i32.add + ) + (func (;35;) (type 1) (result i32) + i32.const 3 + i32.const 4 + call $swap-i32-i32 + i32.const 5 + i32.add + i32.mul + ) + (func (;36;) (type 19) (result i32 i32) + i32.const 3 + i32.const 4 + call $swap-i32-i32 + call $swap-i32-i32 + ) + (func $fac (;37;) (type 7) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + local.get 0 + i64.const 1 + i64.sub + call $fac + i64.mul + end + ) + (func $fac-acc (;38;) (type 21) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + call $fac-acc + end + ) + (func $fib (;39;) (type 7) (param i64) (result i64) + local.get 0 + i64.const 1 + i64.le_u + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + i64.const 2 + i64.sub + call $fib + local.get 0 + i64.const 1 + i64.sub + call $fib + i64.add + end + ) + (func $even (;40;) (type 22) (param i64) (result i32) + local.get 0 + i64.eqz + if (result i32) ;; label = @1 + i32.const 44 + else + local.get 0 + i64.const 1 + i64.sub + call $odd + end + ) + (func $odd (;41;) (type 22) (param i64) (result i32) + local.get 0 + i64.eqz + if (result i32) ;; label = @1 + i32.const 99 + else + local.get 0 + i64.const 1 + i64.sub + call $even + end + ) + (func $runaway (;42;) (type 23) + call $runaway + ) + (func $mutual-runaway1 (;43;) (type 23) + call $mutual-runaway2 + ) + (func $mutual-runaway2 (;44;) (type 23) + call $mutual-runaway1 + ) + (func (;45;) (type 1) (result i32) + call $const-i32 + i32.const 2 + i32.const 3 + select + ) + (func (;46;) (type 1) (result i32) + i32.const 2 + call $const-i32 + i32.const 3 + select + ) + (func (;47;) (type 1) (result i32) + i32.const 2 + i32.const 3 + call $const-i32 + select + ) + (func (;48;) (type 1) (result i32) + call $const-i32 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 2 + end + ) + (func (;49;) (type 1) (result i32) + block (result i32) ;; label = @1 + call $const-i32 + i32.const 2 + br_if 0 (;@1;) + end + ) + (func (;50;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + call $const-i32 + br_if 0 (;@1;) + end + ) + (func (;51;) (type 1) (result i32) + block (result i32) ;; label = @1 + call $const-i32 + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;52;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + call $const-i32 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;53;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;54;) (type 1) (result i32) + block (result i32) ;; label = @1 + call $const-i32 + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;55;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + call $const-i32 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;56;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + call $const-i32 + call_indirect (type $check) + end + ) + (func (;57;) (type 23) + call $const-i32 + i32.const 1 + i32.store + ) + (func (;58;) (type 23) + i32.const 10 + call $const-i32 + i32.store + ) + (func (;59;) (type 1) (result i32) + call $const-i32 + memory.grow + ) + (func (;60;) (type 1) (result i32) + call $const-i32 + return + ) + (func (;61;) (type 23) + call $const-i32 + drop + ) + (func (;62;) (type 1) (result i32) + block (result i32) ;; label = @1 + call $const-i32 + br 0 (;@1;) + end + ) + (func (;63;) (type 1) (result i32) + (local i32) + call $const-i32 + local.set 0 + local.get 0 + ) + (func (;64;) (type 1) (result i32) + (local i32) + call $const-i32 + local.tee 0 + ) + (func (;65;) (type 1) (result i32) + call $const-i32 + global.set $a + global.get $a + ) + (func (;66;) (type 1) (result i32) + call $const-i32 + i32.load + ) + (func $dummy (;67;) (type 6) (param i32) (result i32) + local.get 0 + ) + (func $du (;68;) (type 8) (param f32) (result f32) + local.get 0 + ) + (func (;69;) (type 3) (result f32) + block (result f32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + call $du + f32.sqrt + end + ) + (func (;70;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + call $dummy + i32.const 10 + i32.add + end + ) + (func (;71;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 1 + call $dummy + i32.sub + end + ) + (func (;72;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + call $dummy + i32.eqz + end + ) + (func (;73;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + call $dummy + i32.const 10 + i32.le_u + end + ) + (func (;74;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 1 + call $dummy + i32.ne + end + ) + (func (;75;) (type 2) (result i64) + block (result i64) ;; label = @1 + i32.const 1 + call $dummy + i64.extend_i32_s + end + ) + (func $return-from-long-argument-list-helper (;76;) (type 24) (param f32 i32 i32 f64 f32 f32 f32 f64 f32 i32 i32 f32 f64 i64 i64 i32 i64 i64 f32 i64 i64 i64 i32 f32 f32 f32 f64 f32 i32 i64 f32 f64 f64 f32 i32 f32 f32 f64 i64 f64 i32 i64 f32 f64 i32 i32 i32 i64 f64 i32 i64 i64 f64 f64 f64 f64 f64 f64 i32 f32 f64 f64 i32 i64 f32 f32 f32 i32 f64 f64 f64 f64 f64 f32 i64 i64 i32 i32 i32 f32 f64 i32 i64 f32 f32 f32 i32 i32 f32 f64 i64 f32 f64 f32 f32 f32 i32 f32 i64 i32) (result i32) + local.get 99 + ) + (func (;77;) (type 6) (param i32) (result i32) + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 0 + f64.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 0 + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + i64.const 0 + i64.const 0 + i32.const 0 + i64.const 0 + i64.const 0 + f32.const 0x0p+0 (;=0;) + i64.const 0 + i64.const 0 + i64.const 0 + i32.const 0 + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + i32.const 0 + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 0 + i32.const 0 + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i64.const 0 + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + i32.const 0 + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + i32.const 0 + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + i64.const 0 + i64.const 0 + i32.const 0 + i32.const 0 + i32.const 0 + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 0 + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + f64.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + f32.const 0x0p+0 (;=0;) + i32.const 0 + f32.const 0x0p+0 (;=0;) + i64.const 0 + local.get 0 + call $return-from-long-argument-list-helper + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "type-i32" (func 17)) + (export "type-i64" (func 18)) + (export "type-f32" (func 19)) + (export "type-f64" (func 20)) + (export "type-i32-i64" (func 21)) + (export "type-first-i32" (func 22)) + (export "type-first-i64" (func 23)) + (export "type-first-f32" (func 24)) + (export "type-first-f64" (func 25)) + (export "type-second-i32" (func 26)) + (export "type-second-i64" (func 27)) + (export "type-second-f32" (func 28)) + (export "type-second-f64" (func 29)) + (export "type-all-i32-f64" (func 30)) + (export "type-all-i32-i32" (func 31)) + (export "type-all-f32-f64" (func 32)) + (export "type-all-f64-i32" (func 33)) + (export "as-binary-all-operands" (func 34)) + (export "as-mixed-operands" (func 35)) + (export "as-call-all-operands" (func 36)) + (export "fac" (func $fac)) + (export "fac-acc" (func $fac-acc)) + (export "fib" (func $fib)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (export "runaway" (func $runaway)) + (export "mutual-runaway" (func $mutual-runaway1)) + (export "as-select-first" (func 45)) + (export "as-select-mid" (func 46)) + (export "as-select-last" (func 47)) + (export "as-if-condition" (func 48)) + (export "as-br_if-first" (func 49)) + (export "as-br_if-last" (func 50)) + (export "as-br_table-first" (func 51)) + (export "as-br_table-last" (func 52)) + (export "as-call_indirect-first" (func 54)) + (export "as-call_indirect-mid" (func 55)) + (export "as-call_indirect-last" (func 56)) + (export "as-store-first" (func 57)) + (export "as-store-last" (func 58)) + (export "as-memory.grow-value" (func 59)) + (export "as-return-value" (func 60)) + (export "as-drop-operand" (func 61)) + (export "as-br-value" (func 62)) + (export "as-local.set-value" (func 63)) + (export "as-local.tee-value" (func 64)) + (export "as-global.set-value" (func 65)) + (export "as-load-operand" (func 66)) + (export "as-unary-operand" (func 69)) + (export "as-binary-left" (func 70)) + (export "as-binary-right" (func 71)) + (export "as-test-operand" (func 72)) + (export "as-compare-left" (func 73)) + (export "as-compare-right" (func 74)) + (export "as-convert-operand" (func 75)) + (export "return-from-long-argument-list" (func 77)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/call_indirect.wast/0.print b/tests/snapshots/testsuite/call_indirect.wast/0.print new file mode 100644 index 0000000000..057a203f9d --- /dev/null +++ b/tests/snapshots/testsuite/call_indirect.wast/0.print @@ -0,0 +1,671 @@ +(module + (type $proc (;0;) (func)) + (type $out-i32 (;1;) (func (result i32))) + (type $out-i64 (;2;) (func (result i64))) + (type $out-f32 (;3;) (func (result f32))) + (type $out-f64 (;4;) (func (result f64))) + (type $out-f64-i32 (;5;) (func (result f64 i32))) + (type $over-i32 (;6;) (func (param i32) (result i32))) + (type $over-i64 (;7;) (func (param i64) (result i64))) + (type $over-f32 (;8;) (func (param f32) (result f32))) + (type $over-f64 (;9;) (func (param f64) (result f64))) + (type $over-i32-f64 (;10;) (func (param i32 f64) (result i32 f64))) + (type $swap-i32-i64 (;11;) (func (param i32 i64) (result i64 i32))) + (type $f32-i32 (;12;) (func (param f32 i32) (result i32))) + (type $i32-i64 (;13;) (func (param i32 i64) (result i64))) + (type $f64-f32 (;14;) (func (param f64 f32) (result f32))) + (type $i64-f64 (;15;) (func (param i64 f64) (result f64))) + (type $over-i32-duplicate (;16;) (func (param i32) (result i32))) + (type $over-i64-duplicate (;17;) (func (param i64) (result i64))) + (type $over-f32-duplicate (;18;) (func (param f32) (result f32))) + (type $over-f64-duplicate (;19;) (func (param f64) (result f64))) + (type (;20;) (func (param i64))) + (type (;21;) (func (param i64 f64 i32 i64))) + (type (;22;) (func (param i64) (result i32))) + (type (;23;) (func (param i64 f64 i32 i64) (result i32))) + (type (;24;) (func (result i32 f64))) + (type (;25;) (func (result i64 i32))) + (type (;26;) (func (param i32) (result i64))) + (type (;27;) (func (param i32) (result f32))) + (type (;28;) (func (param i32) (result f64))) + (func $const-i32 (;0;) (type $out-i32) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type $out-i64) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type $out-f32) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type $out-f64) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $const-f64-i32 (;4;) (type $out-f64-i32) (result f64 i32) + f64.const 0x1.ec8p+11 (;=3940;) + i32.const 32 + ) + (func $id-i32 (;5;) (type $over-i32) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;6;) (type $over-i64) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;7;) (type $over-f32) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;8;) (type $over-f64) (param f64) (result f64) + local.get 0 + ) + (func $id-i32-f64 (;9;) (type $over-i32-f64) (param i32 f64) (result i32 f64) + local.get 0 + local.get 1 + ) + (func $swap-i32-i64 (;10;) (type $swap-i32-i64) (param i32 i64) (result i64 i32) + local.get 1 + local.get 0 + ) + (func $i32-i64 (;11;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + ) + (func $i64-f64 (;12;) (type $i64-f64) (param i64 f64) (result f64) + local.get 1 + ) + (func $f32-i32 (;13;) (type $f32-i32) (param f32 i32) (result i32) + local.get 1 + ) + (func $f64-f32 (;14;) (type $f64-f32) (param f64 f32) (result f32) + local.get 1 + ) + (func $over-i32-duplicate (;15;) (type $over-i32-duplicate) (param i32) (result i32) + local.get 0 + ) + (func $over-i64-duplicate (;16;) (type $over-i64-duplicate) (param i64) (result i64) + local.get 0 + ) + (func $over-f32-duplicate (;17;) (type $over-f32-duplicate) (param f32) (result f32) + local.get 0 + ) + (func $over-f64-duplicate (;18;) (type $over-f64-duplicate) (param f64) (result f64) + local.get 0 + ) + (func (;19;) (type $proc) + i32.const 0 + call_indirect (type $proc) + i64.const 0 + i32.const 0 + call_indirect (type 20) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i32.const 0 + call_indirect (type 21) + i32.const 0 + call_indirect (type $proc) + i32.const 0 + call_indirect (type $out-i32) + i32.eqz + drop + i32.const 0 + call_indirect (type $out-i32) + i32.eqz + drop + i64.const 0 + i32.const 0 + call_indirect (type 22) + i32.eqz + drop + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i32.const 0 + call_indirect (type 23) + i32.eqz + drop + i64.const 0 + i32.const 0 + call_indirect (type $over-i64) + i64.eqz + drop + ) + (func (;20;) (type $out-i32) (result i32) + i32.const 0 + call_indirect (type $out-i32) + ) + (func (;21;) (type $out-i64) (result i64) + i32.const 1 + call_indirect (type $out-i64) + ) + (func (;22;) (type $out-f32) (result f32) + i32.const 2 + call_indirect (type $out-f32) + ) + (func (;23;) (type $out-f64) (result f64) + i32.const 3 + call_indirect (type $out-f64) + ) + (func (;24;) (type $out-f64-i32) (result f64 i32) + i32.const 29 + call_indirect (type $out-f64-i32) + ) + (func (;25;) (type $out-i64) (result i64) + i64.const 100 + i32.const 5 + call_indirect (type $over-i64) + ) + (func (;26;) (type $out-i32) (result i32) + i32.const 32 + i32.const 4 + call_indirect (type $over-i32) + ) + (func (;27;) (type $out-i64) (result i64) + i64.const 64 + i32.const 5 + call_indirect (type $over-i64) + ) + (func (;28;) (type $out-f32) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + i32.const 6 + call_indirect (type $over-f32) + ) + (func (;29;) (type $out-f64) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + i32.const 7 + call_indirect (type $over-f64) + ) + (func (;30;) (type $out-i32) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + i32.const 8 + call_indirect (type $f32-i32) + ) + (func (;31;) (type $out-i64) (result i64) + i32.const 32 + i64.const 64 + i32.const 9 + call_indirect (type $i32-i64) + ) + (func (;32;) (type $out-f32) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + i32.const 10 + call_indirect (type $f64-f32) + ) + (func (;33;) (type $out-f64) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + i32.const 11 + call_indirect (type $i64-f64) + ) + (func (;34;) (type $out-f64-i32) (result f64 i32) + i32.const 29 + call_indirect (type $out-f64-i32) + ) + (func (;35;) (type 24) (result i32 f64) + i32.const 1 + f64.const 0x1p+1 (;=2;) + i32.const 30 + call_indirect (type $over-i32-f64) + ) + (func (;36;) (type 25) (result i64 i32) + i32.const 1 + i64.const 2 + i32.const 31 + call_indirect (type $swap-i32-i64) + ) + (func (;37;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + local.get 0 + call_indirect (type $over-i64) + ) + (func (;38;) (type 26) (param i32) (result i64) + i64.const 9 + local.get 0 + call_indirect (type $over-i64-duplicate) + ) + (func (;39;) (type $over-i32) (param i32) (result i32) + i32.const 9 + local.get 0 + call_indirect (type $over-i32-duplicate) + ) + (func (;40;) (type 27) (param i32) (result f32) + f32.const 0x1.2p+3 (;=9;) + local.get 0 + call_indirect (type $over-f32-duplicate) + ) + (func (;41;) (type 28) (param i32) (result f64) + f64.const 0x1.2p+3 (;=9;) + local.get 0 + call_indirect (type $over-f64-duplicate) + ) + (func $fac-i64 (;42;) (type $over-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + local.get 0 + i64.const 1 + i64.sub + i32.const 12 + call_indirect (type $over-i64) + i64.mul + end + ) + (func $fib-i64 (;43;) (type $over-i64) (param i64) (result i64) + local.get 0 + i64.const 1 + i64.le_u + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + i64.const 2 + i64.sub + i32.const 13 + call_indirect (type $over-i64) + local.get 0 + i64.const 1 + i64.sub + i32.const 13 + call_indirect (type $over-i64) + i64.add + end + ) + (func $fac-i32 (;44;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 1 + else + local.get 0 + local.get 0 + i32.const 1 + i32.sub + i32.const 23 + call_indirect (type $over-i32) + i32.mul + end + ) + (func $fac-f32 (;45;) (type $over-f32) (param f32) (result f32) + local.get 0 + f32.const 0x0p+0 (;=0;) + f32.eq + if (result f32) ;; label = @1 + f32.const 0x1p+0 (;=1;) + else + local.get 0 + local.get 0 + f32.const 0x1p+0 (;=1;) + f32.sub + i32.const 24 + call_indirect (type $over-f32) + f32.mul + end + ) + (func $fac-f64 (;46;) (type $over-f64) (param f64) (result f64) + local.get 0 + f64.const 0x0p+0 (;=0;) + f64.eq + if (result f64) ;; label = @1 + f64.const 0x1p+0 (;=1;) + else + local.get 0 + local.get 0 + f64.const 0x1p+0 (;=1;) + f64.sub + i32.const 25 + call_indirect (type $over-f64) + f64.mul + end + ) + (func $fib-i32 (;47;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.const 1 + i32.le_u + if (result i32) ;; label = @1 + i32.const 1 + else + local.get 0 + i32.const 2 + i32.sub + i32.const 26 + call_indirect (type $over-i32) + local.get 0 + i32.const 1 + i32.sub + i32.const 26 + call_indirect (type $over-i32) + i32.add + end + ) + (func $fib-f32 (;48;) (type $over-f32) (param f32) (result f32) + local.get 0 + f32.const 0x1p+0 (;=1;) + f32.le + if (result f32) ;; label = @1 + f32.const 0x1p+0 (;=1;) + else + local.get 0 + f32.const 0x1p+1 (;=2;) + f32.sub + i32.const 27 + call_indirect (type $over-f32) + local.get 0 + f32.const 0x1p+0 (;=1;) + f32.sub + i32.const 27 + call_indirect (type $over-f32) + f32.add + end + ) + (func $fib-f64 (;49;) (type $over-f64) (param f64) (result f64) + local.get 0 + f64.const 0x1p+0 (;=1;) + f64.le + if (result f64) ;; label = @1 + f64.const 0x1p+0 (;=1;) + else + local.get 0 + f64.const 0x1p+1 (;=2;) + f64.sub + i32.const 28 + call_indirect (type $over-f64) + local.get 0 + f64.const 0x1p+0 (;=1;) + f64.sub + i32.const 28 + call_indirect (type $over-f64) + f64.add + end + ) + (func $even (;50;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 44 + else + local.get 0 + i32.const 1 + i32.sub + i32.const 15 + call_indirect (type $over-i32) + end + ) + (func $odd (;51;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 99 + else + local.get 0 + i32.const 1 + i32.sub + i32.const 14 + call_indirect (type $over-i32) + end + ) + (func $runaway (;52;) (type $proc) + i32.const 16 + call_indirect (type $proc) + ) + (func $mutual-runaway1 (;53;) (type $proc) + i32.const 18 + call_indirect (type $proc) + ) + (func $mutual-runaway2 (;54;) (type $proc) + i32.const 17 + call_indirect (type $proc) + ) + (func (;55;) (type $out-i32) (result i32) + i32.const 0 + call_indirect (type $out-i32) + i32.const 2 + i32.const 3 + select + ) + (func (;56;) (type $out-i32) (result i32) + i32.const 2 + i32.const 0 + call_indirect (type $out-i32) + i32.const 3 + select + ) + (func (;57;) (type $out-i32) (result i32) + i32.const 2 + i32.const 3 + i32.const 0 + call_indirect (type $out-i32) + select + ) + (func (;58;) (type $out-i32) (result i32) + i32.const 0 + call_indirect (type $out-i32) + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 2 + end + ) + (func (;59;) (type $out-i64) (result i64) + block (result i64) ;; label = @1 + i32.const 1 + call_indirect (type $out-i64) + i32.const 2 + br_if 0 (;@1;) + end + ) + (func (;60;) (type $out-i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + call_indirect (type $out-i32) + br_if 0 (;@1;) + end + ) + (func (;61;) (type $out-f32) (result f32) + block (result f32) ;; label = @1 + i32.const 2 + call_indirect (type $out-f32) + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;62;) (type $out-i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + call_indirect (type $out-i32) + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;63;) (type $proc) + i32.const 0 + call_indirect (type $out-i32) + i32.const 1 + i32.store + ) + (func (;64;) (type $proc) + i32.const 10 + i32.const 3 + call_indirect (type $out-f64) + f64.store + ) + (func (;65;) (type $out-i32) (result i32) + i32.const 0 + call_indirect (type $out-i32) + memory.grow + ) + (func (;66;) (type $out-i32) (result i32) + i32.const 1 + i32.const 4 + call_indirect (type $over-i32) + return + ) + (func (;67;) (type $proc) + i64.const 1 + i32.const 5 + call_indirect (type $over-i64) + drop + ) + (func (;68;) (type $out-f32) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1p+0 (;=1;) + i32.const 6 + call_indirect (type $over-f32) + br 0 (;@1;) + end + ) + (func (;69;) (type $out-f64) (result f64) + (local f64) + f64.const 0x1p+0 (;=1;) + i32.const 7 + call_indirect (type $over-f64) + local.set 0 + local.get 0 + ) + (func (;70;) (type $out-f64) (result f64) + (local f64) + f64.const 0x1p+0 (;=1;) + i32.const 7 + call_indirect (type $over-f64) + local.tee 0 + ) + (func (;71;) (type $out-f64) (result f64) + f64.const 0x1p+0 (;=1;) + i32.const 7 + call_indirect (type $over-f64) + global.set $a + global.get $a + ) + (func (;72;) (type $out-i32) (result i32) + i32.const 0 + call_indirect (type $out-i32) + i32.load + ) + (func (;73;) (type $out-f32) (result f32) + block (result f32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + i32.const 6 + call_indirect (type $over-f32) + f32.sqrt + end + ) + (func (;74;) (type $out-i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 4 + call_indirect (type $over-i32) + i32.const 10 + i32.add + end + ) + (func (;75;) (type $out-i32) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 1 + i32.const 4 + call_indirect (type $over-i32) + i32.sub + end + ) + (func (;76;) (type $out-i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 4 + call_indirect (type $over-i32) + i32.eqz + end + ) + (func (;77;) (type $out-i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 4 + call_indirect (type $over-i32) + i32.const 10 + i32.le_u + end + ) + (func (;78;) (type $out-i32) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 1 + i32.const 4 + call_indirect (type $over-i32) + i32.ne + end + ) + (func (;79;) (type $out-i64) (result i64) + block (result i64) ;; label = @1 + i32.const 1 + i32.const 4 + call_indirect (type $over-i32) + i64.extend_i32_s + end + ) + (table (;0;) 32 32 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut f64) f64.const 0x1.4p+3 (;=10;)) + (export "type-i32" (func 20)) + (export "type-i64" (func 21)) + (export "type-f32" (func 22)) + (export "type-f64" (func 23)) + (export "type-f64-i32" (func 24)) + (export "type-index" (func 25)) + (export "type-first-i32" (func 26)) + (export "type-first-i64" (func 27)) + (export "type-first-f32" (func 28)) + (export "type-first-f64" (func 29)) + (export "type-second-i32" (func 30)) + (export "type-second-i64" (func 31)) + (export "type-second-f32" (func 32)) + (export "type-second-f64" (func 33)) + (export "type-all-f64-i32" (func 34)) + (export "type-all-i32-f64" (func 35)) + (export "type-all-i32-i64" (func 36)) + (export "dispatch" (func 37)) + (export "dispatch-structural-i64" (func 38)) + (export "dispatch-structural-i32" (func 39)) + (export "dispatch-structural-f32" (func 40)) + (export "dispatch-structural-f64" (func 41)) + (export "fac-i64" (func $fac-i64)) + (export "fib-i64" (func $fib-i64)) + (export "fac-i32" (func $fac-i32)) + (export "fac-f32" (func $fac-f32)) + (export "fac-f64" (func $fac-f64)) + (export "fib-i32" (func $fib-i32)) + (export "fib-f32" (func $fib-f32)) + (export "fib-f64" (func $fib-f64)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (export "runaway" (func $runaway)) + (export "mutual-runaway" (func $mutual-runaway1)) + (export "as-select-first" (func 55)) + (export "as-select-mid" (func 56)) + (export "as-select-last" (func 57)) + (export "as-if-condition" (func 58)) + (export "as-br_if-first" (func 59)) + (export "as-br_if-last" (func 60)) + (export "as-br_table-first" (func 61)) + (export "as-br_table-last" (func 62)) + (export "as-store-first" (func 63)) + (export "as-store-last" (func 64)) + (export "as-memory.grow-value" (func 65)) + (export "as-return-value" (func 66)) + (export "as-drop-operand" (func 67)) + (export "as-br-value" (func 68)) + (export "as-local.set-value" (func 69)) + (export "as-local.tee-value" (func 70)) + (export "as-global.set-value" (func 71)) + (export "as-load-operand" (func 72)) + (export "as-unary-operand" (func 73)) + (export "as-binary-left" (func 74)) + (export "as-binary-right" (func 75)) + (export "as-test-operand" (func 76)) + (export "as-compare-left" (func 77)) + (export "as-compare-right" (func 78)) + (export "as-convert-operand" (func 79)) + (elem (;0;) (i32.const 0) 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 $fac-i64 $fib-i64 $even $odd $runaway $mutual-runaway1 $mutual-runaway2 $over-i32-duplicate $over-i64-duplicate $over-f32-duplicate $over-f64-duplicate $fac-i32 $fac-f32 $fac-f64 $fib-i32 $fib-f32 $fib-f64 $const-f64-i32 $id-i32-f64 $swap-i32-i64) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/call_indirect.wast/123.print b/tests/snapshots/testsuite/call_indirect.wast/123.print new file mode 100644 index 0000000000..8adf05b6f1 --- /dev/null +++ b/tests/snapshots/testsuite/call_indirect.wast/123.print @@ -0,0 +1,59 @@ +(module + (type $ii-i (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32 i32 i32) (result i32))) + (func $f (;0;) (type $ii-i) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add + ) + (func $g (;1;) (type $ii-i) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.sub + ) + (func $h (;2;) (type $ii-i) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.mul + ) + (func $i (;3;) (type $ii-i) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.div_u + ) + (func $j (;4;) (type $ii-i) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.rem_u + ) + (func $z (;5;) (type 1)) + (func (;6;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + call_indirect (type $ii-i) + ) + (func (;7;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + call_indirect $t2 (type $ii-i) + ) + (func (;8;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + call_indirect $t3 (type $ii-i) + ) + (table $t1 (;0;) 2 2 funcref) + (table $t2 (;1;) 3 3 funcref) + (table $t3 (;2;) 4 funcref) + (export "call-1" (func 6)) + (export "call-2" (func 7)) + (export "call-3" (func 8)) + (elem (;0;) (i32.const 0) func $f $g) + (elem (;1;) (table $t2) (i32.const 0) func $h $i $j) + (elem (;2;) (table $t3) (i32.const 0) func $g $h) + (elem (;3;) (table $t3) (i32.const 3) func $z) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/call_indirect.wast/169.print b/tests/snapshots/testsuite/call_indirect.wast/169.print new file mode 100644 index 0000000000..deb8527745 --- /dev/null +++ b/tests/snapshots/testsuite/call_indirect.wast/169.print @@ -0,0 +1,59 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) + unreachable + call_indirect (type 0) + ) + (func (;1;) (type 0) + unreachable + call_indirect (type 0) + nop + ) + (func (;2;) (type 0) + unreachable + call_indirect (type 0) + call_indirect (type 0) + ) + (func (;3;) (type 0) + unreachable + call_indirect (type 0) + call_indirect (type 0) + ) + (func (;4;) (type 0) + unreachable + call_indirect (type 0) + call_indirect (type 0) + call_indirect (type 0) + ) + (func (;5;) (type 0) + unreachable + call_indirect (type 0) + ) + (func (;6;) (type 0) + unreachable + call_indirect (type 0) + ) + (func (;7;) (type 0) + unreachable + call_indirect (type 0) + call_indirect (type 0) + ) + (func (;8;) (type 0) + unreachable + call_indirect (type 0) + call_indirect (type 0) + ) + (func (;9;) (type 1) (result i32) + unreachable + call_indirect (type 0) + select + ) + (func (;10;) (type 1) (result i32) + unreachable + call_indirect (type 0) + select + call_indirect (type 0) + ) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/comments.wast/0.print b/tests/snapshots/testsuite/comments.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/comments.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/comments.wast/1.print b/tests/snapshots/testsuite/comments.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/comments.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/comments.wast/2.print b/tests/snapshots/testsuite/comments.wast/2.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/comments.wast/2.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/comments.wast/3.print b/tests/snapshots/testsuite/comments.wast/3.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/comments.wast/3.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/0.print b/tests/snapshots/testsuite/const.wast/0.print new file mode 100644 index 0000000000..a34fac468a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/0.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 123456789 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/1.print b/tests/snapshots/testsuite/const.wast/1.print new file mode 100644 index 0000000000..c4307d5a5e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/1.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const -1697645601 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/110.print b/tests/snapshots/testsuite/const.wast/110.print new file mode 100644 index 0000000000..19d98380aa --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/110.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const -1 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/111.print b/tests/snapshots/testsuite/const.wast/111.print new file mode 100644 index 0000000000..1ef92aafe9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/111.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const -2147483648 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/114.print b/tests/snapshots/testsuite/const.wast/114.print new file mode 100644 index 0000000000..19d98380aa --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/114.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const -1 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/115.print b/tests/snapshots/testsuite/const.wast/115.print new file mode 100644 index 0000000000..1ef92aafe9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/115.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const -2147483648 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/118.print b/tests/snapshots/testsuite/const.wast/118.print new file mode 100644 index 0000000000..820e78777a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/118.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const -1 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/119.print b/tests/snapshots/testsuite/const.wast/119.print new file mode 100644 index 0000000000..b12f88cfb1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/119.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const -9223372036854775808 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/12.print b/tests/snapshots/testsuite/const.wast/12.print new file mode 100644 index 0000000000..b6a75cb874 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/12.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.d6f346p+26 (;=123456790;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/122.print b/tests/snapshots/testsuite/const.wast/122.print new file mode 100644 index 0000000000..820e78777a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/122.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const -1 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/123.print b/tests/snapshots/testsuite/const.wast/123.print new file mode 100644 index 0000000000..b12f88cfb1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/123.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const -9223372036854775808 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/126.print b/tests/snapshots/testsuite/const.wast/126.print new file mode 100644 index 0000000000..2752333293 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/126.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1p+127 (;=170141180000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/127.print b/tests/snapshots/testsuite/const.wast/127.print new file mode 100644 index 0000000000..f720d2f5cf --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/127.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const -0x1p+127 (;=-170141180000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/128.print b/tests/snapshots/testsuite/const.wast/128.print new file mode 100644 index 0000000000..5118232732 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/128.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/129.print b/tests/snapshots/testsuite/const.wast/129.print new file mode 100644 index 0000000000..ff38b012e2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/129.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const -0x1.fffffep+127 (;=-340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/13.print b/tests/snapshots/testsuite/const.wast/13.print new file mode 100644 index 0000000000..f52902d69d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/13.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fe9af6p+89 (;=1234567900000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/130.print b/tests/snapshots/testsuite/const.wast/130.print new file mode 100644 index 0000000000..5118232732 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/130.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/131.print b/tests/snapshots/testsuite/const.wast/131.print new file mode 100644 index 0000000000..ff38b012e2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/131.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const -0x1.fffffep+127 (;=-340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/132.print b/tests/snapshots/testsuite/const.wast/132.print new file mode 100644 index 0000000000..5118232732 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/132.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/133.print b/tests/snapshots/testsuite/const.wast/133.print new file mode 100644 index 0000000000..ff38b012e2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/133.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const -0x1.fffffep+127 (;=-340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/134.print b/tests/snapshots/testsuite/const.wast/134.print new file mode 100644 index 0000000000..5118232732 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/134.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/135.print b/tests/snapshots/testsuite/const.wast/135.print new file mode 100644 index 0000000000..ff38b012e2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/135.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const -0x1.fffffep+127 (;=-340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/14.print b/tests/snapshots/testsuite/const.wast/14.print new file mode 100644 index 0000000000..f52902d69d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/14.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fe9af6p+89 (;=1234567900000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/140.print b/tests/snapshots/testsuite/const.wast/140.print new file mode 100644 index 0000000000..5a5d01cbe8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/140.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.2ced32p+126 (;=100000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/141.print b/tests/snapshots/testsuite/const.wast/141.print new file mode 100644 index 0000000000..d3aa036267 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/141.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const -0x1.2ced32p+126 (;=-100000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/144.print b/tests/snapshots/testsuite/const.wast/144.print new file mode 100644 index 0000000000..5118232732 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/144.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/145.print b/tests/snapshots/testsuite/const.wast/145.print new file mode 100644 index 0000000000..ff38b012e2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/145.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const -0x1.fffffep+127 (;=-340282350000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/148.print b/tests/snapshots/testsuite/const.wast/148.print new file mode 100644 index 0000000000..785e0a30f4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/148.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1p+1023 (;=89884656743115800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/149.print b/tests/snapshots/testsuite/const.wast/149.print new file mode 100644 index 0000000000..a75c95b3b8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/149.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const -0x1p+1023 (;=-89884656743115800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/15.print b/tests/snapshots/testsuite/const.wast/15.print new file mode 100644 index 0000000000..600a870037 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/15.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.b25ffep-37 (;=0.000000000012345679;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/150.print b/tests/snapshots/testsuite/const.wast/150.print new file mode 100644 index 0000000000..c2ba852141 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/150.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fffffffffffffp+1023 (;=179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/151.print b/tests/snapshots/testsuite/const.wast/151.print new file mode 100644 index 0000000000..43eb71bdaa --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/151.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const -0x1.fffffffffffffp+1023 (;=-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/152.print b/tests/snapshots/testsuite/const.wast/152.print new file mode 100644 index 0000000000..c2ba852141 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/152.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fffffffffffffp+1023 (;=179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/153.print b/tests/snapshots/testsuite/const.wast/153.print new file mode 100644 index 0000000000..43eb71bdaa --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/153.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const -0x1.fffffffffffffp+1023 (;=-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/154.print b/tests/snapshots/testsuite/const.wast/154.print new file mode 100644 index 0000000000..c2ba852141 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/154.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fffffffffffffp+1023 (;=179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/155.print b/tests/snapshots/testsuite/const.wast/155.print new file mode 100644 index 0000000000..43eb71bdaa --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/155.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const -0x1.fffffffffffffp+1023 (;=-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/16.print b/tests/snapshots/testsuite/const.wast/16.print new file mode 100644 index 0000000000..b6a75cb874 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/16.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.d6f346p+26 (;=123456790;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/160.print b/tests/snapshots/testsuite/const.wast/160.print new file mode 100644 index 0000000000..83938d8b81 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/160.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.1ccf385ebc8ap+1023 (;=100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/161.print b/tests/snapshots/testsuite/const.wast/161.print new file mode 100644 index 0000000000..65f596ca20 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/161.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const -0x1.1ccf385ebc8ap+1023 (;=-100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/164.print b/tests/snapshots/testsuite/const.wast/164.print new file mode 100644 index 0000000000..c2ba852141 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/164.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fffffffffffffp+1023 (;=179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/165.print b/tests/snapshots/testsuite/const.wast/165.print new file mode 100644 index 0000000000..43eb71bdaa --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/165.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const -0x1.fffffffffffffp+1023 (;=-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/168.print b/tests/snapshots/testsuite/const.wast/168.print new file mode 100644 index 0000000000..d439d5ba71 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/168.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const nan:0x1 (;=NaN;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/169.print b/tests/snapshots/testsuite/const.wast/169.print new file mode 100644 index 0000000000..5dc269dff7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/169.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const nan:0x1 (;=NaN;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/17.print b/tests/snapshots/testsuite/const.wast/17.print new file mode 100644 index 0000000000..f52902d69d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/17.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fe9af6p+89 (;=1234567900000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/170.print b/tests/snapshots/testsuite/const.wast/170.print new file mode 100644 index 0000000000..8b7d318c18 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/170.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const nan:0x7fffff (;=NaN;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/171.print b/tests/snapshots/testsuite/const.wast/171.print new file mode 100644 index 0000000000..a65fd09344 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/171.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const nan:0xfffffffffffff (;=NaN;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/178.print b/tests/snapshots/testsuite/const.wast/178.print new file mode 100644 index 0000000000..99be6f3910 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/178.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1p-50 (;=0.0000000000000008881784;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/18.print b/tests/snapshots/testsuite/const.wast/18.print new file mode 100644 index 0000000000..f52902d69d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/18.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fe9af6p+89 (;=1234567900000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/180.print b/tests/snapshots/testsuite/const.wast/180.print new file mode 100644 index 0000000000..4aba0de47d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/180.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1p-50 (;=-0.0000000000000008881784;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/182.print b/tests/snapshots/testsuite/const.wast/182.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/182.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/184.print b/tests/snapshots/testsuite/const.wast/184.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/184.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/186.print b/tests/snapshots/testsuite/const.wast/186.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/186.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/188.print b/tests/snapshots/testsuite/const.wast/188.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/188.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/19.print b/tests/snapshots/testsuite/const.wast/19.print new file mode 100644 index 0000000000..600a870037 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/19.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.b25ffep-37 (;=0.000000000012345679;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/190.print b/tests/snapshots/testsuite/const.wast/190.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/190.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/192.print b/tests/snapshots/testsuite/const.wast/192.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/192.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/194.print b/tests/snapshots/testsuite/const.wast/194.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/194.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/196.print b/tests/snapshots/testsuite/const.wast/196.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/196.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/198.print b/tests/snapshots/testsuite/const.wast/198.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/198.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/20.print b/tests/snapshots/testsuite/const.wast/20.print new file mode 100644 index 0000000000..b6a75cb874 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/20.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.d6f346p+26 (;=123456790;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/200.print b/tests/snapshots/testsuite/const.wast/200.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/200.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/202.print b/tests/snapshots/testsuite/const.wast/202.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/202.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/204.print b/tests/snapshots/testsuite/const.wast/204.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/204.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/206.print b/tests/snapshots/testsuite/const.wast/206.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/206.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/208.print b/tests/snapshots/testsuite/const.wast/208.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/208.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/21.print b/tests/snapshots/testsuite/const.wast/21.print new file mode 100644 index 0000000000..f52902d69d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/21.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fe9af6p+89 (;=1234567900000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/210.print b/tests/snapshots/testsuite/const.wast/210.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/210.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/212.print b/tests/snapshots/testsuite/const.wast/212.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/212.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/214.print b/tests/snapshots/testsuite/const.wast/214.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/214.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/216.print b/tests/snapshots/testsuite/const.wast/216.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/216.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/218.print b/tests/snapshots/testsuite/const.wast/218.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/218.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/22.print b/tests/snapshots/testsuite/const.wast/22.print new file mode 100644 index 0000000000..f52902d69d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/22.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.fe9af6p+89 (;=1234567900000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/220.print b/tests/snapshots/testsuite/const.wast/220.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/220.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/222.print b/tests/snapshots/testsuite/const.wast/222.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/222.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/224.print b/tests/snapshots/testsuite/const.wast/224.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/224.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/226.print b/tests/snapshots/testsuite/const.wast/226.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/226.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/228.print b/tests/snapshots/testsuite/const.wast/228.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/228.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/23.print b/tests/snapshots/testsuite/const.wast/23.print new file mode 100644 index 0000000000..600a870037 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/23.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.b25ffep-37 (;=0.000000000012345679;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/230.print b/tests/snapshots/testsuite/const.wast/230.print new file mode 100644 index 0000000000..1c2b752bd7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/230.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000006p-50 (;=0.0000000000000008881787;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/232.print b/tests/snapshots/testsuite/const.wast/232.print new file mode 100644 index 0000000000..809b67b1fc --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/232.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000006p-50 (;=-0.0000000000000008881787;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/234.print b/tests/snapshots/testsuite/const.wast/234.print new file mode 100644 index 0000000000..99be6f3910 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/234.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1p-50 (;=0.0000000000000008881784;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/236.print b/tests/snapshots/testsuite/const.wast/236.print new file mode 100644 index 0000000000..4aba0de47d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/236.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1p-50 (;=-0.0000000000000008881784;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/238.print b/tests/snapshots/testsuite/const.wast/238.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/238.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/24.print b/tests/snapshots/testsuite/const.wast/24.print new file mode 100644 index 0000000000..69fab4caba --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/24.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+56 (;=81985530000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/240.print b/tests/snapshots/testsuite/const.wast/240.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/240.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/242.print b/tests/snapshots/testsuite/const.wast/242.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/242.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/244.print b/tests/snapshots/testsuite/const.wast/244.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/244.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/246.print b/tests/snapshots/testsuite/const.wast/246.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/246.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/248.print b/tests/snapshots/testsuite/const.wast/248.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/248.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/25.print b/tests/snapshots/testsuite/const.wast/25.print new file mode 100644 index 0000000000..28df102496 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/25.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+75 (;=42984030000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/250.print b/tests/snapshots/testsuite/const.wast/250.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/250.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/252.print b/tests/snapshots/testsuite/const.wast/252.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/252.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/254.print b/tests/snapshots/testsuite/const.wast/254.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/254.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/256.print b/tests/snapshots/testsuite/const.wast/256.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/256.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/258.print b/tests/snapshots/testsuite/const.wast/258.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/258.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/26.print b/tests/snapshots/testsuite/const.wast/26.print new file mode 100644 index 0000000000..28df102496 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/26.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+75 (;=42984030000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/260.print b/tests/snapshots/testsuite/const.wast/260.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/260.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/262.print b/tests/snapshots/testsuite/const.wast/262.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/262.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/264.print b/tests/snapshots/testsuite/const.wast/264.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/264.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/266.print b/tests/snapshots/testsuite/const.wast/266.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/266.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/268.print b/tests/snapshots/testsuite/const.wast/268.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/268.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/27.print b/tests/snapshots/testsuite/const.wast/27.print new file mode 100644 index 0000000000..d7e5a27030 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/27.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+37 (;=156374990000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/270.print b/tests/snapshots/testsuite/const.wast/270.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/270.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/272.print b/tests/snapshots/testsuite/const.wast/272.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/272.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/274.print b/tests/snapshots/testsuite/const.wast/274.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/274.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/276.print b/tests/snapshots/testsuite/const.wast/276.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/276.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/278.print b/tests/snapshots/testsuite/const.wast/278.print new file mode 100644 index 0000000000..1c2b752bd7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/278.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000006p-50 (;=0.0000000000000008881787;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/28.print b/tests/snapshots/testsuite/const.wast/28.print new file mode 100644 index 0000000000..69fab4caba --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/28.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+56 (;=81985530000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/280.print b/tests/snapshots/testsuite/const.wast/280.print new file mode 100644 index 0000000000..809b67b1fc --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/280.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000006p-50 (;=-0.0000000000000008881787;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/282.print b/tests/snapshots/testsuite/const.wast/282.print new file mode 100644 index 0000000000..99be6f3910 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/282.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1p-50 (;=0.0000000000000008881784;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/284.print b/tests/snapshots/testsuite/const.wast/284.print new file mode 100644 index 0000000000..4aba0de47d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/284.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1p-50 (;=-0.0000000000000008881784;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/286.print b/tests/snapshots/testsuite/const.wast/286.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/286.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/288.print b/tests/snapshots/testsuite/const.wast/288.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/288.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/29.print b/tests/snapshots/testsuite/const.wast/29.print new file mode 100644 index 0000000000..28df102496 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/29.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+75 (;=42984030000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/290.print b/tests/snapshots/testsuite/const.wast/290.print new file mode 100644 index 0000000000..6f40be789d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/290.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p-50 (;=0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/292.print b/tests/snapshots/testsuite/const.wast/292.print new file mode 100644 index 0000000000..926fc93eb7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/292.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p-50 (;=-0.0000000000000008881785;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/294.print b/tests/snapshots/testsuite/const.wast/294.print new file mode 100644 index 0000000000..763c2dd3d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/294.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p-50 (;=0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/296.print b/tests/snapshots/testsuite/const.wast/296.print new file mode 100644 index 0000000000..82c4970698 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/296.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p-50 (;=-0.0000000000000008881786;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/298.print b/tests/snapshots/testsuite/const.wast/298.print new file mode 100644 index 0000000000..b21e1a964e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/298.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1p+50 (;=1125899900000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/30.print b/tests/snapshots/testsuite/const.wast/30.print new file mode 100644 index 0000000000..28df102496 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/30.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+75 (;=42984030000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/300.print b/tests/snapshots/testsuite/const.wast/300.print new file mode 100644 index 0000000000..edc2f14a08 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/300.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1p+50 (;=-1125899900000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/302.print b/tests/snapshots/testsuite/const.wast/302.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/302.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/304.print b/tests/snapshots/testsuite/const.wast/304.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/304.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/306.print b/tests/snapshots/testsuite/const.wast/306.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/306.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/308.print b/tests/snapshots/testsuite/const.wast/308.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/308.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/31.print b/tests/snapshots/testsuite/const.wast/31.print new file mode 100644 index 0000000000..d7e5a27030 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/31.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+37 (;=156374990000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/310.print b/tests/snapshots/testsuite/const.wast/310.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/310.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/312.print b/tests/snapshots/testsuite/const.wast/312.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/312.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/314.print b/tests/snapshots/testsuite/const.wast/314.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/314.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/316.print b/tests/snapshots/testsuite/const.wast/316.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/316.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/318.print b/tests/snapshots/testsuite/const.wast/318.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/318.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/32.print b/tests/snapshots/testsuite/const.wast/32.print new file mode 100644 index 0000000000..69fab4caba --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/32.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+56 (;=81985530000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/320.print b/tests/snapshots/testsuite/const.wast/320.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/320.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/322.print b/tests/snapshots/testsuite/const.wast/322.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/322.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/324.print b/tests/snapshots/testsuite/const.wast/324.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/324.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/326.print b/tests/snapshots/testsuite/const.wast/326.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/326.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/328.print b/tests/snapshots/testsuite/const.wast/328.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/328.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/33.print b/tests/snapshots/testsuite/const.wast/33.print new file mode 100644 index 0000000000..28df102496 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/33.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+75 (;=42984030000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/330.print b/tests/snapshots/testsuite/const.wast/330.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/330.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/332.print b/tests/snapshots/testsuite/const.wast/332.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/332.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/334.print b/tests/snapshots/testsuite/const.wast/334.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/334.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/336.print b/tests/snapshots/testsuite/const.wast/336.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/336.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/338.print b/tests/snapshots/testsuite/const.wast/338.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/338.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/34.print b/tests/snapshots/testsuite/const.wast/34.print new file mode 100644 index 0000000000..28df102496 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/34.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+75 (;=42984030000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/340.print b/tests/snapshots/testsuite/const.wast/340.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/340.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/342.print b/tests/snapshots/testsuite/const.wast/342.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/342.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/344.print b/tests/snapshots/testsuite/const.wast/344.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/344.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/346.print b/tests/snapshots/testsuite/const.wast/346.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/346.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/348.print b/tests/snapshots/testsuite/const.wast/348.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/348.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/35.print b/tests/snapshots/testsuite/const.wast/35.print new file mode 100644 index 0000000000..d7e5a27030 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/35.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f32.const 0x1.234568p+37 (;=156374990000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/350.print b/tests/snapshots/testsuite/const.wast/350.print new file mode 100644 index 0000000000..8a1956b38a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/350.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000006p+50 (;=1125900300000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/352.print b/tests/snapshots/testsuite/const.wast/352.print new file mode 100644 index 0000000000..c37e0a8c6e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/352.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000006p+50 (;=-1125900300000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/354.print b/tests/snapshots/testsuite/const.wast/354.print new file mode 100644 index 0000000000..b21e1a964e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/354.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1p+50 (;=1125899900000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/356.print b/tests/snapshots/testsuite/const.wast/356.print new file mode 100644 index 0000000000..edc2f14a08 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/356.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1p+50 (;=-1125899900000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/358.print b/tests/snapshots/testsuite/const.wast/358.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/358.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/360.print b/tests/snapshots/testsuite/const.wast/360.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/360.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/362.print b/tests/snapshots/testsuite/const.wast/362.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/362.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/364.print b/tests/snapshots/testsuite/const.wast/364.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/364.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/366.print b/tests/snapshots/testsuite/const.wast/366.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/366.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/368.print b/tests/snapshots/testsuite/const.wast/368.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/368.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/370.print b/tests/snapshots/testsuite/const.wast/370.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/370.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/372.print b/tests/snapshots/testsuite/const.wast/372.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/372.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/374.print b/tests/snapshots/testsuite/const.wast/374.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/374.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/376.print b/tests/snapshots/testsuite/const.wast/376.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/376.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/378.print b/tests/snapshots/testsuite/const.wast/378.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/378.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/380.print b/tests/snapshots/testsuite/const.wast/380.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/380.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/382.print b/tests/snapshots/testsuite/const.wast/382.print new file mode 100644 index 0000000000..b21e1a964e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/382.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1p+50 (;=1125899900000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/384.print b/tests/snapshots/testsuite/const.wast/384.print new file mode 100644 index 0000000000..edc2f14a08 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/384.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1p+50 (;=-1125899900000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/386.print b/tests/snapshots/testsuite/const.wast/386.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/386.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/388.print b/tests/snapshots/testsuite/const.wast/388.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/388.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/390.print b/tests/snapshots/testsuite/const.wast/390.print new file mode 100644 index 0000000000..34730831ac --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/390.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000002p+50 (;=1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/392.print b/tests/snapshots/testsuite/const.wast/392.print new file mode 100644 index 0000000000..88b82650d4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/392.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000002p+50 (;=-1125900000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/394.print b/tests/snapshots/testsuite/const.wast/394.print new file mode 100644 index 0000000000..746ace3590 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/394.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.000004p+50 (;=1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/396.print b/tests/snapshots/testsuite/const.wast/396.print new file mode 100644 index 0000000000..4df29011a8 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/396.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.000004p+50 (;=-1125900200000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/398.print b/tests/snapshots/testsuite/const.wast/398.print new file mode 100644 index 0000000000..1fbc56a78f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/398.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x0p+0 (;=0;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/400.print b/tests/snapshots/testsuite/const.wast/400.print new file mode 100644 index 0000000000..dec360ec90 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/400.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x0p+0 (;=-0;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/402.print b/tests/snapshots/testsuite/const.wast/402.print new file mode 100644 index 0000000000..d759d6cc7a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/402.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-149 (;=0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/404.print b/tests/snapshots/testsuite/const.wast/404.print new file mode 100644 index 0000000000..b62987ae5f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/404.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-149 (;=-0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/406.print b/tests/snapshots/testsuite/const.wast/406.print new file mode 100644 index 0000000000..d759d6cc7a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/406.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-149 (;=0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/408.print b/tests/snapshots/testsuite/const.wast/408.print new file mode 100644 index 0000000000..b62987ae5f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/408.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-149 (;=-0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/410.print b/tests/snapshots/testsuite/const.wast/410.print new file mode 100644 index 0000000000..d759d6cc7a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/410.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-149 (;=0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/412.print b/tests/snapshots/testsuite/const.wast/412.print new file mode 100644 index 0000000000..b62987ae5f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/412.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-149 (;=-0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/414.print b/tests/snapshots/testsuite/const.wast/414.print new file mode 100644 index 0000000000..d759d6cc7a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/414.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-149 (;=0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/416.print b/tests/snapshots/testsuite/const.wast/416.print new file mode 100644 index 0000000000..b62987ae5f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/416.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-149 (;=-0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/418.print b/tests/snapshots/testsuite/const.wast/418.print new file mode 100644 index 0000000000..d759d6cc7a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/418.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-149 (;=0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/420.print b/tests/snapshots/testsuite/const.wast/420.print new file mode 100644 index 0000000000..b62987ae5f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/420.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-149 (;=-0.000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/422.print b/tests/snapshots/testsuite/const.wast/422.print new file mode 100644 index 0000000000..d5134bea23 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/422.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-148 (;=0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/424.print b/tests/snapshots/testsuite/const.wast/424.print new file mode 100644 index 0000000000..989fd623c7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/424.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-148 (;=-0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/426.print b/tests/snapshots/testsuite/const.wast/426.print new file mode 100644 index 0000000000..d5134bea23 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/426.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-148 (;=0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/428.print b/tests/snapshots/testsuite/const.wast/428.print new file mode 100644 index 0000000000..989fd623c7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/428.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-148 (;=-0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/430.print b/tests/snapshots/testsuite/const.wast/430.print new file mode 100644 index 0000000000..d5134bea23 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/430.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-148 (;=0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/432.print b/tests/snapshots/testsuite/const.wast/432.print new file mode 100644 index 0000000000..989fd623c7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/432.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-148 (;=-0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/434.print b/tests/snapshots/testsuite/const.wast/434.print new file mode 100644 index 0000000000..d5134bea23 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/434.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-148 (;=0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/436.print b/tests/snapshots/testsuite/const.wast/436.print new file mode 100644 index 0000000000..989fd623c7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/436.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-148 (;=-0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/438.print b/tests/snapshots/testsuite/const.wast/438.print new file mode 100644 index 0000000000..d5134bea23 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/438.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-148 (;=0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/440.print b/tests/snapshots/testsuite/const.wast/440.print new file mode 100644 index 0000000000..989fd623c7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/440.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-148 (;=-0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/442.print b/tests/snapshots/testsuite/const.wast/442.print new file mode 100644 index 0000000000..d5134bea23 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/442.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-148 (;=0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/444.print b/tests/snapshots/testsuite/const.wast/444.print new file mode 100644 index 0000000000..989fd623c7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/444.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-148 (;=-0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/446.print b/tests/snapshots/testsuite/const.wast/446.print new file mode 100644 index 0000000000..d5134bea23 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/446.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.p-148 (;=0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/448.print b/tests/snapshots/testsuite/const.wast/448.print new file mode 100644 index 0000000000..989fd623c7 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/448.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.p-148 (;=-0.000000000000000000000000000000000000000000003;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/450.print b/tests/snapshots/testsuite/const.wast/450.print new file mode 100644 index 0000000000..6f015c743a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/450.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.8p-148 (;=0.000000000000000000000000000000000000000000004;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/452.print b/tests/snapshots/testsuite/const.wast/452.print new file mode 100644 index 0000000000..3971248f6c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/452.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.8p-148 (;=-0.000000000000000000000000000000000000000000004;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/454.print b/tests/snapshots/testsuite/const.wast/454.print new file mode 100644 index 0000000000..8334ada13a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/454.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/456.print b/tests/snapshots/testsuite/const.wast/456.print new file mode 100644 index 0000000000..019961f369 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/456.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.fffffep+127 (;=-340282350000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/458.print b/tests/snapshots/testsuite/const.wast/458.print new file mode 100644 index 0000000000..8334ada13a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/458.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/460.print b/tests/snapshots/testsuite/const.wast/460.print new file mode 100644 index 0000000000..019961f369 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/460.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.fffffep+127 (;=-340282350000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/462.print b/tests/snapshots/testsuite/const.wast/462.print new file mode 100644 index 0000000000..8334ada13a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/462.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/464.print b/tests/snapshots/testsuite/const.wast/464.print new file mode 100644 index 0000000000..019961f369 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/464.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + f32.const -0x1.fffffep+127 (;=-340282350000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/466.print b/tests/snapshots/testsuite/const.wast/466.print new file mode 100644 index 0000000000..25558a4d1d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/466.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102884;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/468.print b/tests/snapshots/testsuite/const.wast/468.print new file mode 100644 index 0000000000..456f0919c0 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/468.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102884;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/470.print b/tests/snapshots/testsuite/const.wast/470.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/470.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/472.print b/tests/snapshots/testsuite/const.wast/472.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/472.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/474.print b/tests/snapshots/testsuite/const.wast/474.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/474.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/476.print b/tests/snapshots/testsuite/const.wast/476.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/476.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/478.print b/tests/snapshots/testsuite/const.wast/478.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/478.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/480.print b/tests/snapshots/testsuite/const.wast/480.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/480.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/482.print b/tests/snapshots/testsuite/const.wast/482.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/482.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/484.print b/tests/snapshots/testsuite/const.wast/484.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/484.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/486.print b/tests/snapshots/testsuite/const.wast/486.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/486.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/488.print b/tests/snapshots/testsuite/const.wast/488.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/488.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/490.print b/tests/snapshots/testsuite/const.wast/490.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/490.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/492.print b/tests/snapshots/testsuite/const.wast/492.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/492.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/494.print b/tests/snapshots/testsuite/const.wast/494.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/494.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/496.print b/tests/snapshots/testsuite/const.wast/496.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/496.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/498.print b/tests/snapshots/testsuite/const.wast/498.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/498.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/500.print b/tests/snapshots/testsuite/const.wast/500.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/500.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/502.print b/tests/snapshots/testsuite/const.wast/502.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/502.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/504.print b/tests/snapshots/testsuite/const.wast/504.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/504.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/506.print b/tests/snapshots/testsuite/const.wast/506.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/506.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/508.print b/tests/snapshots/testsuite/const.wast/508.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/508.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/510.print b/tests/snapshots/testsuite/const.wast/510.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/510.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/512.print b/tests/snapshots/testsuite/const.wast/512.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/512.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/514.print b/tests/snapshots/testsuite/const.wast/514.print new file mode 100644 index 0000000000..6de7afcf83 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/514.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000003p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028857;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/516.print b/tests/snapshots/testsuite/const.wast/516.print new file mode 100644 index 0000000000..ecbedb246f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/516.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000003p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028857;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/518.print b/tests/snapshots/testsuite/const.wast/518.print new file mode 100644 index 0000000000..25558a4d1d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/518.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102884;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/520.print b/tests/snapshots/testsuite/const.wast/520.print new file mode 100644 index 0000000000..456f0919c0 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/520.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102884;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/522.print b/tests/snapshots/testsuite/const.wast/522.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/522.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/524.print b/tests/snapshots/testsuite/const.wast/524.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/524.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/526.print b/tests/snapshots/testsuite/const.wast/526.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/526.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/528.print b/tests/snapshots/testsuite/const.wast/528.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/528.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/530.print b/tests/snapshots/testsuite/const.wast/530.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/530.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/532.print b/tests/snapshots/testsuite/const.wast/532.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/532.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/534.print b/tests/snapshots/testsuite/const.wast/534.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/534.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/536.print b/tests/snapshots/testsuite/const.wast/536.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/536.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/538.print b/tests/snapshots/testsuite/const.wast/538.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/538.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/540.print b/tests/snapshots/testsuite/const.wast/540.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/540.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/542.print b/tests/snapshots/testsuite/const.wast/542.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/542.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/544.print b/tests/snapshots/testsuite/const.wast/544.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/544.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/546.print b/tests/snapshots/testsuite/const.wast/546.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/546.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/548.print b/tests/snapshots/testsuite/const.wast/548.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/548.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/55.print b/tests/snapshots/testsuite/const.wast/55.print new file mode 100644 index 0000000000..7b8690bf8d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/55.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.d6f3454p+26 (;=123456789;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/550.print b/tests/snapshots/testsuite/const.wast/550.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/550.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/552.print b/tests/snapshots/testsuite/const.wast/552.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/552.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/554.print b/tests/snapshots/testsuite/const.wast/554.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/554.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/556.print b/tests/snapshots/testsuite/const.wast/556.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/556.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/558.print b/tests/snapshots/testsuite/const.wast/558.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/558.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/56.print b/tests/snapshots/testsuite/const.wast/56.print new file mode 100644 index 0000000000..091633b75e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/56.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b5e16fap+89 (;=1234567890000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/560.print b/tests/snapshots/testsuite/const.wast/560.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/560.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/562.print b/tests/snapshots/testsuite/const.wast/562.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/562.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/564.print b/tests/snapshots/testsuite/const.wast/564.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/564.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/566.print b/tests/snapshots/testsuite/const.wast/566.print new file mode 100644 index 0000000000..6de7afcf83 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/566.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000003p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028857;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/568.print b/tests/snapshots/testsuite/const.wast/568.print new file mode 100644 index 0000000000..ecbedb246f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/568.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000003p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028857;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/57.print b/tests/snapshots/testsuite/const.wast/57.print new file mode 100644 index 0000000000..091633b75e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/57.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b5e16fap+89 (;=1234567890000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/570.print b/tests/snapshots/testsuite/const.wast/570.print new file mode 100644 index 0000000000..ad96598516 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/570.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p+999 (;=5357543035931337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/572.print b/tests/snapshots/testsuite/const.wast/572.print new file mode 100644 index 0000000000..29e90b4215 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/572.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p+999 (;=-5357543035931337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/574.print b/tests/snapshots/testsuite/const.wast/574.print new file mode 100644 index 0000000000..d45faab061 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/574.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+999 (;=5357543035931338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/576.print b/tests/snapshots/testsuite/const.wast/576.print new file mode 100644 index 0000000000..714912a936 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/576.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+999 (;=-5357543035931338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/578.print b/tests/snapshots/testsuite/const.wast/578.print new file mode 100644 index 0000000000..d45faab061 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/578.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+999 (;=5357543035931338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/58.print b/tests/snapshots/testsuite/const.wast/58.print new file mode 100644 index 0000000000..c35fbfc7ed --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/58.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.b25ffd62b4311p-37 (;=0.0000000000123456789;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/580.print b/tests/snapshots/testsuite/const.wast/580.print new file mode 100644 index 0000000000..714912a936 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/580.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+999 (;=-5357543035931338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/582.print b/tests/snapshots/testsuite/const.wast/582.print new file mode 100644 index 0000000000..38f2cf1bae --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/582.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+999 (;=5357543035931339000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/584.print b/tests/snapshots/testsuite/const.wast/584.print new file mode 100644 index 0000000000..78f5e077b2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/584.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+999 (;=-5357543035931339000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/586.print b/tests/snapshots/testsuite/const.wast/586.print new file mode 100644 index 0000000000..28e5c59dfc --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/586.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p+600 (;=4149515568880993000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/588.print b/tests/snapshots/testsuite/const.wast/588.print new file mode 100644 index 0000000000..940167686f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/588.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p+600 (;=-4149515568880993000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/59.print b/tests/snapshots/testsuite/const.wast/59.print new file mode 100644 index 0000000000..7b8690bf8d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/59.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.d6f3454p+26 (;=123456789;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/590.print b/tests/snapshots/testsuite/const.wast/590.print new file mode 100644 index 0000000000..a2e5b2bb60 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/590.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+600 (;=4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/592.print b/tests/snapshots/testsuite/const.wast/592.print new file mode 100644 index 0000000000..eb0996a513 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/592.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+600 (;=-4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/594.print b/tests/snapshots/testsuite/const.wast/594.print new file mode 100644 index 0000000000..a2e5b2bb60 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/594.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+600 (;=4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/596.print b/tests/snapshots/testsuite/const.wast/596.print new file mode 100644 index 0000000000..eb0996a513 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/596.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+600 (;=-4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/598.print b/tests/snapshots/testsuite/const.wast/598.print new file mode 100644 index 0000000000..a2e5b2bb60 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/598.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+600 (;=4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/6.print b/tests/snapshots/testsuite/const.wast/6.print new file mode 100644 index 0000000000..83e747ac7f --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/6.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 123456789 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/60.print b/tests/snapshots/testsuite/const.wast/60.print new file mode 100644 index 0000000000..091633b75e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/60.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b5e16fap+89 (;=1234567890000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/600.print b/tests/snapshots/testsuite/const.wast/600.print new file mode 100644 index 0000000000..eb0996a513 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/600.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+600 (;=-4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/602.print b/tests/snapshots/testsuite/const.wast/602.print new file mode 100644 index 0000000000..a2e5b2bb60 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/602.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+600 (;=4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/604.print b/tests/snapshots/testsuite/const.wast/604.print new file mode 100644 index 0000000000..eb0996a513 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/604.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+600 (;=-4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/606.print b/tests/snapshots/testsuite/const.wast/606.print new file mode 100644 index 0000000000..a2e5b2bb60 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/606.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+600 (;=4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/608.print b/tests/snapshots/testsuite/const.wast/608.print new file mode 100644 index 0000000000..eb0996a513 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/608.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+600 (;=-4149515568880994000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/61.print b/tests/snapshots/testsuite/const.wast/61.print new file mode 100644 index 0000000000..091633b75e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/61.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b5e16fap+89 (;=1234567890000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/610.print b/tests/snapshots/testsuite/const.wast/610.print new file mode 100644 index 0000000000..bec38e05a1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/610.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+600 (;=4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/612.print b/tests/snapshots/testsuite/const.wast/612.print new file mode 100644 index 0000000000..97260b847b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/612.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+600 (;=-4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/614.print b/tests/snapshots/testsuite/const.wast/614.print new file mode 100644 index 0000000000..bec38e05a1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/614.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+600 (;=4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/616.print b/tests/snapshots/testsuite/const.wast/616.print new file mode 100644 index 0000000000..97260b847b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/616.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+600 (;=-4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/618.print b/tests/snapshots/testsuite/const.wast/618.print new file mode 100644 index 0000000000..bec38e05a1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/618.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+600 (;=4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/62.print b/tests/snapshots/testsuite/const.wast/62.print new file mode 100644 index 0000000000..c35fbfc7ed --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/62.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.b25ffd62b4311p-37 (;=0.0000000000123456789;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/620.print b/tests/snapshots/testsuite/const.wast/620.print new file mode 100644 index 0000000000..97260b847b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/620.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+600 (;=-4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/622.print b/tests/snapshots/testsuite/const.wast/622.print new file mode 100644 index 0000000000..bec38e05a1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/622.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+600 (;=4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/624.print b/tests/snapshots/testsuite/const.wast/624.print new file mode 100644 index 0000000000..97260b847b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/624.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+600 (;=-4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/626.print b/tests/snapshots/testsuite/const.wast/626.print new file mode 100644 index 0000000000..bec38e05a1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/626.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+600 (;=4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/628.print b/tests/snapshots/testsuite/const.wast/628.print new file mode 100644 index 0000000000..97260b847b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/628.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+600 (;=-4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/63.print b/tests/snapshots/testsuite/const.wast/63.print new file mode 100644 index 0000000000..b7b457a8e3 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/63.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.d6f34540ca458p+26 (;=123456789.01234567;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/630.print b/tests/snapshots/testsuite/const.wast/630.print new file mode 100644 index 0000000000..bec38e05a1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/630.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+600 (;=4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/632.print b/tests/snapshots/testsuite/const.wast/632.print new file mode 100644 index 0000000000..97260b847b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/632.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+600 (;=-4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/634.print b/tests/snapshots/testsuite/const.wast/634.print new file mode 100644 index 0000000000..bec38e05a1 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/634.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+600 (;=4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/636.print b/tests/snapshots/testsuite/const.wast/636.print new file mode 100644 index 0000000000..97260b847b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/636.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+600 (;=-4149515568880995000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/638.print b/tests/snapshots/testsuite/const.wast/638.print new file mode 100644 index 0000000000..eae9d2f671 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/638.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000003p+600 (;=4149515568880996000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/64.print b/tests/snapshots/testsuite/const.wast/64.print new file mode 100644 index 0000000000..ff5ed00c51 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/64.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b6bcbd5p+89 (;=1234567890123456900000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/640.print b/tests/snapshots/testsuite/const.wast/640.print new file mode 100644 index 0000000000..4b83254d59 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/640.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000003p+600 (;=-4149515568880996000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/642.print b/tests/snapshots/testsuite/const.wast/642.print new file mode 100644 index 0000000000..b682d56e51 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/642.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p+97 (;=158456325028528680000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/644.print b/tests/snapshots/testsuite/const.wast/644.print new file mode 100644 index 0000000000..1b03b02a4a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/644.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p+97 (;=-158456325028528680000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/646.print b/tests/snapshots/testsuite/const.wast/646.print new file mode 100644 index 0000000000..de63c4f0f6 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/646.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+97 (;=158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/648.print b/tests/snapshots/testsuite/const.wast/648.print new file mode 100644 index 0000000000..2f86c6233c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/648.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+97 (;=-158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/65.print b/tests/snapshots/testsuite/const.wast/65.print new file mode 100644 index 0000000000..ff5ed00c51 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/65.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b6bcbd5p+89 (;=1234567890123456900000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/650.print b/tests/snapshots/testsuite/const.wast/650.print new file mode 100644 index 0000000000..de63c4f0f6 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/650.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+97 (;=158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/652.print b/tests/snapshots/testsuite/const.wast/652.print new file mode 100644 index 0000000000..2f86c6233c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/652.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+97 (;=-158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/654.print b/tests/snapshots/testsuite/const.wast/654.print new file mode 100644 index 0000000000..de63c4f0f6 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/654.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+97 (;=158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/656.print b/tests/snapshots/testsuite/const.wast/656.print new file mode 100644 index 0000000000..2f86c6233c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/656.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+97 (;=-158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/658.print b/tests/snapshots/testsuite/const.wast/658.print new file mode 100644 index 0000000000..de63c4f0f6 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/658.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+97 (;=158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/66.print b/tests/snapshots/testsuite/const.wast/66.print new file mode 100644 index 0000000000..6840d04e0b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/66.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.b25ffd636ec12p-37 (;=0.000000000012345678901234568;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/660.print b/tests/snapshots/testsuite/const.wast/660.print new file mode 100644 index 0000000000..2f86c6233c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/660.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+97 (;=-158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/662.print b/tests/snapshots/testsuite/const.wast/662.print new file mode 100644 index 0000000000..de63c4f0f6 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/662.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+97 (;=158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/664.print b/tests/snapshots/testsuite/const.wast/664.print new file mode 100644 index 0000000000..2f86c6233c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/664.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+97 (;=-158456325028528700000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/666.print b/tests/snapshots/testsuite/const.wast/666.print new file mode 100644 index 0000000000..b0f86d547a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/666.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+97 (;=158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/668.print b/tests/snapshots/testsuite/const.wast/668.print new file mode 100644 index 0000000000..d278707239 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/668.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+97 (;=-158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/67.print b/tests/snapshots/testsuite/const.wast/67.print new file mode 100644 index 0000000000..7b8690bf8d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/67.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.d6f3454p+26 (;=123456789;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/670.print b/tests/snapshots/testsuite/const.wast/670.print new file mode 100644 index 0000000000..b0f86d547a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/670.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+97 (;=158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/672.print b/tests/snapshots/testsuite/const.wast/672.print new file mode 100644 index 0000000000..d278707239 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/672.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+97 (;=-158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/674.print b/tests/snapshots/testsuite/const.wast/674.print new file mode 100644 index 0000000000..b0f86d547a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/674.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+97 (;=158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/676.print b/tests/snapshots/testsuite/const.wast/676.print new file mode 100644 index 0000000000..d278707239 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/676.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+97 (;=-158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/678.print b/tests/snapshots/testsuite/const.wast/678.print new file mode 100644 index 0000000000..b0f86d547a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/678.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+97 (;=158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/68.print b/tests/snapshots/testsuite/const.wast/68.print new file mode 100644 index 0000000000..7b8690bf8d --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/68.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.d6f3454p+26 (;=123456789;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/680.print b/tests/snapshots/testsuite/const.wast/680.print new file mode 100644 index 0000000000..d278707239 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/680.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+97 (;=-158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/682.print b/tests/snapshots/testsuite/const.wast/682.print new file mode 100644 index 0000000000..b0f86d547a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/682.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+97 (;=158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/684.print b/tests/snapshots/testsuite/const.wast/684.print new file mode 100644 index 0000000000..d278707239 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/684.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+97 (;=-158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/686.print b/tests/snapshots/testsuite/const.wast/686.print new file mode 100644 index 0000000000..b0f86d547a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/686.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+97 (;=158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/688.print b/tests/snapshots/testsuite/const.wast/688.print new file mode 100644 index 0000000000..d278707239 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/688.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+97 (;=-158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/69.print b/tests/snapshots/testsuite/const.wast/69.print new file mode 100644 index 0000000000..b7b457a8e3 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/69.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.d6f34540ca458p+26 (;=123456789.01234567;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/690.print b/tests/snapshots/testsuite/const.wast/690.print new file mode 100644 index 0000000000..b0f86d547a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/690.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+97 (;=158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/692.print b/tests/snapshots/testsuite/const.wast/692.print new file mode 100644 index 0000000000..d278707239 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/692.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+97 (;=-158456325028528750000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/694.print b/tests/snapshots/testsuite/const.wast/694.print new file mode 100644 index 0000000000..9a4b8ec1cc --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/694.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000003p+97 (;=158456325028528780000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/696.print b/tests/snapshots/testsuite/const.wast/696.print new file mode 100644 index 0000000000..69e3fe0e1b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/696.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000003p+97 (;=-158456325028528780000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/698.print b/tests/snapshots/testsuite/const.wast/698.print new file mode 100644 index 0000000000..e57fbddc7c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/698.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p+60 (;=1152921504606847000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/7.print b/tests/snapshots/testsuite/const.wast/7.print new file mode 100644 index 0000000000..e3c2559901 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/7.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 82586009202572527 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/70.print b/tests/snapshots/testsuite/const.wast/70.print new file mode 100644 index 0000000000..091633b75e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/70.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b5e16fap+89 (;=1234567890000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/700.print b/tests/snapshots/testsuite/const.wast/700.print new file mode 100644 index 0000000000..dbc3884f36 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/700.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p+60 (;=-1152921504606847000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/702.print b/tests/snapshots/testsuite/const.wast/702.print new file mode 100644 index 0000000000..04e0ab3671 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/702.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+60 (;=1152921504606847200;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/704.print b/tests/snapshots/testsuite/const.wast/704.print new file mode 100644 index 0000000000..5ba83293f0 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/704.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+60 (;=-1152921504606847200;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/706.print b/tests/snapshots/testsuite/const.wast/706.print new file mode 100644 index 0000000000..04e0ab3671 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/706.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+60 (;=1152921504606847200;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/708.print b/tests/snapshots/testsuite/const.wast/708.print new file mode 100644 index 0000000000..5ba83293f0 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/708.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+60 (;=-1152921504606847200;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/71.print b/tests/snapshots/testsuite/const.wast/71.print new file mode 100644 index 0000000000..091633b75e --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/71.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b5e16fap+89 (;=1234567890000000000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/710.print b/tests/snapshots/testsuite/const.wast/710.print new file mode 100644 index 0000000000..41d21ce76b --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/710.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+60 (;=1152921504606847500;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/712.print b/tests/snapshots/testsuite/const.wast/712.print new file mode 100644 index 0000000000..b8999cb385 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/712.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+60 (;=-1152921504606847500;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/714.print b/tests/snapshots/testsuite/const.wast/714.print new file mode 100644 index 0000000000..3f67a9bf08 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/714.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x0p+0 (;=0;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/716.print b/tests/snapshots/testsuite/const.wast/716.print new file mode 100644 index 0000000000..31cf7c6b9a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/716.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x0p+0 (;=-0;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/718.print b/tests/snapshots/testsuite/const.wast/718.print new file mode 100644 index 0000000000..ec871568d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/718.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1074 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/72.print b/tests/snapshots/testsuite/const.wast/72.print new file mode 100644 index 0000000000..ff5ed00c51 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/72.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.fe9af5b6bcbd5p+89 (;=1234567890123456900000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/720.print b/tests/snapshots/testsuite/const.wast/720.print new file mode 100644 index 0000000000..10eb1bf07c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/720.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1074 (;=-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/722.print b/tests/snapshots/testsuite/const.wast/722.print new file mode 100644 index 0000000000..ec871568d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/722.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1074 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/724.print b/tests/snapshots/testsuite/const.wast/724.print new file mode 100644 index 0000000000..10eb1bf07c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/724.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1074 (;=-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/726.print b/tests/snapshots/testsuite/const.wast/726.print new file mode 100644 index 0000000000..ec871568d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/726.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1074 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/728.print b/tests/snapshots/testsuite/const.wast/728.print new file mode 100644 index 0000000000..10eb1bf07c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/728.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1074 (;=-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/73.print b/tests/snapshots/testsuite/const.wast/73.print new file mode 100644 index 0000000000..f08f8a81c4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/73.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+80 (;=1375488932539311400000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/730.print b/tests/snapshots/testsuite/const.wast/730.print new file mode 100644 index 0000000000..ec871568d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/730.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1074 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/732.print b/tests/snapshots/testsuite/const.wast/732.print new file mode 100644 index 0000000000..10eb1bf07c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/732.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1074 (;=-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/734.print b/tests/snapshots/testsuite/const.wast/734.print new file mode 100644 index 0000000000..ec871568d2 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/734.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1074 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/736.print b/tests/snapshots/testsuite/const.wast/736.print new file mode 100644 index 0000000000..10eb1bf07c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/736.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1074 (;=-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/738.print b/tests/snapshots/testsuite/const.wast/738.print new file mode 100644 index 0000000000..502bb138b9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/738.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1073 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/74.print b/tests/snapshots/testsuite/const.wast/74.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/74.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/740.print b/tests/snapshots/testsuite/const.wast/740.print new file mode 100644 index 0000000000..4c0932dc84 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/740.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1073 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/742.print b/tests/snapshots/testsuite/const.wast/742.print new file mode 100644 index 0000000000..502bb138b9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/742.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1073 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/744.print b/tests/snapshots/testsuite/const.wast/744.print new file mode 100644 index 0000000000..4c0932dc84 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/744.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1073 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/746.print b/tests/snapshots/testsuite/const.wast/746.print new file mode 100644 index 0000000000..502bb138b9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/746.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1073 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/748.print b/tests/snapshots/testsuite/const.wast/748.print new file mode 100644 index 0000000000..4c0932dc84 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/748.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1073 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/75.print b/tests/snapshots/testsuite/const.wast/75.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/75.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/750.print b/tests/snapshots/testsuite/const.wast/750.print new file mode 100644 index 0000000000..502bb138b9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/750.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1073 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/752.print b/tests/snapshots/testsuite/const.wast/752.print new file mode 100644 index 0000000000..4c0932dc84 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/752.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1073 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/754.print b/tests/snapshots/testsuite/const.wast/754.print new file mode 100644 index 0000000000..502bb138b9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/754.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1073 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/756.print b/tests/snapshots/testsuite/const.wast/756.print new file mode 100644 index 0000000000..4c0932dc84 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/756.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1073 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/758.print b/tests/snapshots/testsuite/const.wast/758.print new file mode 100644 index 0000000000..502bb138b9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/758.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1073 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/76.print b/tests/snapshots/testsuite/const.wast/76.print new file mode 100644 index 0000000000..8ba71221dc --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/76.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+61 (;=2623536934927580700;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/760.print b/tests/snapshots/testsuite/const.wast/760.print new file mode 100644 index 0000000000..4c0932dc84 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/760.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1073 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/762.print b/tests/snapshots/testsuite/const.wast/762.print new file mode 100644 index 0000000000..502bb138b9 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/762.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.p-1073 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/764.print b/tests/snapshots/testsuite/const.wast/764.print new file mode 100644 index 0000000000..4c0932dc84 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/764.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.p-1073 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/766.print b/tests/snapshots/testsuite/const.wast/766.print new file mode 100644 index 0000000000..e1578802bd --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/766.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000003p-1022 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225073858507203;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/768.print b/tests/snapshots/testsuite/const.wast/768.print new file mode 100644 index 0000000000..00406fe3fa --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/768.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000003p-1022 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225073858507203;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/77.print b/tests/snapshots/testsuite/const.wast/77.print new file mode 100644 index 0000000000..f08f8a81c4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/77.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+80 (;=1375488932539311400000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/770.print b/tests/snapshots/testsuite/const.wast/770.print new file mode 100644 index 0000000000..0f90b10c7a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/770.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.fffffffffffffp+1023 (;=179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/772.print b/tests/snapshots/testsuite/const.wast/772.print new file mode 100644 index 0000000000..49d58f4b1c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/772.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.fffffffffffffp+1023 (;=-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/774.print b/tests/snapshots/testsuite/const.wast/774.print new file mode 100644 index 0000000000..0f90b10c7a --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/774.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.fffffffffffffp+1023 (;=179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/776.print b/tests/snapshots/testsuite/const.wast/776.print new file mode 100644 index 0000000000..49d58f4b1c --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/776.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.fffffffffffffp+1023 (;=-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/78.print b/tests/snapshots/testsuite/const.wast/78.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/78.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/79.print b/tests/snapshots/testsuite/const.wast/79.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/79.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/80.print b/tests/snapshots/testsuite/const.wast/80.print new file mode 100644 index 0000000000..8ba71221dc --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/80.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+61 (;=2623536934927580700;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/81.print b/tests/snapshots/testsuite/const.wast/81.print new file mode 100644 index 0000000000..f08f8a81c4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/81.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+80 (;=1375488932539311400000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/82.print b/tests/snapshots/testsuite/const.wast/82.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/82.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/83.print b/tests/snapshots/testsuite/const.wast/83.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/83.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/84.print b/tests/snapshots/testsuite/const.wast/84.print new file mode 100644 index 0000000000..8ba71221dc --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/84.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+61 (;=2623536934927580700;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/85.print b/tests/snapshots/testsuite/const.wast/85.print new file mode 100644 index 0000000000..f08f8a81c4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/85.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+80 (;=1375488932539311400000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/86.print b/tests/snapshots/testsuite/const.wast/86.print new file mode 100644 index 0000000000..f08f8a81c4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/86.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+80 (;=1375488932539311400000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/87.print b/tests/snapshots/testsuite/const.wast/87.print new file mode 100644 index 0000000000..f08f8a81c4 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/87.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+80 (;=1375488932539311400000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/88.print b/tests/snapshots/testsuite/const.wast/88.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/88.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/89.print b/tests/snapshots/testsuite/const.wast/89.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/89.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/const.wast/90.print b/tests/snapshots/testsuite/const.wast/90.print new file mode 100644 index 0000000000..77081c7494 --- /dev/null +++ b/tests/snapshots/testsuite/const.wast/90.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + f64.const 0x1.23456789abcdfp+99 (;=721152341463170500000000000000;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/conversions.wast/0.print b/tests/snapshots/testsuite/conversions.wast/0.print new file mode 100644 index 0000000000..528151c3a9 --- /dev/null +++ b/tests/snapshots/testsuite/conversions.wast/0.print @@ -0,0 +1,179 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i64) (result i32))) + (type (;2;) (func (param f32) (result i32))) + (type (;3;) (func (param f64) (result i32))) + (type (;4;) (func (param f32) (result i64))) + (type (;5;) (func (param f64) (result i64))) + (type (;6;) (func (param i32) (result f32))) + (type (;7;) (func (param i64) (result f32))) + (type (;8;) (func (param i32) (result f64))) + (type (;9;) (func (param i64) (result f64))) + (type (;10;) (func (param f32) (result f64))) + (type (;11;) (func (param f64) (result f32))) + (func (;0;) (type 0) (param $x i32) (result i64) + local.get $x + i64.extend_i32_s + ) + (func (;1;) (type 0) (param $x i32) (result i64) + local.get $x + i64.extend_i32_u + ) + (func (;2;) (type 1) (param $x i64) (result i32) + local.get $x + i32.wrap_i64 + ) + (func (;3;) (type 2) (param $x f32) (result i32) + local.get $x + i32.trunc_f32_s + ) + (func (;4;) (type 2) (param $x f32) (result i32) + local.get $x + i32.trunc_f32_u + ) + (func (;5;) (type 3) (param $x f64) (result i32) + local.get $x + i32.trunc_f64_s + ) + (func (;6;) (type 3) (param $x f64) (result i32) + local.get $x + i32.trunc_f64_u + ) + (func (;7;) (type 4) (param $x f32) (result i64) + local.get $x + i64.trunc_f32_s + ) + (func (;8;) (type 4) (param $x f32) (result i64) + local.get $x + i64.trunc_f32_u + ) + (func (;9;) (type 5) (param $x f64) (result i64) + local.get $x + i64.trunc_f64_s + ) + (func (;10;) (type 5) (param $x f64) (result i64) + local.get $x + i64.trunc_f64_u + ) + (func (;11;) (type 2) (param $x f32) (result i32) + local.get $x + i32.trunc_sat_f32_s + ) + (func (;12;) (type 2) (param $x f32) (result i32) + local.get $x + i32.trunc_sat_f32_u + ) + (func (;13;) (type 3) (param $x f64) (result i32) + local.get $x + i32.trunc_sat_f64_s + ) + (func (;14;) (type 3) (param $x f64) (result i32) + local.get $x + i32.trunc_sat_f64_u + ) + (func (;15;) (type 4) (param $x f32) (result i64) + local.get $x + i64.trunc_sat_f32_s + ) + (func (;16;) (type 4) (param $x f32) (result i64) + local.get $x + i64.trunc_sat_f32_u + ) + (func (;17;) (type 5) (param $x f64) (result i64) + local.get $x + i64.trunc_sat_f64_s + ) + (func (;18;) (type 5) (param $x f64) (result i64) + local.get $x + i64.trunc_sat_f64_u + ) + (func (;19;) (type 6) (param $x i32) (result f32) + local.get $x + f32.convert_i32_s + ) + (func (;20;) (type 7) (param $x i64) (result f32) + local.get $x + f32.convert_i64_s + ) + (func (;21;) (type 8) (param $x i32) (result f64) + local.get $x + f64.convert_i32_s + ) + (func (;22;) (type 9) (param $x i64) (result f64) + local.get $x + f64.convert_i64_s + ) + (func (;23;) (type 6) (param $x i32) (result f32) + local.get $x + f32.convert_i32_u + ) + (func (;24;) (type 7) (param $x i64) (result f32) + local.get $x + f32.convert_i64_u + ) + (func (;25;) (type 8) (param $x i32) (result f64) + local.get $x + f64.convert_i32_u + ) + (func (;26;) (type 9) (param $x i64) (result f64) + local.get $x + f64.convert_i64_u + ) + (func (;27;) (type 10) (param $x f32) (result f64) + local.get $x + f64.promote_f32 + ) + (func (;28;) (type 11) (param $x f64) (result f32) + local.get $x + f32.demote_f64 + ) + (func (;29;) (type 6) (param $x i32) (result f32) + local.get $x + f32.reinterpret_i32 + ) + (func (;30;) (type 9) (param $x i64) (result f64) + local.get $x + f64.reinterpret_i64 + ) + (func (;31;) (type 2) (param $x f32) (result i32) + local.get $x + i32.reinterpret_f32 + ) + (func (;32;) (type 5) (param $x f64) (result i64) + local.get $x + i64.reinterpret_f64 + ) + (export "i64.extend_i32_s" (func 0)) + (export "i64.extend_i32_u" (func 1)) + (export "i32.wrap_i64" (func 2)) + (export "i32.trunc_f32_s" (func 3)) + (export "i32.trunc_f32_u" (func 4)) + (export "i32.trunc_f64_s" (func 5)) + (export "i32.trunc_f64_u" (func 6)) + (export "i64.trunc_f32_s" (func 7)) + (export "i64.trunc_f32_u" (func 8)) + (export "i64.trunc_f64_s" (func 9)) + (export "i64.trunc_f64_u" (func 10)) + (export "i32.trunc_sat_f32_s" (func 11)) + (export "i32.trunc_sat_f32_u" (func 12)) + (export "i32.trunc_sat_f64_s" (func 13)) + (export "i32.trunc_sat_f64_u" (func 14)) + (export "i64.trunc_sat_f32_s" (func 15)) + (export "i64.trunc_sat_f32_u" (func 16)) + (export "i64.trunc_sat_f64_s" (func 17)) + (export "i64.trunc_sat_f64_u" (func 18)) + (export "f32.convert_i32_s" (func 19)) + (export "f32.convert_i64_s" (func 20)) + (export "f64.convert_i32_s" (func 21)) + (export "f64.convert_i64_s" (func 22)) + (export "f32.convert_i32_u" (func 23)) + (export "f32.convert_i64_u" (func 24)) + (export "f64.convert_i32_u" (func 25)) + (export "f64.convert_i64_u" (func 26)) + (export "f64.promote_f32" (func 27)) + (export "f32.demote_f64" (func 28)) + (export "f32.reinterpret_i32" (func 29)) + (export "f64.reinterpret_i64" (func 30)) + (export "i32.reinterpret_f32" (func 31)) + (export "i64.reinterpret_f64" (func 32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/custom.wast/0.print b/tests/snapshots/testsuite/custom.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/custom.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/custom.wast/1.print b/tests/snapshots/testsuite/custom.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/custom.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/custom.wast/2.print b/tests/snapshots/testsuite/custom.wast/2.print new file mode 100644 index 0000000000..d94d24a9d0 --- /dev/null +++ b/tests/snapshots/testsuite/custom.wast/2.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32 i32) (result i32))) + (func (;0;) (type 0) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add + ) + (export "addTwo" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/0.print b/tests/snapshots/testsuite/data.wast/0.print new file mode 100644 index 0000000000..76dcc35a32 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/0.print @@ -0,0 +1,27 @@ +(module + (memory $m (;0;) 1) + (data (;0;) (i32.const 0) "") + (data (;1;) (i32.const 1) "abcd") + (data (;2;) (i32.const 0) "") + (data (;3;) (i32.const 0) "abc") + (data (;4;) (i32.const 0) "") + (data (;5;) (i32.const 1) "abcd") + (data (;6;) (i32.const 0) "") + (data (;7;) (i32.const 0) "abc") + (data (;8;) (i32.const 0) "") + (data (;9;) (i32.const 1) "abcd") + (data (;10;) (i32.const 0) "") + (data (;11;) (i32.const 0) "abc") + (data $d1 (;12;) (i32.const 0) "") + (data $d2 (;13;) (i32.const 1) "abcd") + (data $d3 (;14;) (i32.const 0) "") + (data $d4 (;15;) (i32.const 0) "abc") + (data $d5 (;16;) (i32.const 0) "") + (data $d6 (;17;) (i32.const 1) "abcd") + (data $d7 (;18;) (i32.const 0) "") + (data $d8 (;19;) (i32.const 0) "abc") + (data $d9 (;20;) (i32.const 0) "") + (data $d10 (;21;) (i32.const 1) "abcd") + (data $d11 (;22;) (i32.const 0) "") + (data $d12 (;23;) (i32.const 0) "abc") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/1.print b/tests/snapshots/testsuite/data.wast/1.print new file mode 100644 index 0000000000..cc1e75fe22 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/1.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/11.print b/tests/snapshots/testsuite/data.wast/11.print new file mode 100644 index 0000000000..0474fc6565 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/11.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 65535) "b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/12.print b/tests/snapshots/testsuite/data.wast/12.print new file mode 100644 index 0000000000..c7cfbb07bb --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/12.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 65535) "b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/13.print b/tests/snapshots/testsuite/data.wast/13.print new file mode 100644 index 0000000000..0d6dc72126 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/13.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 2) + (data (;0;) (i32.const 131071) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/14.print b/tests/snapshots/testsuite/data.wast/14.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/14.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/15.print b/tests/snapshots/testsuite/data.wast/15.print new file mode 100644 index 0000000000..bb79a2b2e5 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/15.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/16.print b/tests/snapshots/testsuite/data.wast/16.print new file mode 100644 index 0000000000..70d5011af0 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/16.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/17.print b/tests/snapshots/testsuite/data.wast/17.print new file mode 100644 index 0000000000..2f4c3a8d18 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/17.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 65536) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/18.print b/tests/snapshots/testsuite/data.wast/18.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/18.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/19.print b/tests/snapshots/testsuite/data.wast/19.print new file mode 100644 index 0000000000..bb79a2b2e5 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/19.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/2.print b/tests/snapshots/testsuite/data.wast/2.print new file mode 100644 index 0000000000..481aec56e8 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/2.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/20.print b/tests/snapshots/testsuite/data.wast/20.print new file mode 100644 index 0000000000..70d5011af0 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/20.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/21.print b/tests/snapshots/testsuite/data.wast/21.print new file mode 100644 index 0000000000..4e08a2a6d1 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/21.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/22.print b/tests/snapshots/testsuite/data.wast/22.print new file mode 100644 index 0000000000..376eeb676a --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/22.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/23.print b/tests/snapshots/testsuite/data.wast/23.print new file mode 100644 index 0000000000..18183a143f --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/23.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/24.print b/tests/snapshots/testsuite/data.wast/24.print new file mode 100644 index 0000000000..86be16f707 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/24.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/25.print b/tests/snapshots/testsuite/data.wast/25.print new file mode 100644 index 0000000000..6cb38d0981 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/25.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 1) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/26.print b/tests/snapshots/testsuite/data.wast/26.print new file mode 100644 index 0000000000..42df962f09 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/26.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (i32.const 1) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/3.print b/tests/snapshots/testsuite/data.wast/3.print new file mode 100644 index 0000000000..fbef21b722 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/3.print @@ -0,0 +1,8 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 3) "b") + (data (;2;) (i32.const 100) "cde") + (data (;3;) (i32.const 5) "x") + (data (;4;) (i32.const 3) "c") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/4.print b/tests/snapshots/testsuite/data.wast/4.print new file mode 100644 index 0000000000..bb6a67d9e3 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/4.print @@ -0,0 +1,9 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 1) "b") + (data (;2;) (i32.const 2) "cde") + (data (;3;) (i32.const 3) "f") + (data (;4;) (i32.const 2) "g") + (data (;5;) (i32.const 1) "h") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/5.print b/tests/snapshots/testsuite/data.wast/5.print new file mode 100644 index 0000000000..ee7a8e6fe9 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/5.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/6.print b/tests/snapshots/testsuite/data.wast/6.print new file mode 100644 index 0000000000..55a464f093 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/6.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/7.print b/tests/snapshots/testsuite/data.wast/7.print new file mode 100644 index 0000000000..cc48f688bf --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/7.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/data.wast/8.print b/tests/snapshots/testsuite/data.wast/8.print new file mode 100644 index 0000000000..9baa7ce142 --- /dev/null +++ b/tests/snapshots/testsuite/data.wast/8.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/0.print b/tests/snapshots/testsuite/elem.wast/0.print new file mode 100644 index 0000000000..f5b37aa021 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/0.print @@ -0,0 +1,67 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func $g (;1;) (type 0)) + (table $t (;0;) 10 funcref) + (elem (;0;) funcref) + (elem (;1;) funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem (;2;) func) + (elem (;3;) func $f $f $g $g) + (elem $p1 (;4;) funcref) + (elem $p2 (;5;) funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $p3 (;6;) func) + (elem $p4 (;7;) func $f $f $g $g) + (elem (;8;) (i32.const 0) funcref) + (elem (;9;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;10;) (i32.const 0) func) + (elem (;11;) (i32.const 0) func $f $g) + (elem (;12;) (i32.const 0) funcref) + (elem (;13;) (i32.const 0) func $f $g) + (elem (;14;) (i32.const 0) func) + (elem (;15;) (i32.const 0) func $f $f) + (elem (;16;) (i32.const 0) func) + (elem (;17;) (i32.const 0) func $f $f) + (elem (;18;) (i32.const 0) func) + (elem (;19;) (i32.const 0) func $f $f) + (elem (;20;) (i32.const 0) func) + (elem (;21;) (i32.const 0) func $f $f) + (elem (;22;) (i32.const 0) func) + (elem (;23;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;24;) (i32.const 0) func $f $f) + (elem (;25;) (i32.const 0) func $f $f) + (elem (;26;) (i32.const 0) func) + (elem (;27;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;28;) (i32.const 0) func $f $f) + (elem (;29;) (i32.const 0) func $f $f) + (elem (;30;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a1 (;31;) (i32.const 0) funcref) + (elem $a2 (;32;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a3 (;33;) (i32.const 0) func) + (elem $a4 (;34;) (i32.const 0) func $f $g) + (elem $a9 (;35;) (i32.const 0) funcref) + (elem $a10 (;36;) (i32.const 0) func $f $g) + (elem $a11 (;37;) (i32.const 0) func) + (elem $a12 (;38;) (i32.const 0) func $f $f) + (elem $a13 (;39;) (i32.const 0) func) + (elem $a14 (;40;) (i32.const 0) func $f $f) + (elem $a15 (;41;) (i32.const 0) func) + (elem $a16 (;42;) (i32.const 0) func $f $f) + (elem $a17 (;43;) (i32.const 0) func) + (elem $a18 (;44;) (i32.const 0) func $f $f) + (elem $a19 (;45;) (i32.const 0) func) + (elem $a20 (;46;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a21 (;47;) (i32.const 0) func $f $f) + (elem $a22 (;48;) (i32.const 0) func $f $f) + (elem $a23 (;49;) (i32.const 0) func) + (elem $a24 (;50;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a25 (;51;) (i32.const 0) func $f $f) + (elem $a26 (;52;) (i32.const 0) func $f $f) + (elem (;53;) declare funcref) + (elem (;54;) declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem (;55;) declare func) + (elem (;56;) declare func $f $f $g $g) + (elem $d1 (;57;) declare funcref) + (elem $d2 (;58;) declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $d3 (;59;) declare func) + (elem $d4 (;60;) declare func $f $f $g $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/1.print b/tests/snapshots/testsuite/elem.wast/1.print new file mode 100644 index 0000000000..609acc4a8d --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/1.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func $g (;1;) (type 0)) + (table $t (;0;) 3 3 funcref) + (elem (;0;) (i32.const 0) funcref (ref.func $f) (ref.null func) (ref.func $g)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/11.print b/tests/snapshots/testsuite/elem.wast/11.print new file mode 100644 index 0000000000..c20a98422b --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/11.print @@ -0,0 +1,22 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 11 funcref) + (export "call-7" (func 2)) + (export "call-9" (func 3)) + (elem (;0;) (i32.const 6) funcref (ref.null func) (ref.func $const-i32-a)) + (elem (;1;) (i32.const 9) funcref (ref.func $const-i32-b) (ref.null func)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/16.print b/tests/snapshots/testsuite/elem.wast/16.print new file mode 100644 index 0000000000..59834e5a95 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/16.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/17.print b/tests/snapshots/testsuite/elem.wast/17.print new file mode 100644 index 0000000000..6e685d7bc7 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/17.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/18.print b/tests/snapshots/testsuite/elem.wast/18.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/18.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/19.print b/tests/snapshots/testsuite/elem.wast/19.print new file mode 100644 index 0000000000..b890117b79 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/19.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/2.print b/tests/snapshots/testsuite/elem.wast/2.print new file mode 100644 index 0000000000..2da39bb2cc --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/2.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/20.print b/tests/snapshots/testsuite/elem.wast/20.print new file mode 100644 index 0000000000..6dd5628226 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/20.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/21.print b/tests/snapshots/testsuite/elem.wast/21.print new file mode 100644 index 0000000000..9cdf4a4535 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/21.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 20 funcref) + (elem (;0;) (i32.const 20) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/22.print b/tests/snapshots/testsuite/elem.wast/22.print new file mode 100644 index 0000000000..fdbf02b70d --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/22.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/23.print b/tests/snapshots/testsuite/elem.wast/23.print new file mode 100644 index 0000000000..9a7e48cac6 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/23.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 100 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/24.print b/tests/snapshots/testsuite/elem.wast/24.print new file mode 100644 index 0000000000..8e7e87eeea --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/24.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 1) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/25.print b/tests/snapshots/testsuite/elem.wast/25.print new file mode 100644 index 0000000000..8e00e00fe9 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/25.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 30 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 1) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/3.print b/tests/snapshots/testsuite/elem.wast/3.print new file mode 100644 index 0000000000..9fbc90ac8a --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/3.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/38.print b/tests/snapshots/testsuite/elem.wast/38.print new file mode 100644 index 0000000000..f553de715e --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/38.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func (;1;) (type 0) + i32.const 0 + i32.const 0 + i32.const 1 + table.init $e + ) + (table (;0;) 10 funcref) + (export "init" (func 1)) + (elem $e (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/4.print b/tests/snapshots/testsuite/elem.wast/4.print new file mode 100644 index 0000000000..fdf2793aac --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/4.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 0) func $f) + (elem (;1;) (i32.const 3) func $f) + (elem (;2;) (i32.const 7) func $f) + (elem (;3;) (i32.const 5) func $f) + (elem (;4;) (i32.const 3) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/40.print b/tests/snapshots/testsuite/elem.wast/40.print new file mode 100644 index 0000000000..0a8dfffa28 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/40.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func (;1;) (type 0) + i32.const 0 + i32.const 0 + i32.const 1 + table.init $e + ) + (table (;0;) 10 funcref) + (export "init" (func 1)) + (elem $e (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/5.print b/tests/snapshots/testsuite/elem.wast/5.print new file mode 100644 index 0000000000..2c9c937ee7 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/5.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) + (elem (;1;) (i32.const 3) func $f) + (elem (;2;) (i32.const 7) func $f) + (elem (;3;) (i32.const 3) func $f) + (elem (;4;) (i32.const 5) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/6.print b/tests/snapshots/testsuite/elem.wast/6.print new file mode 100644 index 0000000000..ba9ed82c15 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/6.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (import "spectest" "global_i32" (global (;0;) i32)) + (func $f (;0;) (type 0)) + (table (;0;) 1000 funcref) + (elem (;0;) (global.get 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/63.print b/tests/snapshots/testsuite/elem.wast/63.print new file mode 100644 index 0000000000..6ad9b0b3b3 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/63.print @@ -0,0 +1,17 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call-overwritten" (func 2)) + (elem (;0;) (i32.const 9) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/65.print b/tests/snapshots/testsuite/elem.wast/65.print new file mode 100644 index 0000000000..9e872c44e5 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/65.print @@ -0,0 +1,17 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (export "call-overwritten-element" (func 2)) + (elem (;0;) (i32.const 9) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/67.print b/tests/snapshots/testsuite/elem.wast/67.print new file mode 100644 index 0000000000..a7fafae05a --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/67.print @@ -0,0 +1,28 @@ +(module $module1 + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 8 + call_indirect (type $out-i32) + ) + (func (;4;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "shared-table" (table 0)) + (export "call-7" (func 2)) + (export "call-8" (func 3)) + (export "call-9" (func 4)) + (elem (;0;) (i32.const 8) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/7.print b/tests/snapshots/testsuite/elem.wast/7.print new file mode 100644 index 0000000000..83d7347f17 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/7.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (import "spectest" "global_i32" (global $g (;0;) i32)) + (func $f (;0;) (type 0)) + (table (;0;) 1000 funcref) + (elem (;0;) (global.get $g) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/72.print b/tests/snapshots/testsuite/elem.wast/72.print new file mode 100644 index 0000000000..27cf2472b6 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/72.print @@ -0,0 +1,12 @@ +(module $module2 + (type $out-i32 (;0;) (func (result i32))) + (import "module1" "shared-table" (table (;0;) 10 funcref)) + (func $const-i32-c (;0;) (type $out-i32) (result i32) + i32.const 67 + ) + (func $const-i32-d (;1;) (type $out-i32) (result i32) + i32.const 68 + ) + (elem (;0;) (i32.const 7) func $const-i32-c) + (elem (;1;) (i32.const 8) func $const-i32-d) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/76.print b/tests/snapshots/testsuite/elem.wast/76.print new file mode 100644 index 0000000000..e0ef8f741b --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/76.print @@ -0,0 +1,12 @@ +(module $module3 + (type $out-i32 (;0;) (func (result i32))) + (import "module1" "shared-table" (table (;0;) 10 funcref)) + (func $const-i32-e (;0;) (type $out-i32) (result i32) + i32.const 69 + ) + (func $const-i32-f (;1;) (type $out-i32) (result i32) + i32.const 70 + ) + (elem (;0;) (i32.const 8) func $const-i32-e) + (elem (;1;) (i32.const 9) func $const-i32-f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/8.print b/tests/snapshots/testsuite/elem.wast/8.print new file mode 100644 index 0000000000..6bb8d5e65f --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/8.print @@ -0,0 +1,22 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call-7" (func 2)) + (export "call-9" (func 3)) + (elem (;0;) (i32.const 7) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/84.print b/tests/snapshots/testsuite/elem.wast/84.print new file mode 100644 index 0000000000..b1267707e4 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/84.print @@ -0,0 +1,17 @@ +(module $m + (type (;0;) (func (param i32) (result externref))) + (type (;1;) (func (param i32 externref))) + (func (;0;) (type 0) (param $i i32) (result externref) + local.get $i + table.get $t + ) + (func (;1;) (type 1) (param $i i32) (param $x externref) + local.get $i + local.get $x + table.set $t + ) + (table $t (;0;) 2 externref) + (export "table" (table $t)) + (export "get" (func 0)) + (export "set" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/92.print b/tests/snapshots/testsuite/elem.wast/92.print new file mode 100644 index 0000000000..c6a336d99d --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/92.print @@ -0,0 +1,4 @@ +(module + (import "exporter" "table" (table $t (;0;) 2 externref)) + (elem (;0;) (i32.const 0) externref (ref.null extern)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/95.print b/tests/snapshots/testsuite/elem.wast/95.print new file mode 100644 index 0000000000..d2623e77ab --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/95.print @@ -0,0 +1,8 @@ +(module $module4 + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 42 + ) + (global (;0;) funcref ref.func 0) + (export "f" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/elem.wast/97.print b/tests/snapshots/testsuite/elem.wast/97.print new file mode 100644 index 0000000000..bd279c1b29 --- /dev/null +++ b/tests/snapshots/testsuite/elem.wast/97.print @@ -0,0 +1,11 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (import "module4" "f" (global (;0;) funcref)) + (func (;0;) (type $out-i32) (result i32) + i32.const 0 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call_imported_elem" (func 0)) + (elem (;0;) (i32.const 0) funcref (global.get 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/endianness.wast/0.print b/tests/snapshots/testsuite/endianness.wast/0.print new file mode 100644 index 0000000000..3e80821cc3 --- /dev/null +++ b/tests/snapshots/testsuite/endianness.wast/0.print @@ -0,0 +1,229 @@ +(module + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i64))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i32) (result i64))) + (type (;4;) (func (param i64) (result i64))) + (type (;5;) (func (param f32) (result f32))) + (type (;6;) (func (param f64) (result f64))) + (func $i16_store_little (;0;) (type 0) (param $address i32) (param $value i32) + local.get $address + local.get $value + i32.store8 + local.get $address + i32.const 1 + i32.add + local.get $value + i32.const 8 + i32.shr_u + i32.store8 + ) + (func $i32_store_little (;1;) (type 0) (param $address i32) (param $value i32) + local.get $address + local.get $value + call $i16_store_little + local.get $address + i32.const 2 + i32.add + local.get $value + i32.const 16 + i32.shr_u + call $i16_store_little + ) + (func $i64_store_little (;2;) (type 1) (param $address i32) (param $value i64) + local.get $address + local.get $value + i32.wrap_i64 + call $i32_store_little + local.get $address + i32.const 4 + i32.add + local.get $value + i64.const 32 + i64.shr_u + i32.wrap_i64 + call $i32_store_little + ) + (func $i16_load_little (;3;) (type 2) (param $address i32) (result i32) + local.get $address + i32.load8_u + local.get $address + i32.const 1 + i32.add + i32.load8_u + i32.const 8 + i32.shl + i32.or + ) + (func $i32_load_little (;4;) (type 2) (param $address i32) (result i32) + local.get $address + call $i16_load_little + local.get $address + i32.const 2 + i32.add + call $i16_load_little + i32.const 16 + i32.shl + i32.or + ) + (func $i64_load_little (;5;) (type 3) (param $address i32) (result i64) + local.get $address + call $i32_load_little + i64.extend_i32_u + local.get $address + i32.const 4 + i32.add + call $i32_load_little + i64.extend_i32_u + i64.const 32 + i64.shl + i64.or + ) + (func (;6;) (type 2) (param $value i32) (result i32) + i32.const 0 + local.get $value + call $i16_store_little + i32.const 0 + i32.load16_s + ) + (func (;7;) (type 2) (param $value i32) (result i32) + i32.const 0 + local.get $value + call $i16_store_little + i32.const 0 + i32.load16_u + ) + (func (;8;) (type 2) (param $value i32) (result i32) + i32.const 0 + local.get $value + call $i32_store_little + i32.const 0 + i32.load + ) + (func (;9;) (type 4) (param $value i64) (result i64) + i32.const 0 + local.get $value + i32.wrap_i64 + call $i16_store_little + i32.const 0 + i64.load16_s + ) + (func (;10;) (type 4) (param $value i64) (result i64) + i32.const 0 + local.get $value + i32.wrap_i64 + call $i16_store_little + i32.const 0 + i64.load16_u + ) + (func (;11;) (type 4) (param $value i64) (result i64) + i32.const 0 + local.get $value + i32.wrap_i64 + call $i32_store_little + i32.const 0 + i64.load32_s + ) + (func (;12;) (type 4) (param $value i64) (result i64) + i32.const 0 + local.get $value + i32.wrap_i64 + call $i32_store_little + i32.const 0 + i64.load32_u + ) + (func (;13;) (type 4) (param $value i64) (result i64) + i32.const 0 + local.get $value + call $i64_store_little + i32.const 0 + i64.load + ) + (func (;14;) (type 5) (param $value f32) (result f32) + i32.const 0 + local.get $value + i32.reinterpret_f32 + call $i32_store_little + i32.const 0 + f32.load + ) + (func (;15;) (type 6) (param $value f64) (result f64) + i32.const 0 + local.get $value + i64.reinterpret_f64 + call $i64_store_little + i32.const 0 + f64.load + ) + (func (;16;) (type 2) (param $value i32) (result i32) + i32.const 0 + local.get $value + i32.store16 + i32.const 0 + call $i16_load_little + ) + (func (;17;) (type 2) (param $value i32) (result i32) + i32.const 0 + local.get $value + i32.store + i32.const 0 + call $i32_load_little + ) + (func (;18;) (type 4) (param $value i64) (result i64) + i32.const 0 + local.get $value + i64.store16 + i32.const 0 + call $i16_load_little + i64.extend_i32_u + ) + (func (;19;) (type 4) (param $value i64) (result i64) + i32.const 0 + local.get $value + i64.store32 + i32.const 0 + call $i32_load_little + i64.extend_i32_u + ) + (func (;20;) (type 4) (param $value i64) (result i64) + i32.const 0 + local.get $value + i64.store + i32.const 0 + call $i64_load_little + ) + (func (;21;) (type 5) (param $value f32) (result f32) + i32.const 0 + local.get $value + f32.store + i32.const 0 + call $i32_load_little + f32.reinterpret_i32 + ) + (func (;22;) (type 6) (param $value f64) (result f64) + i32.const 0 + local.get $value + f64.store + i32.const 0 + call $i64_load_little + f64.reinterpret_i64 + ) + (memory (;0;) 1) + (export "i32_load16_s" (func 6)) + (export "i32_load16_u" (func 7)) + (export "i32_load" (func 8)) + (export "i64_load16_s" (func 9)) + (export "i64_load16_u" (func 10)) + (export "i64_load32_s" (func 11)) + (export "i64_load32_u" (func 12)) + (export "i64_load" (func 13)) + (export "f32_load" (func 14)) + (export "f64_load" (func 15)) + (export "i32_store16" (func 16)) + (export "i32_store" (func 17)) + (export "i64_store16" (func 18)) + (export "i64_store32" (func 19)) + (export "i64_store" (func 20)) + (export "f32_store" (func 21)) + (export "f64_store" (func 22)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/0.print b/tests/snapshots/testsuite/exports.wast/0.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/0.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/1.print b/tests/snapshots/testsuite/exports.wast/1.print new file mode 100644 index 0000000000..e7a58f9dc9 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/1.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) + (export "b" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/10.print b/tests/snapshots/testsuite/exports.wast/10.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/10.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/11.print b/tests/snapshots/testsuite/exports.wast/11.print new file mode 100644 index 0000000000..c34519993c --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/11.print @@ -0,0 +1,10 @@ +(module $Func + (type (;0;) (func (param i32) (result i32))) + (func $f (;0;) (type 0) (param $n i32) (result i32) + local.get $n + i32.const 1 + i32.add + return + ) + (export "e" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/14.print b/tests/snapshots/testsuite/exports.wast/14.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/14.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/15.print b/tests/snapshots/testsuite/exports.wast/15.print new file mode 100644 index 0000000000..5d29297e1f --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/15.print @@ -0,0 +1 @@ +(module $Other1) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/17.print b/tests/snapshots/testsuite/exports.wast/17.print new file mode 100644 index 0000000000..9b016a3b70 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/17.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 42 + ) + (export "a" (func 0)) + (export "b" (func 0)) + (export "c" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/2.print b/tests/snapshots/testsuite/exports.wast/2.print new file mode 100644 index 0000000000..92bc234966 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/2.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) + (export "a" (func 0)) + (export "b" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/29.print b/tests/snapshots/testsuite/exports.wast/29.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/29.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/3.print b/tests/snapshots/testsuite/exports.wast/3.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/3.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/30.print b/tests/snapshots/testsuite/exports.wast/30.print new file mode 100644 index 0000000000..cb29da92eb --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/30.print @@ -0,0 +1,5 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) + (export "b" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/31.print b/tests/snapshots/testsuite/exports.wast/31.print new file mode 100644 index 0000000000..ce572cc593 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/31.print @@ -0,0 +1,6 @@ +(module + (global (;0;) i32 i32.const 0) + (global (;1;) i32 i32.const 0) + (export "a" (global 0)) + (export "b" (global 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/32.print b/tests/snapshots/testsuite/exports.wast/32.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/32.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/33.print b/tests/snapshots/testsuite/exports.wast/33.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/33.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/34.print b/tests/snapshots/testsuite/exports.wast/34.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/34.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/35.print b/tests/snapshots/testsuite/exports.wast/35.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/35.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/36.print b/tests/snapshots/testsuite/exports.wast/36.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/36.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/37.print b/tests/snapshots/testsuite/exports.wast/37.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/37.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/38.print b/tests/snapshots/testsuite/exports.wast/38.print new file mode 100644 index 0000000000..ce0c9c5233 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/38.print @@ -0,0 +1,4 @@ +(module $Global + (global $g (;0;) i32 i32.const 42) + (export "e" (global $g)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/4.print b/tests/snapshots/testsuite/exports.wast/4.print new file mode 100644 index 0000000000..1e92fbc9f7 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/4.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) + (export "b" (func 0)) + (export "c" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/41.print b/tests/snapshots/testsuite/exports.wast/41.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/41.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/42.print b/tests/snapshots/testsuite/exports.wast/42.print new file mode 100644 index 0000000000..95a91d8cad --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/42.print @@ -0,0 +1 @@ +(module $Other2) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/5.print b/tests/snapshots/testsuite/exports.wast/5.print new file mode 100644 index 0000000000..786bbc30b4 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/5.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param i32)) + (export "a" (func 0)) + (export "b" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/52.print b/tests/snapshots/testsuite/exports.wast/52.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/52.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/53.print b/tests/snapshots/testsuite/exports.wast/53.print new file mode 100644 index 0000000000..eadf450224 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/53.print @@ -0,0 +1,5 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) + (export "b" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/54.print b/tests/snapshots/testsuite/exports.wast/54.print new file mode 100644 index 0000000000..d0cac41d19 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/54.print @@ -0,0 +1,6 @@ +(module + (table (;0;) 0 funcref) + (table (;1;) 0 funcref) + (export "a" (table 0)) + (export "b" (table 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/55.print b/tests/snapshots/testsuite/exports.wast/55.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/55.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/56.print b/tests/snapshots/testsuite/exports.wast/56.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/56.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/57.print b/tests/snapshots/testsuite/exports.wast/57.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/57.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/58.print b/tests/snapshots/testsuite/exports.wast/58.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/58.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/59.print b/tests/snapshots/testsuite/exports.wast/59.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/59.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/6.print b/tests/snapshots/testsuite/exports.wast/6.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/6.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/60.print b/tests/snapshots/testsuite/exports.wast/60.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/60.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/61.print b/tests/snapshots/testsuite/exports.wast/61.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/61.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/62.print b/tests/snapshots/testsuite/exports.wast/62.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/62.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/63.print b/tests/snapshots/testsuite/exports.wast/63.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/63.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/64.print b/tests/snapshots/testsuite/exports.wast/64.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/64.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/65.print b/tests/snapshots/testsuite/exports.wast/65.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/65.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/66.print b/tests/snapshots/testsuite/exports.wast/66.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/66.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/7.print b/tests/snapshots/testsuite/exports.wast/7.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/7.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/75.print b/tests/snapshots/testsuite/exports.wast/75.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/75.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/76.print b/tests/snapshots/testsuite/exports.wast/76.print new file mode 100644 index 0000000000..277573bf82 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/76.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) + (export "b" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/77.print b/tests/snapshots/testsuite/exports.wast/77.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/77.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/78.print b/tests/snapshots/testsuite/exports.wast/78.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/78.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/79.print b/tests/snapshots/testsuite/exports.wast/79.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/79.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/8.print b/tests/snapshots/testsuite/exports.wast/8.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/8.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/80.print b/tests/snapshots/testsuite/exports.wast/80.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/80.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/81.print b/tests/snapshots/testsuite/exports.wast/81.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/81.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/82.print b/tests/snapshots/testsuite/exports.wast/82.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/82.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/83.print b/tests/snapshots/testsuite/exports.wast/83.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/83.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/84.print b/tests/snapshots/testsuite/exports.wast/84.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/84.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/85.print b/tests/snapshots/testsuite/exports.wast/85.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/85.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/86.print b/tests/snapshots/testsuite/exports.wast/86.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/86.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/87.print b/tests/snapshots/testsuite/exports.wast/87.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/87.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/88.print b/tests/snapshots/testsuite/exports.wast/88.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/88.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/exports.wast/9.print b/tests/snapshots/testsuite/exports.wast/9.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/exports.wast/9.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/f32.wast/0.print b/tests/snapshots/testsuite/f32.wast/0.print new file mode 100644 index 0000000000..126ee2f6e7 --- /dev/null +++ b/tests/snapshots/testsuite/f32.wast/0.print @@ -0,0 +1,65 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f32) (result f32))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.add + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.sub + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.mul + ) + (func (;3;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.div + ) + (func (;4;) (type 1) (param $x f32) (result f32) + local.get $x + f32.sqrt + ) + (func (;5;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.min + ) + (func (;6;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.max + ) + (func (;7;) (type 1) (param $x f32) (result f32) + local.get $x + f32.ceil + ) + (func (;8;) (type 1) (param $x f32) (result f32) + local.get $x + f32.floor + ) + (func (;9;) (type 1) (param $x f32) (result f32) + local.get $x + f32.trunc + ) + (func (;10;) (type 1) (param $x f32) (result f32) + local.get $x + f32.nearest + ) + (export "add" (func 0)) + (export "sub" (func 1)) + (export "mul" (func 2)) + (export "div" (func 3)) + (export "sqrt" (func 4)) + (export "min" (func 5)) + (export "max" (func 6)) + (export "ceil" (func 7)) + (export "floor" (func 8)) + (export "trunc" (func 9)) + (export "nearest" (func 10)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/f32_bitwise.wast/0.print b/tests/snapshots/testsuite/f32_bitwise.wast/0.print new file mode 100644 index 0000000000..fee135e17d --- /dev/null +++ b/tests/snapshots/testsuite/f32_bitwise.wast/0.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f32 f32) (result f32))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.abs + ) + (func (;1;) (type 0) (param $x f32) (result f32) + local.get $x + f32.neg + ) + (func (;2;) (type 1) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.copysign + ) + (export "abs" (func 0)) + (export "neg" (func 1)) + (export "copysign" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/f32_cmp.wast/0.print b/tests/snapshots/testsuite/f32_cmp.wast/0.print new file mode 100644 index 0000000000..8d3105cddb --- /dev/null +++ b/tests/snapshots/testsuite/f32_cmp.wast/0.print @@ -0,0 +1,39 @@ +(module + (type (;0;) (func (param f32 f32) (result i32))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.eq + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.ne + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.lt + ) + (func (;3;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.le + ) + (func (;4;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.gt + ) + (func (;5;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.ge + ) + (export "eq" (func 0)) + (export "ne" (func 1)) + (export "lt" (func 2)) + (export "le" (func 3)) + (export "gt" (func 4)) + (export "ge" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/f64.wast/0.print b/tests/snapshots/testsuite/f64.wast/0.print new file mode 100644 index 0000000000..6c29542be8 --- /dev/null +++ b/tests/snapshots/testsuite/f64.wast/0.print @@ -0,0 +1,65 @@ +(module + (type (;0;) (func (param f64 f64) (result f64))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.add + ) + (func (;1;) (type 0) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.sub + ) + (func (;2;) (type 0) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.mul + ) + (func (;3;) (type 0) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.div + ) + (func (;4;) (type 1) (param $x f64) (result f64) + local.get $x + f64.sqrt + ) + (func (;5;) (type 0) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.min + ) + (func (;6;) (type 0) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.max + ) + (func (;7;) (type 1) (param $x f64) (result f64) + local.get $x + f64.ceil + ) + (func (;8;) (type 1) (param $x f64) (result f64) + local.get $x + f64.floor + ) + (func (;9;) (type 1) (param $x f64) (result f64) + local.get $x + f64.trunc + ) + (func (;10;) (type 1) (param $x f64) (result f64) + local.get $x + f64.nearest + ) + (export "add" (func 0)) + (export "sub" (func 1)) + (export "mul" (func 2)) + (export "div" (func 3)) + (export "sqrt" (func 4)) + (export "min" (func 5)) + (export "max" (func 6)) + (export "ceil" (func 7)) + (export "floor" (func 8)) + (export "trunc" (func 9)) + (export "nearest" (func 10)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/f64_bitwise.wast/0.print b/tests/snapshots/testsuite/f64_bitwise.wast/0.print new file mode 100644 index 0000000000..cef7519210 --- /dev/null +++ b/tests/snapshots/testsuite/f64_bitwise.wast/0.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f64) (result f64))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f64) (result f64) + local.get $x + f64.abs + ) + (func (;1;) (type 0) (param $x f64) (result f64) + local.get $x + f64.neg + ) + (func (;2;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.copysign + ) + (export "abs" (func 0)) + (export "neg" (func 1)) + (export "copysign" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/f64_cmp.wast/0.print b/tests/snapshots/testsuite/f64_cmp.wast/0.print new file mode 100644 index 0000000000..269468f6ce --- /dev/null +++ b/tests/snapshots/testsuite/f64_cmp.wast/0.print @@ -0,0 +1,39 @@ +(module + (type (;0;) (func (param f64 f64) (result i32))) + (func (;0;) (type 0) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.eq + ) + (func (;1;) (type 0) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.ne + ) + (func (;2;) (type 0) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.lt + ) + (func (;3;) (type 0) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.le + ) + (func (;4;) (type 0) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.gt + ) + (func (;5;) (type 0) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.ge + ) + (export "eq" (func 0)) + (export "ne" (func 1)) + (export "lt" (func 2)) + (export "le" (func 3)) + (export "gt" (func 4)) + (export "ge" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/fac.wast/0.print b/tests/snapshots/testsuite/fac.wast/0.print new file mode 100644 index 0000000000..83b2bd2723 --- /dev/null +++ b/tests/snapshots/testsuite/fac.wast/0.print @@ -0,0 +1,151 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (type (;1;) (func (param i64) (result i64 i64))) + (type (;2;) (func (param i64 i64) (result i64 i64 i64))) + (type (;3;) (func (param i64 i64) (result i64))) + (func (;0;) (type 0) (param i64) (result i64) + local.get 0 + i64.const 0 + i64.eq + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + local.get 0 + i64.const 1 + i64.sub + call 0 + i64.mul + end + ) + (func $fac-rec-named (;1;) (type 0) (param $n i64) (result i64) + local.get $n + i64.const 0 + i64.eq + if (result i64) ;; label = @1 + i64.const 1 + else + local.get $n + local.get $n + i64.const 1 + i64.sub + call $fac-rec-named + i64.mul + end + ) + (func (;2;) (type 0) (param i64) (result i64) + (local i64 i64) + local.get 0 + local.set 1 + i64.const 1 + local.set 2 + block ;; label = @1 + loop ;; label = @2 + local.get 1 + i64.const 0 + i64.eq + if ;; label = @3 + br 2 (;@1;) + else + local.get 1 + local.get 2 + i64.mul + local.set 2 + local.get 1 + i64.const 1 + i64.sub + local.set 1 + end + br 0 (;@2;) + end + end + local.get 2 + ) + (func (;3;) (type 0) (param $n i64) (result i64) + (local $i i64) (local $res i64) + local.get $n + local.set $i + i64.const 1 + local.set $res + block $done ;; label = @1 + loop $loop ;; label = @2 + local.get $i + i64.const 0 + i64.eq + if ;; label = @3 + br 2 (;@1;) + else + local.get $i + local.get $res + i64.mul + local.set $res + local.get $i + i64.const 1 + i64.sub + local.set $i + end + br 0 (;@2;) + end + end + local.get $res + ) + (func (;4;) (type 0) (param i64) (result i64) + (local i64) + i64.const 1 + local.set 1 + block ;; label = @1 + local.get 0 + i64.const 2 + i64.lt_s + br_if 0 (;@1;) + loop ;; label = @2 + local.get 1 + local.get 0 + i64.mul + local.set 1 + local.get 0 + i64.const -1 + i64.add + local.set 0 + local.get 0 + i64.const 1 + i64.gt_s + br_if 0 (;@2;) + end + end + local.get 1 + ) + (func $pick0 (;5;) (type 1) (param i64) (result i64 i64) + local.get 0 + local.get 0 + ) + (func $pick1 (;6;) (type 2) (param i64 i64) (result i64 i64 i64) + local.get 0 + local.get 1 + local.get 0 + ) + (func (;7;) (type 0) (param i64) (result i64) + i64.const 1 + local.get 0 + loop $l (type 3) (param i64 i64) (result i64) ;; label = @1 + call $pick1 + call $pick1 + i64.mul + call $pick1 + i64.const 1 + i64.sub + call $pick0 + i64.const 0 + i64.gt_u + br_if 0 (;@1;) + drop + return + end + ) + (export "fac-rec" (func 0)) + (export "fac-rec-named" (func $fac-rec-named)) + (export "fac-iter" (func 2)) + (export "fac-iter-named" (func 3)) + (export "fac-opt" (func 4)) + (export "fac-ssa" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/0.print b/tests/snapshots/testsuite/float_exprs.wast/0.print new file mode 100644 index 0000000000..dccaa18a0d --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/0.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $y + f64.mul + local.get $z + f64.add + ) + (export "f64.no_contraction" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/105.print b/tests/snapshots/testsuite/float_exprs.wast/105.print new file mode 100644 index 0000000000..44b7440441 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/105.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result f32) + local.get $x + local.get $y + f32.add + local.get $z + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $y + f64.add + local.get $z + f64.mul + ) + (export "f32.no_distribute" (func 0)) + (export "f64.no_distribute" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/116.print b/tests/snapshots/testsuite/float_exprs.wast/116.print new file mode 100644 index 0000000000..75ebc7fe1f --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/116.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result f32) + local.get $x + local.get $y + local.get $z + f32.div + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $y + local.get $z + f64.div + f64.mul + ) + (export "f32.no_regroup_div_mul" (func 0)) + (export "f64.no_regroup_div_mul" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/127.print b/tests/snapshots/testsuite/float_exprs.wast/127.print new file mode 100644 index 0000000000..4f7da5f2e0 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/127.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result f32) + local.get $x + local.get $y + f32.mul + local.get $z + f32.div + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $y + f64.mul + local.get $z + f64.div + ) + (export "f32.no_regroup_mul_div" (func 0)) + (export "f64.no_regroup_mul_div" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/138.print b/tests/snapshots/testsuite/float_exprs.wast/138.print new file mode 100644 index 0000000000..080bd6ff42 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/138.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32 f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32) + local.get $x + local.get $y + f32.add + local.get $z + f32.add + local.get $w + f32.add + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64) + local.get $x + local.get $y + f64.add + local.get $z + f64.add + local.get $w + f64.add + ) + (export "f32.no_reassociate_add" (func 0)) + (export "f64.no_reassociate_add" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/149.print b/tests/snapshots/testsuite/float_exprs.wast/149.print new file mode 100644 index 0000000000..d646c36bb2 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/149.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32 f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32) + local.get $x + local.get $y + f32.mul + local.get $z + f32.mul + local.get $w + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64) + local.get $x + local.get $y + f64.mul + local.get $z + f64.mul + local.get $w + f64.mul + ) + (export "f32.no_reassociate_mul" (func 0)) + (export "f64.no_reassociate_mul" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/160.print b/tests/snapshots/testsuite/float_exprs.wast/160.print new file mode 100644 index 0000000000..ae5038f64b --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/160.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x0p+0 (;=0;) + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x0p+0 (;=0;) + f64.div + ) + (export "f32.no_fold_div_0" (func 0)) + (export "f64.no_fold_div_0" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/17.print b/tests/snapshots/testsuite/float_exprs.wast/17.print new file mode 100644 index 0000000000..49f4f70ce4 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/17.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x0p+0 (;=0;) + f32.add + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x0p+0 (;=0;) + f64.add + ) + (export "f32.no_fold_add_zero" (func 0)) + (export "f64.no_fold_add_zero" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/177.print b/tests/snapshots/testsuite/float_exprs.wast/177.print new file mode 100644 index 0000000000..f45e221178 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/177.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const -0x0p+0 (;=-0;) + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const -0x0p+0 (;=-0;) + f64.div + ) + (export "f32.no_fold_div_neg0" (func 0)) + (export "f64.no_fold_div_neg0" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/194.print b/tests/snapshots/testsuite/float_exprs.wast/194.print new file mode 100644 index 0000000000..55ed7e8dfb --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/194.print @@ -0,0 +1,26 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $x + f32.mul + local.get $y + local.get $y + f32.mul + f32.add + f32.sqrt + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $x + f64.mul + local.get $y + local.get $y + f64.mul + f64.add + f64.sqrt + ) + (export "f32.no_fold_to_hypot" (func 0)) + (export "f64.no_fold_to_hypot" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/205.print b/tests/snapshots/testsuite/float_exprs.wast/205.print new file mode 100644 index 0000000000..f271f12f73 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/205.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const 0x1p+0 (;=1;) + local.get $x + f32.div + ) + (export "f32.no_approximate_reciprocal" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/211.print b/tests/snapshots/testsuite/float_exprs.wast/211.print new file mode 100644 index 0000000000..14fd0bec89 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/211.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const 0x1p+0 (;=1;) + local.get $x + f32.sqrt + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + f64.const 0x1p+0 (;=1;) + local.get $x + f64.sqrt + f64.div + ) + (export "f32.no_approximate_reciprocal_sqrt" (func 0)) + (export "f64.no_fuse_reciprocal_sqrt" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/22.print b/tests/snapshots/testsuite/float_exprs.wast/22.print new file mode 100644 index 0000000000..71064f47a4 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/22.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const 0x0p+0 (;=0;) + local.get $x + f32.sub + ) + (func (;1;) (type 1) (param $x f64) (result f64) + f64.const 0x0p+0 (;=0;) + local.get $x + f64.sub + ) + (export "f32.no_fold_zero_sub" (func 0)) + (export "f64.no_fold_zero_sub" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/222.print b/tests/snapshots/testsuite/float_exprs.wast/222.print new file mode 100644 index 0000000000..8ee8959b76 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/222.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const 0x1p+0 (;=1;) + local.get $x + f32.div + f32.sqrt + ) + (export "f32.no_approximate_sqrt_reciprocal" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/228.print b/tests/snapshots/testsuite/float_exprs.wast/228.print new file mode 100644 index 0000000000..29655a6961 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/228.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + f32.convert_i32_s + i32.trunc_f32_s + ) + (func (;1;) (type 0) (param i32) (result i32) + local.get 0 + f32.convert_i32_u + i32.trunc_f32_u + ) + (func (;2;) (type 1) (param i64) (result i64) + local.get 0 + f64.convert_i64_s + i64.trunc_f64_s + ) + (func (;3;) (type 1) (param i64) (result i64) + local.get 0 + f64.convert_i64_u + i64.trunc_f64_u + ) + (export "i32.no_fold_f32_s" (func 0)) + (export "i32.no_fold_f32_u" (func 1)) + (export "i64.no_fold_f64_s" (func 2)) + (export "i64.no_fold_f64_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/241.print b/tests/snapshots/testsuite/float_exprs.wast/241.print new file mode 100644 index 0000000000..7c79e93107 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/241.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.add + local.get $y + f32.sub + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.add + local.get $y + f64.sub + ) + (export "f32.no_fold_add_sub" (func 0)) + (export "f64.no_fold_add_sub" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/252.print b/tests/snapshots/testsuite/float_exprs.wast/252.print new file mode 100644 index 0000000000..e727562c7a --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/252.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.sub + local.get $y + f32.add + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.sub + local.get $y + f64.add + ) + (export "f32.no_fold_sub_add" (func 0)) + (export "f64.no_fold_sub_add" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/263.print b/tests/snapshots/testsuite/float_exprs.wast/263.print new file mode 100644 index 0000000000..69daeac49d --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/263.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.mul + local.get $y + f32.div + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.mul + local.get $y + f64.div + ) + (export "f32.no_fold_mul_div" (func 0)) + (export "f64.no_fold_mul_div" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/27.print b/tests/snapshots/testsuite/float_exprs.wast/27.print new file mode 100644 index 0000000000..7c5976389a --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/27.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x0p+0 (;=0;) + f32.sub + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x0p+0 (;=0;) + f64.sub + ) + (export "f32.no_fold_sub_zero" (func 0)) + (export "f64.no_fold_sub_zero" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/274.print b/tests/snapshots/testsuite/float_exprs.wast/274.print new file mode 100644 index 0000000000..69d98263f0 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/274.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.div + local.get $y + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.div + local.get $y + f64.mul + ) + (export "f32.no_fold_div_mul" (func 0)) + (export "f64.no_fold_div_mul" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/285.print b/tests/snapshots/testsuite/float_exprs.wast/285.print new file mode 100644 index 0000000000..81dfdab477 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/285.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x1p+1 (;=2;) + f32.div + f32.const 0x1p+1 (;=2;) + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x1p+1 (;=2;) + f64.div + f64.const 0x1p+1 (;=2;) + f64.mul + ) + (export "f32.no_fold_div2_mul2" (func 0)) + (export "f64.no_fold_div2_mul2" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/288.print b/tests/snapshots/testsuite/float_exprs.wast/288.print new file mode 100644 index 0000000000..b25b8da1af --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/288.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f64) (result f64) + local.get $x + f32.demote_f64 + f64.promote_f32 + ) + (export "no_fold_demote_promote" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/294.print b/tests/snapshots/testsuite/float_exprs.wast/294.print new file mode 100644 index 0000000000..7ee4613899 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/294.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f64.promote_f32 + f32.demote_f64 + ) + (export "no_fold_promote_demote" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/30.print b/tests/snapshots/testsuite/float_exprs.wast/30.print new file mode 100644 index 0000000000..e5859fdd76 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/30.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x0p+0 (;=0;) + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x0p+0 (;=0;) + f64.mul + ) + (export "f32.no_fold_mul_zero" (func 0)) + (export "f64.no_fold_mul_zero" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/308.print b/tests/snapshots/testsuite/float_exprs.wast/308.print new file mode 100644 index 0000000000..e35eafa03e --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/308.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f64 f32) (result f32))) + (type (;1;) (func (param f32 f64) (result f32))) + (func (;0;) (type 0) (param $x f64) (param $y f32) (result f32) + local.get $x + local.get $y + f64.promote_f32 + f64.add + f32.demote_f64 + ) + (func (;1;) (type 1) (param $y f32) (param $x f64) (result f32) + local.get $y + f64.promote_f32 + local.get $x + f64.add + f32.demote_f64 + ) + (export "no_demote_mixed_add" (func 0)) + (export "no_demote_mixed_add_commuted" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/319.print b/tests/snapshots/testsuite/float_exprs.wast/319.print new file mode 100644 index 0000000000..b1132166c0 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/319.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param f64 f32) (result f32))) + (func (;0;) (type 0) (param $x f64) (param $y f32) (result f32) + local.get $x + local.get $y + f64.promote_f32 + f64.sub + f32.demote_f64 + ) + (export "no_demote_mixed_sub" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/325.print b/tests/snapshots/testsuite/float_exprs.wast/325.print new file mode 100644 index 0000000000..897dd718a9 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/325.print @@ -0,0 +1,100 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + i32.trunc_f32_s + f32.convert_i32_s + ) + (func (;1;) (type 0) (param $x f32) (result f32) + local.get $x + i32.trunc_f32_u + f32.convert_i32_s + ) + (func (;2;) (type 0) (param $x f32) (result f32) + local.get $x + i32.trunc_f32_s + f32.convert_i32_u + ) + (func (;3;) (type 0) (param $x f32) (result f32) + local.get $x + i32.trunc_f32_u + f32.convert_i32_u + ) + (func (;4;) (type 1) (param $x f64) (result f64) + local.get $x + i32.trunc_f64_s + f64.convert_i32_s + ) + (func (;5;) (type 1) (param $x f64) (result f64) + local.get $x + i32.trunc_f64_u + f64.convert_i32_s + ) + (func (;6;) (type 1) (param $x f64) (result f64) + local.get $x + i32.trunc_f64_s + f64.convert_i32_u + ) + (func (;7;) (type 1) (param $x f64) (result f64) + local.get $x + i32.trunc_f64_u + f64.convert_i32_u + ) + (func (;8;) (type 0) (param $x f32) (result f32) + local.get $x + i64.trunc_f32_s + f32.convert_i64_s + ) + (func (;9;) (type 0) (param $x f32) (result f32) + local.get $x + i64.trunc_f32_u + f32.convert_i64_s + ) + (func (;10;) (type 0) (param $x f32) (result f32) + local.get $x + i64.trunc_f32_s + f32.convert_i64_u + ) + (func (;11;) (type 0) (param $x f32) (result f32) + local.get $x + i64.trunc_f32_u + f32.convert_i64_u + ) + (func (;12;) (type 1) (param $x f64) (result f64) + local.get $x + i64.trunc_f64_s + f64.convert_i64_s + ) + (func (;13;) (type 1) (param $x f64) (result f64) + local.get $x + i64.trunc_f64_u + f64.convert_i64_s + ) + (func (;14;) (type 1) (param $x f64) (result f64) + local.get $x + i64.trunc_f64_s + f64.convert_i64_u + ) + (func (;15;) (type 1) (param $x f64) (result f64) + local.get $x + i64.trunc_f64_u + f64.convert_i64_u + ) + (export "f32.i32.no_fold_trunc_s_convert_s" (func 0)) + (export "f32.i32.no_fold_trunc_u_convert_s" (func 1)) + (export "f32.i32.no_fold_trunc_s_convert_u" (func 2)) + (export "f32.i32.no_fold_trunc_u_convert_u" (func 3)) + (export "f64.i32.no_fold_trunc_s_convert_s" (func 4)) + (export "f64.i32.no_fold_trunc_u_convert_s" (func 5)) + (export "f64.i32.no_fold_trunc_s_convert_u" (func 6)) + (export "f64.i32.no_fold_trunc_u_convert_u" (func 7)) + (export "f32.i64.no_fold_trunc_s_convert_s" (func 8)) + (export "f32.i64.no_fold_trunc_u_convert_s" (func 9)) + (export "f32.i64.no_fold_trunc_s_convert_u" (func 10)) + (export "f32.i64.no_fold_trunc_u_convert_u" (func 11)) + (export "f64.i64.no_fold_trunc_s_convert_s" (func 12)) + (export "f64.i64.no_fold_trunc_u_convert_s" (func 13)) + (export "f64.i64.no_fold_trunc_s_convert_u" (func 14)) + (export "f64.i64.no_fold_trunc_u_convert_u" (func 15)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/358.print b/tests/snapshots/testsuite/float_exprs.wast/358.print new file mode 100644 index 0000000000..9d2f6e781e --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/358.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param i32 f32))) + (type (;1;) (func (param i32) (result f32))) + (func (;0;) (type 0) (param $i i32) (param $x f32) + local.get $i + local.get $x + f32.store + ) + (func (;1;) (type 0) (param $n i32) (param $z f32) + (local $i i32) + block $exit ;; label = @1 + loop $cont ;; label = @2 + local.get $i + local.get $i + f32.load + local.get $z + f32.div + f32.store + local.get $i + i32.const 4 + i32.add + local.set $i + local.get $i + local.get $n + i32.lt_u + br_if 0 (;@2;) + end + end + ) + (func (;2;) (type 1) (param $i i32) (result f32) + local.get $i + f32.load + ) + (memory (;0;) 1 1) + (export "init" (func 0)) + (export "run" (func 1)) + (export "check" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/372.print b/tests/snapshots/testsuite/float_exprs.wast/372.print new file mode 100644 index 0000000000..ca30eb3df7 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/372.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param i32 f64))) + (type (;1;) (func (param i32) (result f64))) + (func (;0;) (type 0) (param $i i32) (param $x f64) + local.get $i + local.get $x + f64.store + ) + (func (;1;) (type 0) (param $n i32) (param $z f64) + (local $i i32) + block $exit ;; label = @1 + loop $cont ;; label = @2 + local.get $i + local.get $i + f64.load + local.get $z + f64.div + f64.store + local.get $i + i32.const 8 + i32.add + local.set $i + local.get $i + local.get $n + i32.lt_u + br_if 0 (;@2;) + end + end + ) + (func (;2;) (type 1) (param $i i32) (result f64) + local.get $i + f64.load + ) + (memory (;0;) 1 1) + (export "init" (func 0)) + (export "run" (func 1)) + (export "check" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/386.print b/tests/snapshots/testsuite/float_exprs.wast/386.print new file mode 100644 index 0000000000..91be34d77e --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/386.print @@ -0,0 +1,60 @@ +(module + (type (;0;) (func (param f32 f32) (result i32))) + (type (;1;) (func (param f64 f64) (result i32))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.ge + i32.eqz + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.gt + i32.eqz + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.le + i32.eqz + ) + (func (;3;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.lt + i32.eqz + ) + (func (;4;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.ge + i32.eqz + ) + (func (;5;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.gt + i32.eqz + ) + (func (;6;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.le + i32.eqz + ) + (func (;7;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.lt + i32.eqz + ) + (export "f32.ult" (func 0)) + (export "f32.ule" (func 1)) + (export "f32.ugt" (func 2)) + (export "f32.uge" (func 3)) + (export "f64.ult" (func 4)) + (export "f64.ule" (func 5)) + (export "f64.ugt" (func 6)) + (export "f64.uge" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/39.print b/tests/snapshots/testsuite/float_exprs.wast/39.print new file mode 100644 index 0000000000..e0226a3859 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/39.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x1p+0 (;=1;) + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x1p+0 (;=1;) + f64.mul + ) + (export "f32.no_fold_mul_one" (func 0)) + (export "f64.no_fold_mul_one" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/419.print b/tests/snapshots/testsuite/float_exprs.wast/419.print new file mode 100644 index 0000000000..c46762e729 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/419.print @@ -0,0 +1,76 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + local.get $x + local.get $y + f32.lt + select + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + local.get $x + local.get $y + f32.le + select + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + local.get $x + local.get $y + f32.gt + select + ) + (func (;3;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + local.get $x + local.get $y + f32.ge + select + ) + (func (;4;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + local.get $x + local.get $y + f64.lt + select + ) + (func (;5;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + local.get $x + local.get $y + f64.le + select + ) + (func (;6;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + local.get $x + local.get $y + f64.gt + select + ) + (func (;7;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + local.get $x + local.get $y + f64.ge + select + ) + (export "f32.no_fold_lt_select" (func 0)) + (export "f32.no_fold_le_select" (func 1)) + (export "f32.no_fold_gt_select" (func 2)) + (export "f32.no_fold_ge_select" (func 3)) + (export "f64.no_fold_lt_select" (func 4)) + (export "f64.no_fold_le_select" (func 5)) + (export "f64.no_fold_gt_select" (func 6)) + (export "f64.no_fold_ge_select" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/42.print b/tests/snapshots/testsuite/float_exprs.wast/42.print new file mode 100644 index 0000000000..a2c9d1e782 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/42.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const 0x0p+0 (;=0;) + local.get $x + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + f64.const 0x0p+0 (;=0;) + local.get $x + f64.div + ) + (export "f32.no_fold_zero_div" (func 0)) + (export "f64.no_fold_zero_div" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/452.print b/tests/snapshots/testsuite/float_exprs.wast/452.print new file mode 100644 index 0000000000..f1a740d4c8 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/452.print @@ -0,0 +1,92 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.lt + if (result f32) ;; label = @1 + local.get $x + else + local.get $y + end + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.le + if (result f32) ;; label = @1 + local.get $x + else + local.get $y + end + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.gt + if (result f32) ;; label = @1 + local.get $x + else + local.get $y + end + ) + (func (;3;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.ge + if (result f32) ;; label = @1 + local.get $x + else + local.get $y + end + ) + (func (;4;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.lt + if (result f64) ;; label = @1 + local.get $x + else + local.get $y + end + ) + (func (;5;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.le + if (result f64) ;; label = @1 + local.get $x + else + local.get $y + end + ) + (func (;6;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.gt + if (result f64) ;; label = @1 + local.get $x + else + local.get $y + end + ) + (func (;7;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.ge + if (result f64) ;; label = @1 + local.get $x + else + local.get $y + end + ) + (export "f32.no_fold_lt_if" (func 0)) + (export "f32.no_fold_le_if" (func 1)) + (export "f32.no_fold_gt_if" (func 2)) + (export "f32.no_fold_ge_if" (func 3)) + (export "f64.no_fold_lt_if" (func 4)) + (export "f64.no_fold_le_if" (func 5)) + (export "f64.no_fold_gt_if" (func 6)) + (export "f64.no_fold_ge_if" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/485.print b/tests/snapshots/testsuite/float_exprs.wast/485.print new file mode 100644 index 0000000000..b6648110a2 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/485.print @@ -0,0 +1,84 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.neg + local.get $x + local.get $x + f32.const 0x0p+0 (;=0;) + f32.lt + select + ) + (func (;1;) (type 0) (param $x f32) (result f32) + local.get $x + f32.neg + local.get $x + local.get $x + f32.const -0x0p+0 (;=-0;) + f32.le + select + ) + (func (;2;) (type 0) (param $x f32) (result f32) + local.get $x + local.get $x + f32.neg + local.get $x + f32.const -0x0p+0 (;=-0;) + f32.gt + select + ) + (func (;3;) (type 0) (param $x f32) (result f32) + local.get $x + local.get $x + f32.neg + local.get $x + f32.const 0x0p+0 (;=0;) + f32.ge + select + ) + (func (;4;) (type 1) (param $x f64) (result f64) + local.get $x + f64.neg + local.get $x + local.get $x + f64.const 0x0p+0 (;=0;) + f64.lt + select + ) + (func (;5;) (type 1) (param $x f64) (result f64) + local.get $x + f64.neg + local.get $x + local.get $x + f64.const -0x0p+0 (;=-0;) + f64.le + select + ) + (func (;6;) (type 1) (param $x f64) (result f64) + local.get $x + local.get $x + f64.neg + local.get $x + f64.const -0x0p+0 (;=-0;) + f64.gt + select + ) + (func (;7;) (type 1) (param $x f64) (result f64) + local.get $x + local.get $x + f64.neg + local.get $x + f64.const 0x0p+0 (;=0;) + f64.ge + select + ) + (export "f32.no_fold_lt_select_to_abs" (func 0)) + (export "f32.no_fold_le_select_to_abs" (func 1)) + (export "f32.no_fold_gt_select_to_abs" (func 2)) + (export "f32.no_fold_ge_select_to_abs" (func 3)) + (export "f64.no_fold_lt_select_to_abs" (func 4)) + (export "f64.no_fold_le_select_to_abs" (func 5)) + (export "f64.no_fold_gt_select_to_abs" (func 6)) + (export "f64.no_fold_ge_select_to_abs" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/51.print b/tests/snapshots/testsuite/float_exprs.wast/51.print new file mode 100644 index 0000000000..407f8ae72d --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/51.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x1p+0 (;=1;) + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x1p+0 (;=1;) + f64.div + ) + (export "f32.no_fold_div_one" (func 0)) + (export "f64.no_fold_div_one" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/518.print b/tests/snapshots/testsuite/float_exprs.wast/518.print new file mode 100644 index 0000000000..ce4a69ffed --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/518.print @@ -0,0 +1,100 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x0p+0 (;=0;) + f32.lt + if (result f32) ;; label = @1 + local.get $x + f32.neg + else + local.get $x + end + ) + (func (;1;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const -0x0p+0 (;=-0;) + f32.le + if (result f32) ;; label = @1 + local.get $x + f32.neg + else + local.get $x + end + ) + (func (;2;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const -0x0p+0 (;=-0;) + f32.gt + if (result f32) ;; label = @1 + local.get $x + else + local.get $x + f32.neg + end + ) + (func (;3;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x0p+0 (;=0;) + f32.ge + if (result f32) ;; label = @1 + local.get $x + else + local.get $x + f32.neg + end + ) + (func (;4;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x0p+0 (;=0;) + f64.lt + if (result f64) ;; label = @1 + local.get $x + f64.neg + else + local.get $x + end + ) + (func (;5;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const -0x0p+0 (;=-0;) + f64.le + if (result f64) ;; label = @1 + local.get $x + f64.neg + else + local.get $x + end + ) + (func (;6;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const -0x0p+0 (;=-0;) + f64.gt + if (result f64) ;; label = @1 + local.get $x + else + local.get $x + f64.neg + end + ) + (func (;7;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x0p+0 (;=0;) + f64.ge + if (result f64) ;; label = @1 + local.get $x + else + local.get $x + f64.neg + end + ) + (export "f32.no_fold_lt_if_to_abs" (func 0)) + (export "f32.no_fold_le_if_to_abs" (func 1)) + (export "f32.no_fold_gt_if_to_abs" (func 2)) + (export "f32.no_fold_ge_if_to_abs" (func 3)) + (export "f64.no_fold_lt_if_to_abs" (func 4)) + (export "f64.no_fold_le_if_to_abs" (func 5)) + (export "f64.no_fold_gt_if_to_abs" (func 6)) + (export "f64.no_fold_ge_if_to_abs" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/54.print b/tests/snapshots/testsuite/float_exprs.wast/54.print new file mode 100644 index 0000000000..c360e04850 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/54.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const -0x1p+0 (;=-1;) + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const -0x1p+0 (;=-1;) + f64.div + ) + (export "f32.no_fold_div_neg1" (func 0)) + (export "f64.no_fold_div_neg1" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/551.print b/tests/snapshots/testsuite/float_exprs.wast/551.print new file mode 100644 index 0000000000..28126e2231 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/551.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result f64))) + (func (;0;) (type 0) (result f32) + f32.const 0x1.553f7cp+0 (;=1.333;) + f32.const 0x1.39999ap+0 (;=1.225;) + f32.add + f32.const 0x1.553f7cp+0 (;=1.333;) + f32.sub + f32.const 0x1.39999ap+0 (;=1.225;) + f32.sub + ) + (func (;1;) (type 1) (result f64) + f64.const 0x1.553f7ced91687p+0 (;=1.333;) + f64.const 0x1.399999999999ap+0 (;=1.225;) + f64.add + f64.const 0x1.553f7ced91687p+0 (;=1.333;) + f64.sub + f64.const 0x1.399999999999ap+0 (;=1.225;) + f64.sub + ) + (export "f32.incorrect_correction" (func 0)) + (export "f64.incorrect_correction" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/554.print b/tests/snapshots/testsuite/float_exprs.wast/554.print new file mode 100644 index 0000000000..628f3d370e --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/554.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func (result f32))) + (func (;0;) (type 0) (result f32) + (local $x f32) (local $r f32) (local $q f32) (local $z0 f32) (local $z1 f32) + f32.const 0x1.388p+7 (;=156.25;) + local.set $x + f32.const 0x1.a0aaaap+7 (;=208.33333;) + local.set $r + f32.const 0x1.c78e2ap+0 (;=1.779513;) + local.set $q + local.get $r + f32.neg + local.get $x + f32.mul + local.get $x + local.get $q + f32.mul + local.get $r + f32.sub + f32.div + local.set $z0 + local.get $r + f32.neg + local.get $x + f32.mul + local.get $x + local.get $q + f32.mul + local.get $r + f32.sub + f32.div + local.set $z1 + block ;; label = @1 + local.get $z0 + local.get $z1 + f32.eq + br_if 0 (;@1;) + unreachable + end + local.get $z1 + ) + (export "calculate" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/556.print b/tests/snapshots/testsuite/float_exprs.wast/556.print new file mode 100644 index 0000000000..684128922d --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/556.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + (local $x f64) (local $r f64) (local $q f64) (local $z0 f64) (local $z1 f64) + f64.const 0x1.388p+7 (;=156.25;) + local.set $x + f64.const 0x1.a0aaaaaab064bp+7 (;=208.333333334;) + local.set $r + f64.const 0x1.c78e2aae3d096p+0 (;=1.77951304201;) + local.set $q + local.get $r + f64.neg + local.get $x + f64.mul + local.get $x + local.get $q + f64.mul + local.get $r + f64.sub + f64.div + local.set $z0 + local.get $r + f64.neg + local.get $x + f64.mul + local.get $x + local.get $q + f64.mul + local.get $r + f64.sub + f64.div + local.set $z1 + block ;; label = @1 + local.get $z0 + local.get $z1 + f64.eq + br_if 0 (;@1;) + unreachable + end + local.get $z1 + ) + (export "calculate" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/558.print b/tests/snapshots/testsuite/float_exprs.wast/558.print new file mode 100644 index 0000000000..ba2d93e1ed --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/558.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const 0x0p+0 (;=0;) + f32.const -0x0p+0 (;=-0;) + local.get $x + f32.sub + f32.sub + ) + (export "llvm_pr26746" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/560.print b/tests/snapshots/testsuite/float_exprs.wast/560.print new file mode 100644 index 0000000000..0c3feaa6f2 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/560.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func (param i32) (result f32))) + (func (;0;) (type 0) (param $x i32) (result f32) + local.get $x + i32.const 268435455 + i32.and + f32.convert_i32_s + f32.const -0x1p+23 (;=-8388608;) + f32.add + ) + (export "llvm_pr27153" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/562.print b/tests/snapshots/testsuite/float_exprs.wast/562.print new file mode 100644 index 0000000000..a45c71b1c2 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/562.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (param i32 i32) (result f32))) + (func (;0;) (type 0) (param $x i32) (param $y i32) (result f32) + local.get $x + i32.const -25034805 + i32.or + f32.convert_i32_s + local.get $y + i32.const 14942208 + i32.and + f32.convert_i32_s + f32.add + ) + (export "llvm_pr27036" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/564.print b/tests/snapshots/testsuite/float_exprs.wast/564.print new file mode 100644 index 0000000000..4ea73785f4 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/564.print @@ -0,0 +1,31 @@ +(module + (type (;0;) (func (param f64 f64 f64 f64) (result f64))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (type (;2;) (func (param f32 f32 f32) (result f32))) + (func (;0;) (type 0) (param $a f64) (param $b f64) (param $c f64) (param $d f64) (result f64) + local.get $a + local.get $b + f64.mul + local.get $c + local.get $d + f64.mul + f64.div + ) + (func (;1;) (type 1) (param $a f64) (param $b f64) (param $c f64) (result f64) + local.get $a + local.get $b + f64.mul + local.get $c + f64.sub + ) + (func (;2;) (type 2) (param $a f32) (param $b f32) (param $c f32) (result f32) + local.get $a + local.get $b + f32.mul + local.get $c + f32.mul + ) + (export "thepast0" (func 0)) + (export "thepast1" (func 1)) + (export "thepast2" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/568.print b/tests/snapshots/testsuite/float_exprs.wast/568.print new file mode 100644 index 0000000000..b0cc022776 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/568.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const 0x1p+0 (;=1;) + local.get $x + f32.div + ) + (export "inverse" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/57.print b/tests/snapshots/testsuite/float_exprs.wast/57.print new file mode 100644 index 0000000000..980ed871d1 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/57.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const -0x0p+0 (;=-0;) + local.get $x + f32.sub + ) + (func (;1;) (type 1) (param $x f64) (result f64) + f64.const -0x0p+0 (;=-0;) + local.get $x + f64.sub + ) + (export "f32.no_fold_neg0_sub" (func 0)) + (export "f64.no_fold_neg0_sub" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/570.print b/tests/snapshots/testsuite/float_exprs.wast/570.print new file mode 100644 index 0000000000..74f92a0328 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/570.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.sqrt + f32.const 0x1p+1 (;=2;) + f32.sub + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.sqrt + f64.const 0x1p+1 (;=2;) + f64.sub + ) + (export "f32_sqrt_minus_2" (func 0)) + (export "f64_sqrt_minus_2" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/573.print b/tests/snapshots/testsuite/float_exprs.wast/573.print new file mode 100644 index 0000000000..59f6cacf90 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/573.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const 0x1p+0 (;=1;) + f32.const 0x1p+0 (;=1;) + local.get $x + f32.div + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + f64.const 0x1p+0 (;=1;) + f64.const 0x1p+0 (;=1;) + local.get $x + f64.div + f64.div + ) + (export "f32.no_fold_recip_recip" (func 0)) + (export "f64.no_fold_recip_recip" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/592.print b/tests/snapshots/testsuite/float_exprs.wast/592.print new file mode 100644 index 0000000000..789afe7cc2 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/592.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.add + local.get $x + local.get $y + f32.sub + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.add + local.get $x + local.get $y + f64.sub + f64.mul + ) + (export "f32.no_algebraic_factoring" (func 0)) + (export "f64.no_algebraic_factoring" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/6.print b/tests/snapshots/testsuite/float_exprs.wast/6.print new file mode 100644 index 0000000000..89287473da --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/6.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result f32) + local.get $x + local.get $y + f32.mul + local.get $z + f32.add + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $y + f64.mul + local.get $z + f64.add + ) + (export "f32.no_fma" (func 0)) + (export "f64.no_fma" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/60.print b/tests/snapshots/testsuite/float_exprs.wast/60.print new file mode 100644 index 0000000000..4994e2330e --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/60.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const -0x1p+0 (;=-1;) + local.get $x + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (result f64) + f64.const -0x1p+0 (;=-1;) + local.get $x + f64.mul + ) + (export "f32.no_fold_neg1_mul" (func 0)) + (export "f64.no_fold_neg1_mul" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/603.print b/tests/snapshots/testsuite/float_exprs.wast/603.print new file mode 100644 index 0000000000..63439c5760 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/603.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $x + f32.mul + local.get $y + local.get $y + f32.mul + f32.sub + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $x + f64.mul + local.get $y + local.get $y + f64.mul + f64.sub + ) + (export "f32.no_algebraic_factoring" (func 0)) + (export "f64.no_algebraic_factoring" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/614.print b/tests/snapshots/testsuite/float_exprs.wast/614.print new file mode 100644 index 0000000000..a5d74d537b --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/614.print @@ -0,0 +1,59 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result f32))) + (func (;0;) (type 0) (param $i i32) (param $j i32) (param $k i32) + (local $x0 f32) (local $x1 f32) (local $x2 f32) (local $x3 f32) (local $y0 f32) (local $y1 f32) (local $y2 f32) (local $y3 f32) + local.get $i + f32.load + local.set $x0 + local.get $i + f32.load offset=4 + local.set $x1 + local.get $i + f32.load offset=8 + local.set $x2 + local.get $i + f32.load offset=12 + local.set $x3 + local.get $j + f32.load + local.set $y0 + local.get $j + f32.load offset=4 + local.set $y1 + local.get $j + f32.load offset=8 + local.set $y2 + local.get $j + f32.load offset=12 + local.set $y3 + local.get $k + local.get $x0 + local.get $y0 + f32.add + f32.store + local.get $k + local.get $x1 + local.get $y1 + f32.add + f32.store offset=4 + local.get $k + local.get $x2 + local.get $y2 + f32.add + f32.store offset=8 + local.get $k + local.get $x3 + local.get $y3 + f32.add + f32.store offset=12 + ) + (func (;1;) (type 1) (param $k i32) (result f32) + local.get $k + f32.load + ) + (memory (;0;) 1 1) + (export "f32.simple_x4_sum" (func 0)) + (export "f32.load" (func 1)) + (data (;0;) (i32.const 0) "\01\00\00\00\01\00\00\80\01\00\00\00\01\00\00\80\01\00\00\00\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/620.print b/tests/snapshots/testsuite/float_exprs.wast/620.print new file mode 100644 index 0000000000..7148701a48 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/620.print @@ -0,0 +1,59 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result f64))) + (func (;0;) (type 0) (param $i i32) (param $j i32) (param $k i32) + (local $x0 f64) (local $x1 f64) (local $x2 f64) (local $x3 f64) (local $y0 f64) (local $y1 f64) (local $y2 f64) (local $y3 f64) + local.get $i + f64.load + local.set $x0 + local.get $i + f64.load offset=8 + local.set $x1 + local.get $i + f64.load offset=16 + local.set $x2 + local.get $i + f64.load offset=24 + local.set $x3 + local.get $j + f64.load + local.set $y0 + local.get $j + f64.load offset=8 + local.set $y1 + local.get $j + f64.load offset=16 + local.set $y2 + local.get $j + f64.load offset=24 + local.set $y3 + local.get $k + local.get $x0 + local.get $y0 + f64.add + f64.store + local.get $k + local.get $x1 + local.get $y1 + f64.add + f64.store offset=8 + local.get $k + local.get $x2 + local.get $y2 + f64.add + f64.store offset=16 + local.get $k + local.get $x3 + local.get $y3 + f64.add + f64.store offset=24 + ) + (func (;1;) (type 1) (param $k i32) (result f64) + local.get $k + f64.load + ) + (memory (;0;) 1 1) + (export "f64.simple_x4_sum" (func 0)) + (export "f64.load" (func 1)) + (data (;0;) (i32.const 0) "\01\00\00\00\00\00\00\00\01\00\00\00\00\00\00\80\01\00\00\00\00\00\00\00\01\00\00\00\00\00\00\80\01\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/626.print b/tests/snapshots/testsuite/float_exprs.wast/626.print new file mode 100644 index 0000000000..52dce95a2e --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/626.print @@ -0,0 +1,62 @@ +(module + (type (;0;) (func (param i32 i32) (result f32))) + (func (;0;) (type 0) (param $p i32) (param $n i32) (result f32) + (local $sum f32) (local $c f32) (local $t f32) + block $exit ;; label = @1 + loop $top ;; label = @2 + local.get $c + local.get $p + f32.load + local.get $t + f32.sub + local.tee $t + f32.add + local.tee $sum + local.get $c + f32.sub + local.get $t + f32.sub + local.set $t + local.get $p + i32.const 4 + i32.add + local.set $p + local.get $sum + local.set $c + local.get $n + i32.const -1 + i32.add + local.tee $n + br_if 0 (;@2;) + end + end + local.get $sum + ) + (func (;1;) (type 0) (param $p i32) (param $n i32) (result f32) + (local $sum f32) + block $exit ;; label = @1 + loop $top ;; label = @2 + local.get $sum + local.get $p + f32.load + f32.add + local.set $sum + local.get $p + i32.const 4 + i32.add + local.set $p + local.get $n + i32.const -1 + i32.add + local.set $n + local.get $n + br_if 0 (;@2;) + end + end + local.get $sum + ) + (memory (;0;) 1 1) + (export "f32.kahan_sum" (func 0)) + (export "f32.plain_sum" (func 1)) + (data (;0;) (i32.const 0) "\c4\c5W$\a5\84\c8\0bm\b8K.\f2v\17\1c\caJV\1e\1bnq\22]\17\1en\bf\cd\14\5c\c7!UQ9\9c\1f\b2Q\f0\a3\93\d7\c1,\ae~\a8(:\01!\f4\0aX\93\f8Bw\9f\839j_\ba\f7\0a\d8Qj4\ca\ad\c64\0e\d8&\dcL3\1c\ed)\90\a8x\0f\d1\cev1#\83\b85\e8\f2D\b0\d3\a1\fc\bb2\e1\b0\baiD\09\d6\d9}\ff.\c0Z6\143\14>\a9\fa\87m\8b\bc\ce\9d\a7\fd\c4\e9\85?\dd\d7\e1\18\a6P&rn?s\0f\f8\12\93#4av\12H\c0\9b\05\93\eb\ac\86\de\94>U\e8\8c\e8\dd\e4\fc\95G\beV\03! L\e6\bf{\f6\7f\d5\bas\1c\c1\14\8f\c4'\96\b3\bd3\ffxA_\c0Z\ce\f6gns\9a\17fp\03\f8\ce'\a3R\b2\9f;\bf\fb\ae\ed\d3Z\f87W\f0\f5n\ef\b1Mp=T\a7\01\9a\85\08H\91\f5\9d\0c`\87[\d9T\1eQm\88\8e\08\8c\a5q:V\08gF\8f\8f\13*,\ec,\1f\b4b+oA\0a\c4eB\a21k,}>\bbu\ac\86\970\d9H\cd\9a\1fV\c4\c6\e4\12\c0\9d\fb\ee\02\8c\ce\1c\f2\1e\a1x#\db\c4\1eI\03\d3q\cc\08P\c5\d8\5c\ed\d5\b5e\ac\b5\c9!\d2\c9)v\de\f00\1a[<\f2;\db:9\82:\16\08o\a8\f1\beii\99q\a6\05\d3\14\93*\16\f2/\11\c7~ \bb\91D\ee\f8\e4\01S\c0\b9\7f\f0\bf\f0\03\9cm\b1\df\a2D\01mkq+\5c\b3!\19F^\8f\db\91\d3|xk\b7\12\00\8f\eb\bd\8a\f5\d4.\c4\c1\1e\dfscYGI\03\0a\b7\cf$\cf\9c\0eDz\9e\14\fbB\bf\9d90\9e\a0\ab/\d1\ae\9ej\83C\e3U}\85\bfc\8a\f8\96\10\1f\fem\e7\22\1b\e1iF\8aD\c8\c8\f9\0c+\19\07\a5\02>\f20\10\9a\85\8a_\ef\81E\a0w\b1\03\10sK\ae\98\9dG\bf\9a-:\d5\0f\03f\e3=S\d9@\ce\1fo2/!+#!lb\d4\a7>\a8\ce(1-\00=g^\af\a0\cf.\d2\b9k\84\ebi\08\ad\bc\0b\c0A\c4P\b6\e3P1\e8\ce\e2\96eU\9c\16F\e6\b0-:\e8\81\05\b0\bf4\f7\bc\10\1c\fb\cc<\f1\85\97B\9f\eb\14\8d<\bf\d7\17\88I\9d\8b+\b2:\83\d1O\04\9e\a1\0f\ad\08\9dT\af\d1\82\c3\ec2/\02\8f\05!-\a2\b7\e4\f4o.\81+\0b\9c\fc\cb\fet\02\f9\db\f4\f3\ea\00\a8\ec\d1\99t&\dd\d64\d5%\b1F\dd\9c\aaq\f5`\b0\88\c8\e0\0bYZ%O)f\f9\e3.\fe\e9\da\e5\18O'b\f4\ce\a4!\95t\c7Wd'\9aL\fdT}a\ce\c3\ac\87F\9c\fa\ff\09\cay\97g$t\ca\d4!\83&%\19\127d\19\e5e\e0tu\8e\dd\c8\eft\c7\d8!+y\04QFe`\03]\fa\d8\f4e\a4\9e]#\da\d7\8a\92\80\a4\dex<\f1WBm\cd\c9/\d5\a4\9e\ab@\f4\cb\1b\d7\a3\ca\fc\eb\a7\01\b2\9aiNF\9b\18N\ddy\a7\aa\a6R9\1e\ef0\cc\9b\bd[\eeL!m0\00r\b0F_\08\cf\c5\b9\e0>\c2\b3\0c\dc\8ed\de\19By\cfC\eaC]\8e\88\f7\ab\15\dc?\c8g \db\b8d\b1G\1f\de\f2\cb?Y\9f\d8F\90\dc\ae/\22\f9\e21\89\d9\9c\1cL\d3\a9JW\84\9c\9f\ea,<\ae<\c3\1e\8b\e5N\17\01%\db4F_\15\ea\05\0c|\d9E\8c\19\d0s\8a\96\16\ddD\f9\05\b7[q\b0\e6!6_u\89\91su\ab}\ae\d3s\ec7\c6\eaUu\ef\ea\ab\8b{\11\dcm\1a\b2j\c4%\cf\aa\e3\9fII\89\cb7\9b\0a\a7\01`p\dc\b7\c8\83\e1B\f5\be\adb\94\ad\8d\a1") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/629.print b/tests/snapshots/testsuite/float_exprs.wast/629.print new file mode 100644 index 0000000000..a91838c9de --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/629.print @@ -0,0 +1,62 @@ +(module + (type (;0;) (func (param i32 i32) (result f64))) + (func (;0;) (type 0) (param $p i32) (param $n i32) (result f64) + (local $sum f64) (local $c f64) (local $t f64) + block $exit ;; label = @1 + loop $top ;; label = @2 + local.get $c + local.get $p + f64.load + local.get $t + f64.sub + local.tee $t + f64.add + local.tee $sum + local.get $c + f64.sub + local.get $t + f64.sub + local.set $t + local.get $p + i32.const 8 + i32.add + local.set $p + local.get $sum + local.set $c + local.get $n + i32.const -1 + i32.add + local.tee $n + br_if 0 (;@2;) + end + end + local.get $sum + ) + (func (;1;) (type 0) (param $p i32) (param $n i32) (result f64) + (local $sum f64) + block $exit ;; label = @1 + loop $top ;; label = @2 + local.get $sum + local.get $p + f64.load + f64.add + local.set $sum + local.get $p + i32.const 8 + i32.add + local.set $p + local.get $n + i32.const -1 + i32.add + local.set $n + local.get $n + br_if 0 (;@2;) + end + end + local.get $sum + ) + (memory (;0;) 1 1) + (export "f64.kahan_sum" (func 0)) + (export "f64.plain_sum" (func 1)) + (data (;0;) (i32.const 0) "\13\05\84B]\a2,\c6C\dbU\a9\cd\daU\e3s\fcX\d6\ba\d5\00\fd\835B\88\8b\13]8JG\0drs\a1\1a\ef\c4E\17W\d8\c9F\e0\8dl\e17p\c8\83[U^Z-s\1eV\c8\e1mi\14x\0a\8aZd:\09\c7\a8\87\c5\f0\d3]\e6\03\fc\93\be&\ca\d6\a9\91`\bd\b0\ed\ae\f70~\92:o\a7Y\8e\aa}\bfgX*T\f8N\fe\ed5X\a6Q\bfB\e5Kf'$m\7fB-(\92\18\ec\08\ae\e7U\da\b1\a6e\a5rPG\1b\b8\a9T\d7\a6\06[\0fBX\83\8a\17\82\c6\10C\a0\c0.m\bcZ\85Sr\7f\adD\bc0I\f2~H\f4\a2q\d0\13\8e\b3\de\99R\e3Et\eav\0e\1b*\c8\ee\14\01\c4P[6<\ef\bar\a2\a6\08\f8{6\9d\f9\ef\0b\c7V-\5c\f0\9d]\de\fc\b8\ad\0fd\0e\97\152&\c21\e6\05\1e\ef\cb\17\1bm\15\0bt]\d3.\f8k\86\b4\basRS\99\a9v E\c9@\80k\14\ed\a1\fa\80F\e6&\d2\e6\98\c4W\bf\c4\1c\a4\90z6\94\14\ba\15\89n\e6\9c7\8c\f4\de\12\22]\a1yPg\0d=z\e9\d4\aa.\7f*z0=\ea]\12H\fe\e1\18\cd\a4W\a2\87>\b6\9a\8b\db\da\9dx\9c\cf\8d\b1O\90\b44\e0\9d\f6\ca\feL;xm\0a\5c\18\9fa\b9\dd\b4\e0\0fv\e0\1bi\0d^Xsp^\0e-\a1}\ff \eb\914\92\ac8r*\1f\8eq.j\f1\af\c7'p\d9\c4W\f7\d2<\1d\b8\f0\f0d\cf\dc\ae\be\a3\cc>\22}Ni!c\17\ed\03\02T\9a\0fPN\13Z5\a1\22\a4\df\86\c2ty\16\b8ii\a0R]\11d\bd[\93\fci\a0\f4\13\d0\81Q\dd\fa\0c\15\c3z\c9bz\a9\1d\c9\e6Z\b3[\97\02\d0\c4\8d4\19P!\0a\bcP\da<0\d6:1\94\8d:\fe\ef\14W\9dK\93\00\96$\0co\fd\bc#v\02l\ebRr\80\11~\80:\13\128\1d8I\95@'\8aD{\e8\dcm\8c\8c\8e<\b5\b3\18\0e\f6\08\1a\84A5\ff\8b\b8\93@\ea\e1Q\1d\89\a5\8dBh)\ea/\c1zR\eb\90]M\d6\80\e3\d7uH\ce\ed\d3\01\1c\8d[\a5\94\0dx\cf\f1\06\13/\98\02\a4m.l\f2\d5t)\89L\f9\03\f5\c7\18\adz\f0h\f8\5c\d6Y\87n\d6?\06\be\86 \e3A\91\22\f3n\8b\f0h\1cW\a7\fc\b0|\9e\99\0b\96\1a\89_\e6\0d|\08Q\a0\a2g\9aG\00\93k\f9(\f0h\dbb\f1\e0e,S3\e0\a7\ca\11B0\f6\af\01\c1e=2\01o\ab.\be\d3\8b\be\14\c3\ff\ec\fb\f0\f9\c5\0c\05o\01\09k\e341\0c\1ff\a6B\bc\1a\87I\16\16\8c\b0\90\0d4\8c\0a\e1\09^\10\a4kV\cc\f0\c9\bb\dc\b8\5c\ce\f6\cc\8du~\b3\07\88\04/\b4^\c9\e3J#s\19bl\9a\03vD\86\9c`\fc\dbr\8f'\a0\dd\b3\c5\da\ff\f9\ecj\b1{\d3\cfP7\c9zx\0c\e4:\b6\f5\e6\f4\98nB}5s\8bE\c0V\97\cdm\ce\cf\ad1\b3\c3T\fa\ef\d5\c0\f4j_T\e7I>3\0a08\fd\d9\05\ff\a5?WF\14\b5\91\17\cak\98#ze\b3l\02\b4\ccy]X\d8\b3\d5\94\ae\f4mue\f7\92\bf~GL<\ee\db\ac\f12]\fboA\1c4\c8\83O\c2X\01\be\05>f\16\a6\04m]O\86\09'\82%\12\cd:\cd\cek\bc\ca\ac(\9b\eej%\86\9eEp\c6\d2\bd;}B\e5'\af\c7\1d\f4\81\c8\b3v\8a\a86\a3\ae*\e6\18\e16\22\ad\f6%r\b09\8b\01\9a\22{\84\c3-_r\a4\98\ac\15p\e7\d4\18\e2}\d20|3\08\cd\ca\c4\22\85\88u\81\c6JtX\8d\e0\e8\ac\c5\abuZ\f4(\12\f0\18ER\f2\97\b2\93Ao\8d\7f\dbp\fb\a3]\1f\a7\8d\98 +\22\9f:\01\b5\8b\1b\d2\cb\14\03\0e\14\14\d2\19Z\1f\ce^\cd\81y\15\01\ca\dest\8cV \9fw-%\16\f6aQ\1d\a4\8e\9b\98\a5\c6\ec\a8EW\82Yx\0d\90\b4\dfQ\b0\c3\82\94\cc\b3S\09\15m\96l:@G\b7Jz\05/\a1\1e\8c\9d\a0 \88\fbR\b7\9f\f3\f3\bb_\e7\8aa\a7!\b1\ac\fa\09\aa\a4l\bc$\80\ba*\e9e\ffp\ff\cc\fae\87v\f3\c5\15\ce\cb\e8B1\00\0c\91W\d9\e0\9d5T$\ad\a4\d8\f9\08gc\c8\cf\81\dd\90\a2\d7\c4\07J\e6\10og\e7'\d4#Y\18\f2\a8\9d_\d8\940\aaT\86O\87\9d\82\b5&\ca\a6\96\bf\cfU\f9\9d7\01\19HC\c5\94l\f3t\97XL<\9d\08\e8\04\c2X0v\e1\a0\f8\ea\e9\c5\ae\cfx\9e\a9\0c\ac\b3DB\e0\bc]\1b\9cIXJ\1c\19I\c1:\ea\f5\eb;\81\a9Kp\0c\cc\9e\1a\d3/\b7R/ ;\ebdQ\1d\a0-\b2>\be\13\85H\922.\db\5c\a1\e7\8cE\915\01\0a\93\c2\eb\09\ce\f3\d2\22$\d0\8c\cc\1d\9d8\c8M\e3\82\ccd\15\06-\e7\01/\ab\bb\b5\04L\92\1cz\d6?\e8_1\15\0c\dc\e41\b4\c4%>*\aa\00\9e\c8\e5!z\7f)\f1\c0\af\1d^\e8c9\ad\f8~l\c8\c5\7f\c2\a8\97'\0a\d9\f4!j\ea\03\09\fb\f7\96;\83y_|K0\9fV5\de\b4s\d4\95\f0\14\c3t/\0d\a3\1dN\8d1$\b3\1a\84\85bZ{<\149\17\e6m\eb7\c2\00X[\0b\e3<\8ab\e1\f85KV\e2\87`\8b\be\a78\91wT\a9Z$%\90\9f\a5Bw\f3\5c9\df\fft\07v\a1\cd\1fb\0b\81\81h\af\05\c1\c0\7f&\ee\c0\91\a3j})aE'\e5W\88\dc\0d\97\04\1a3\a9D\8a\da\02\10E?\8eU\a6v\8cM\e3\f1\89\83\c8\d0\f8\9bPw\9fG\dfL\9cf\0d\aa\18\b8_O\c4\01\ce\dc\84\acF\9ei\e1vEka\89\e4]\94\bb\11\83\9fx\d8\0a\d2\f5~]C\ea\bc\10\f1:\c9\e2d\fbSe\d0\c7\b4\a7\fb\d4\05S%\d0\cd)\88\00V%$}]\b4\f3A\9f\e9\b5\f7\aed,\e3\c9m\d5\84:r\12\b8z\d9\1b\09\e88\da&O\04\ce\03qn\8aD{\5c\81Y\9c\d2\e4\c3\baY\a6\e5(\a7\8f\9a\e4\d5N\b9\ca\7f\cbu\b8+C>\b3\15F\b1\a5\bc\9d\9e8\15\f1\bd\1b!\aa\f1\82\00\95\fc\a7wG9\a73C\92\d7R@K\06\81\8a\a0\bd\f1k\99\84B[\e2;\c5^\12\5c(M\b6\0eN\c8\5c\e8\01\8a\c5\e7\e4\9dB\ee]\9c\c4\eb\ebh\09'\92\95\9a\11Ts\c4\12\80\fb}\fe\c5\08`\7f6A\e0\10\ba\d6+l\f1\b4\17\fe&4\e3K\f8\a8\e3\91\beO*\fc\da\81\b8\e7\fe\d5&PG\f3\1ae2\81\e0\05\b8O21&\00JS\97\c2\c3\0e.\a1&T\ab\05\8eV/}\af\22\84h\a5\8b\97\f6\a4\fd\a8\ccuA\96\86\fd'=)\86\8d\7fL\d4\8esA\f4\1e\e2\ddX'\97\ce\9c\94\cfz\04/\dc\ed") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/63.print b/tests/snapshots/testsuite/float_exprs.wast/63.print new file mode 100644 index 0000000000..13e8ff027c --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/63.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result i32))) + (type (;1;) (func (param f64) (result i32))) + (func (;0;) (type 0) (param $x f32) (result i32) + local.get $x + local.get $x + f32.eq + ) + (func (;1;) (type 1) (param $x f64) (result i32) + local.get $x + local.get $x + f64.eq + ) + (export "f32.no_fold_eq_self" (func 0)) + (export "f64.no_fold_eq_self" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/632.print b/tests/snapshots/testsuite/float_exprs.wast/632.print new file mode 100644 index 0000000000..43f2b386b6 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/632.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.sub + f32.neg + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.sub + f64.neg + ) + (export "f32.no_fold_neg_sub" (func 0)) + (export "f64.no_fold_neg_sub" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/641.print b/tests/snapshots/testsuite/float_exprs.wast/641.print new file mode 100644 index 0000000000..d8cfa769ee --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/641.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.add + f32.neg + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.add + f64.neg + ) + (export "f32.no_fold_neg_add" (func 0)) + (export "f64.no_fold_neg_add" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/650.print b/tests/snapshots/testsuite/float_exprs.wast/650.print new file mode 100644 index 0000000000..62aa138297 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/650.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + f32.neg + local.get $y + f32.neg + f32.add + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + f64.neg + local.get $y + f64.neg + f64.add + ) + (export "f32.no_fold_add_neg_neg" (func 0)) + (export "f64.no_fold_add_neg_neg" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/659.print b/tests/snapshots/testsuite/float_exprs.wast/659.print new file mode 100644 index 0000000000..b709de52de --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/659.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.neg + local.get $x + f32.add + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.neg + local.get $x + f64.add + ) + (export "f32.no_fold_add_neg" (func 0)) + (export "f64.no_fold_add_neg" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/66.print b/tests/snapshots/testsuite/float_exprs.wast/66.print new file mode 100644 index 0000000000..581fb01e19 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/66.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result i32))) + (type (;1;) (func (param f64) (result i32))) + (func (;0;) (type 0) (param $x f32) (result i32) + local.get $x + local.get $x + f32.ne + ) + (func (;1;) (type 1) (param $x f64) (result i32) + local.get $x + local.get $x + f64.ne + ) + (export "f32.no_fold_ne_self" (func 0)) + (export "f64.no_fold_ne_self" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/668.print b/tests/snapshots/testsuite/float_exprs.wast/668.print new file mode 100644 index 0000000000..5e23b25d80 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/668.print @@ -0,0 +1,32 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + local.get $x + f32.add + local.get $x + f32.add + local.get $x + f32.add + local.get $x + f32.add + local.get $x + f32.add + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + local.get $x + f64.add + local.get $x + f64.add + local.get $x + f64.add + local.get $x + f64.add + local.get $x + f64.add + ) + (export "f32.no_fold_6x_via_add" (func 0)) + (export "f64.no_fold_6x_via_add" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/679.print b/tests/snapshots/testsuite/float_exprs.wast/679.print new file mode 100644 index 0000000000..7bcbf544df --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/679.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result f32) + local.get $x + local.get $y + f32.div + local.get $z + f32.div + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $y + f64.div + local.get $z + f64.div + ) + (export "f32.no_fold_div_div" (func 0)) + (export "f64.no_fold_div_div" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/69.print b/tests/snapshots/testsuite/float_exprs.wast/69.print new file mode 100644 index 0000000000..a88e2c0aa3 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/69.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + local.get $x + f32.sub + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + local.get $x + f64.sub + ) + (export "f32.no_fold_sub_self" (func 0)) + (export "f64.no_fold_sub_self" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/690.print b/tests/snapshots/testsuite/float_exprs.wast/690.print new file mode 100644 index 0000000000..dd762f4383 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/690.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32 f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32) + local.get $x + local.get $y + f32.div + local.get $z + local.get $w + f32.div + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64) + local.get $x + local.get $y + f64.div + local.get $z + local.get $w + f64.div + f64.mul + ) + (export "f32.no_fold_mul_divs" (func 0)) + (export "f64.no_fold_mul_divs" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/701.print b/tests/snapshots/testsuite/float_exprs.wast/701.print new file mode 100644 index 0000000000..79dd20ee49 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/701.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result f32) + local.get $x + local.get $z + f32.div + local.get $y + local.get $z + f32.div + f32.add + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $z + f64.div + local.get $y + local.get $z + f64.div + f64.add + ) + (export "f32.no_fold_add_divs" (func 0)) + (export "f64.no_fold_add_divs" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/712.print b/tests/snapshots/testsuite/float_exprs.wast/712.print new file mode 100644 index 0000000000..dbc7785872 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/712.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + local.get $x + f32.mul + f32.sqrt + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + local.get $x + f64.mul + f64.sqrt + ) + (export "f32.no_fold_sqrt_square" (func 0)) + (export "f64.no_fold_sqrt_square" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/723.print b/tests/snapshots/testsuite/float_exprs.wast/723.print new file mode 100644 index 0000000000..58c1ed1de5 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/723.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + f32.sqrt + local.get $y + f32.sqrt + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + f64.sqrt + local.get $y + f64.sqrt + f64.mul + ) + (export "f32.no_fold_mul_sqrts" (func 0)) + (export "f64.no_fold_mul_sqrts" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/734.print b/tests/snapshots/testsuite/float_exprs.wast/734.print new file mode 100644 index 0000000000..5d87b6b7ec --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/734.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + f32.sqrt + local.get $y + f32.sqrt + f32.div + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + f64.sqrt + local.get $y + f64.sqrt + f64.div + ) + (export "f32.no_fold_div_sqrts" (func 0)) + (export "f64.no_fold_div_sqrts" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/74.print b/tests/snapshots/testsuite/float_exprs.wast/74.print new file mode 100644 index 0000000000..2a66466029 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/74.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + local.get $x + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + local.get $x + f64.div + ) + (export "f32.no_fold_div_self" (func 0)) + (export "f64.no_fold_div_self" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/745.print b/tests/snapshots/testsuite/float_exprs.wast/745.print new file mode 100644 index 0000000000..a1a216a80c --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/745.print @@ -0,0 +1,22 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.sqrt + f32.mul + local.get $y + f32.div + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.sqrt + f64.mul + local.get $y + f64.div + ) + (export "f32.no_fold_mul_sqrt_div" (func 0)) + (export "f64.no_fold_mul_sqrt_div" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/756.print b/tests/snapshots/testsuite/float_exprs.wast/756.print new file mode 100644 index 0000000000..1c50a1cdf1 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/756.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result f32) + local.get $x + local.get $y + f32.mul + local.get $z + f32.mul + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $y + f64.mul + local.get $z + f64.mul + ) + (export "f32.no_flush_intermediate_subnormal" (func 0)) + (export "f64.no_flush_intermediate_subnormal" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/759.print b/tests/snapshots/testsuite/float_exprs.wast/759.print new file mode 100644 index 0000000000..cfb9b56674 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/759.print @@ -0,0 +1,60 @@ +(module + (type (;0;) (func (param f32 f32) (result i32))) + (type (;1;) (func (param f64 f64) (result i32))) + (type (;2;) (func (param f64 f32) (result f32))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.mul + local.get $x + f32.eq + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.mul + local.get $x + f32.le + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.mul + local.get $x + f32.lt + ) + (func (;3;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.mul + local.get $x + f64.eq + ) + (func (;4;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.mul + local.get $x + f64.le + ) + (func (;5;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.mul + local.get $x + f64.lt + ) + (func (;6;) (type 2) (param $x f64) (param $y f32) (result f32) + local.get $x + f32.demote_f64 + local.get $y + f32.mul + ) + (export "f32.recoding_eq" (func 0)) + (export "f32.recoding_le" (func 1)) + (export "f32.recoding_lt" (func 2)) + (export "f64.recoding_eq" (func 3)) + (export "f64.recoding_le" (func 4)) + (export "f64.recoding_lt" (func 5)) + (export "recoding_demote" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/773.print b/tests/snapshots/testsuite/float_exprs.wast/773.print new file mode 100644 index 0000000000..dd288df167 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/773.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result i32))) + (type (;1;) (func (param f64 f64 f64) (result i32))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result i32) + local.get $x + local.get $y + f32.div + local.get $z + f32.eq + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result i32) + local.get $x + local.get $y + f64.div + local.get $z + f64.eq + ) + (export "f32.no_extended_precision_div" (func 0)) + (export "f64.no_extended_precision_div" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/776.print b/tests/snapshots/testsuite/float_exprs.wast/776.print new file mode 100644 index 0000000000..15cd193b63 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/776.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + f32.const -0x1p+3 (;=-8;) + local.get $x + f32.mul + f32.const 0x1p+3 (;=8;) + local.get $x + f32.mul + f32.add + ) + (func (;1;) (type 1) (param $x f64) (result f64) + f64.const -0x1p+3 (;=-8;) + local.get $x + f64.mul + f64.const 0x1p+3 (;=8;) + local.get $x + f64.mul + f64.add + ) + (export "f32.no_distribute_exact" (func 0)) + (export "f64.no_distribute_exact" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/779.print b/tests/snapshots/testsuite/float_exprs.wast/779.print new file mode 100644 index 0000000000..16723c4069 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/779.print @@ -0,0 +1,106 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f32 f32 f32 f32) (result f32))) + (type (;2;) (func (param f32 f32 f32) (result f32))) + (type (;3;) (func (param f64) (result f64))) + (type (;4;) (func (param f64 f64 f64 f64) (result f64))) + (type (;5;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param f32) (result f32) + local.get 0 + f32.sqrt + ) + (func (;1;) (type 1) (param f32 f32 f32 f32) (result f32) + local.get 0 + local.get 1 + f32.div + local.get 2 + local.get 3 + local.get 2 + f32.sub + f32.div + f32.add + ) + (func (;2;) (type 2) (param f32 f32 f32) (result f32) + local.get 0 + local.get 1 + f32.mul + local.get 2 + f32.div + ) + (func (;3;) (type 2) (param f32 f32 f32) (result f32) + local.get 0 + local.get 1 + f32.div + local.get 2 + local.get 0 + f32.div + f32.add + ) + (func (;4;) (type 1) (param f32 f32 f32 f32) (result f32) + local.get 0 + local.get 1 + local.get 2 + f32.mul + f32.add + local.get 3 + local.get 1 + local.get 2 + f32.mul + f32.sub + f32.div + ) + (func (;5;) (type 3) (param f64) (result f64) + local.get 0 + f64.sqrt + ) + (func (;6;) (type 4) (param f64 f64 f64 f64) (result f64) + local.get 0 + local.get 1 + f64.div + local.get 2 + local.get 3 + local.get 2 + f64.sub + f64.div + f64.add + ) + (func (;7;) (type 5) (param f64 f64 f64) (result f64) + local.get 0 + local.get 1 + f64.mul + local.get 2 + f64.div + ) + (func (;8;) (type 5) (param f64 f64 f64) (result f64) + local.get 0 + local.get 1 + f64.div + local.get 2 + local.get 0 + f64.div + f64.add + ) + (func (;9;) (type 4) (param f64 f64 f64 f64) (result f64) + local.get 0 + local.get 1 + local.get 2 + f64.mul + f64.add + local.get 3 + local.get 1 + local.get 2 + f64.mul + f64.sub + f64.div + ) + (export "f32.sqrt" (func 0)) + (export "f32.xkcd_sqrt_2" (func 1)) + (export "f32.xkcd_sqrt_3" (func 2)) + (export "f32.xkcd_sqrt_5" (func 3)) + (export "f32.xkcd_better_sqrt_5" (func 4)) + (export "f64.sqrt" (func 5)) + (export "f64.xkcd_sqrt_2" (func 6)) + (export "f64.xkcd_sqrt_3" (func 7)) + (export "f64.xkcd_sqrt_5" (func 8)) + (export "f64.xkcd_better_sqrt_5" (func 9)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/794.print b/tests/snapshots/testsuite/float_exprs.wast/794.print new file mode 100644 index 0000000000..6a698e3cb9 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/794.print @@ -0,0 +1,72 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $0 f32) (param $1 f32) (result f32) + loop $label$0 ;; label = @1 + local.get $0 + local.get $0 + f32.add + local.tee $0 + f32.const 0x1p+0 (;=1;) + f32.add + local.get $0 + f32.sub + f32.const -0x1p+0 (;=-1;) + f32.add + f32.const 0x0p+0 (;=0;) + f32.eq + br_if 0 (;@1;) + end + loop $label$2 ;; label = @1 + local.get $0 + local.get $1 + f32.const 0x1p+0 (;=1;) + f32.add + local.tee $1 + f32.add + local.get $0 + f32.sub + local.get $1 + f32.sub + f32.const 0x0p+0 (;=0;) + f32.ne + br_if 0 (;@1;) + end + local.get $1 + ) + (func (;1;) (type 1) (param $0 f64) (param $1 f64) (result f64) + loop $label$0 ;; label = @1 + local.get $0 + local.get $0 + f64.add + local.tee $0 + f64.const 0x1p+0 (;=1;) + f64.add + local.get $0 + f64.sub + f64.const -0x1p+0 (;=-1;) + f64.add + f64.const 0x0p+0 (;=0;) + f64.eq + br_if 0 (;@1;) + end + loop $label$2 ;; label = @1 + local.get $0 + local.get $1 + f64.const 0x1p+0 (;=1;) + f64.add + local.tee $1 + f64.add + local.get $0 + f64.sub + local.get $1 + f64.sub + f64.const 0x0p+0 (;=0;) + f64.ne + br_if 0 (;@1;) + end + local.get $1 + ) + (export "f32.compute_radix" (func 0)) + (export "f64.compute_radix" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/797.print b/tests/snapshots/testsuite/float_exprs.wast/797.print new file mode 100644 index 0000000000..143e8ed27b --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/797.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + f32.const 0x1p+0 (;=1;) + f32.sub + local.get $y + f32.mul + local.get $y + f32.add + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + f64.const 0x1p+0 (;=1;) + f64.sub + local.get $y + f64.mul + local.get $y + f64.add + ) + (export "f32.no_fold_sub1_mul_add" (func 0)) + (export "f64.no_fold_sub1_mul_add" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/800.print b/tests/snapshots/testsuite/float_exprs.wast/800.print new file mode 100644 index 0000000000..b382dcf0d6 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/800.print @@ -0,0 +1,44 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result i32))) + (type (;1;) (func (param f64 f64 f64) (result i32))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result i32) + local.get $x + local.get $z + f32.add + local.get $y + local.get $z + f32.add + f32.le + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result i32) + local.get $x + local.get $z + f32.add + local.get $y + local.get $z + f32.add + f32.ge + ) + (func (;2;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result i32) + local.get $x + local.get $z + f64.add + local.get $y + local.get $z + f64.add + f64.le + ) + (func (;3;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result i32) + local.get $x + local.get $z + f64.add + local.get $y + local.get $z + f64.add + f64.ge + ) + (export "f32.no_fold_add_le_monotonicity" (func 0)) + (export "f32.no_fold_add_ge_monotonicity" (func 1)) + (export "f64.no_fold_add_le_monotonicity" (func 2)) + (export "f64.no_fold_add_ge_monotonicity" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/805.print b/tests/snapshots/testsuite/float_exprs.wast/805.print new file mode 100644 index 0000000000..dcc1561249 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/805.print @@ -0,0 +1,60 @@ +(module + (type (;0;) (func (param f32 f32) (result i32))) + (type (;1;) (func (param f64 f64) (result i32))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.lt + i32.eqz + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.le + i32.eqz + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.gt + i32.eqz + ) + (func (;3;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.ge + i32.eqz + ) + (func (;4;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.lt + i32.eqz + ) + (func (;5;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.le + i32.eqz + ) + (func (;6;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.gt + i32.eqz + ) + (func (;7;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.ge + i32.eqz + ) + (export "f32.not_lt" (func 0)) + (export "f32.not_le" (func 1)) + (export "f32.not_gt" (func 2)) + (export "f32.not_ge" (func 3)) + (export "f64.not_lt" (func 4)) + (export "f64.not_le" (func 5)) + (export "f64.not_gt" (func 6)) + (export "f64.not_ge" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/814.print b/tests/snapshots/testsuite/float_exprs.wast/814.print new file mode 100644 index 0000000000..4a19e8a78d --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/814.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result f64))) + (func (;0;) (type 0) (result f32) + f32.const 0x1p+0 (;=1;) + f32.const 0x1.8p+1 (;=3;) + f32.const 0x1p+2 (;=4;) + f32.const 0x1.8p+1 (;=3;) + f32.div + f32.const 0x1p+0 (;=1;) + f32.sub + f32.mul + f32.sub + ) + (func (;1;) (type 1) (result f64) + f64.const 0x1p+0 (;=1;) + f64.const 0x1.8p+1 (;=3;) + f64.const 0x1p+2 (;=4;) + f64.const 0x1.8p+1 (;=3;) + f64.div + f64.const 0x1p+0 (;=1;) + f64.sub + f64.mul + f64.sub + ) + (export "f32.epsilon" (func 0)) + (export "f64.epsilon" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/817.print b/tests/snapshots/testsuite/float_exprs.wast/817.print new file mode 100644 index 0000000000..1d2426bf12 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/817.print @@ -0,0 +1,42 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result f64))) + (func (;0;) (type 0) (result f32) + (local $x f32) (local $result f32) + f32.const 0x1p+0 (;=1;) + local.set $x + loop $loop ;; label = @1 + local.get $x + local.tee $result + f32.const 0x1p-1 (;=0.5;) + f32.mul + local.tee $x + f32.const 0x1p+0 (;=1;) + f32.add + f32.const 0x1p+0 (;=1;) + f32.gt + br_if 0 (;@1;) + end + local.get $result + ) + (func (;1;) (type 1) (result f64) + (local $x f64) (local $result f64) + f64.const 0x1p+0 (;=1;) + local.set $x + loop $loop ;; label = @1 + local.get $x + local.tee $result + f64.const 0x1p-1 (;=0.5;) + f64.mul + local.tee $x + f64.const 0x1p+0 (;=1;) + f64.add + f64.const 0x1p+0 (;=1;) + f64.gt + br_if 0 (;@1;) + end + local.get $result + ) + (export "f32.epsilon" (func 0)) + (export "f64.epsilon" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/820.print b/tests/snapshots/testsuite/float_exprs.wast/820.print new file mode 100644 index 0000000000..e0dfb6f5a9 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/820.print @@ -0,0 +1,84 @@ +(module + (type (;0;) (func (param f32 f32) (result i32))) + (type (;1;) (func (param f64 f64) (result i32))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.lt + local.get $x + local.get $y + f32.ge + i32.or + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.le + local.get $x + local.get $y + f32.gt + i32.or + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.gt + local.get $x + local.get $y + f32.le + i32.or + ) + (func (;3;) (type 0) (param $x f32) (param $y f32) (result i32) + local.get $x + local.get $y + f32.ge + local.get $x + local.get $y + f32.lt + i32.or + ) + (func (;4;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.lt + local.get $x + local.get $y + f64.ge + i32.or + ) + (func (;5;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.le + local.get $x + local.get $y + f64.gt + i32.or + ) + (func (;6;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.gt + local.get $x + local.get $y + f64.le + i32.or + ) + (func (;7;) (type 1) (param $x f64) (param $y f64) (result i32) + local.get $x + local.get $y + f64.ge + local.get $x + local.get $y + f64.lt + i32.or + ) + (export "f32.no_trichotomy_lt" (func 0)) + (export "f32.no_trichotomy_le" (func 1)) + (export "f32.no_trichotomy_gt" (func 2)) + (export "f32.no_trichotomy_ge" (func 3)) + (export "f64.no_trichotomy_lt" (func 4)) + (export "f64.no_trichotomy_le" (func 5)) + (export "f64.no_trichotomy_gt" (func 6)) + (export "f64.no_trichotomy_ge" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/829.print b/tests/snapshots/testsuite/float_exprs.wast/829.print new file mode 100644 index 0000000000..ee23288de7 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/829.print @@ -0,0 +1,194 @@ +(module + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i64 i64) (result i64))) + (type (;3;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + f32.reinterpret_i32 + local.get $y + f32.reinterpret_i32 + f32.div + i32.reinterpret_f32 + i32.const 2143289344 + i32.and + ) + (func (;1;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + f32.reinterpret_i32 + local.get $y + f32.reinterpret_i32 + f32.div + i32.reinterpret_f32 + i32.const 2147483647 + i32.and + ) + (func (;2;) (type 1) (param $x i32) (result i32) + local.get $x + f32.reinterpret_i32 + f32.neg + i32.reinterpret_f32 + ) + (func (;3;) (type 2) (param $x i64) (param $y i64) (result i64) + local.get $x + f64.reinterpret_i64 + local.get $y + f64.reinterpret_i64 + f64.div + i64.reinterpret_f64 + i64.const 9221120237041090560 + i64.and + ) + (func (;4;) (type 2) (param $x i64) (param $y i64) (result i64) + local.get $x + f64.reinterpret_i64 + local.get $y + f64.reinterpret_i64 + f64.div + i64.reinterpret_f64 + i64.const 9223372036854775807 + i64.and + ) + (func (;5;) (type 3) (param $x i64) (result i64) + local.get $x + f64.reinterpret_i64 + f64.neg + i64.reinterpret_f64 + ) + (func (;6;) (type 1) (param $x i32) (result i32) + local.get $x + f32.reinterpret_i32 + f32.const 0x0p+0 (;=0;) + f32.sub + i32.reinterpret_f32 + i32.const 2143289344 + i32.and + ) + (func (;7;) (type 1) (param $x i32) (result i32) + f32.const -0x0p+0 (;=-0;) + local.get $x + f32.reinterpret_i32 + f32.sub + i32.reinterpret_f32 + i32.const 2143289344 + i32.and + ) + (func (;8;) (type 1) (param $x i32) (result i32) + local.get $x + f32.reinterpret_i32 + f32.const 0x1p+0 (;=1;) + f32.mul + i32.reinterpret_f32 + i32.const 2143289344 + i32.and + ) + (func (;9;) (type 1) (param $x i32) (result i32) + f32.const -0x1p+0 (;=-1;) + local.get $x + f32.reinterpret_i32 + f32.mul + i32.reinterpret_f32 + i32.const 2143289344 + i32.and + ) + (func (;10;) (type 1) (param $x i32) (result i32) + local.get $x + f32.reinterpret_i32 + f32.const 0x1p+0 (;=1;) + f32.div + i32.reinterpret_f32 + i32.const 2143289344 + i32.and + ) + (func (;11;) (type 1) (param $x i32) (result i32) + local.get $x + f32.reinterpret_i32 + f32.const -0x1p+0 (;=-1;) + f32.div + i32.reinterpret_f32 + i32.const 2143289344 + i32.and + ) + (func (;12;) (type 3) (param $x i64) (result i64) + local.get $x + f64.reinterpret_i64 + f64.const 0x0p+0 (;=0;) + f64.sub + i64.reinterpret_f64 + i64.const 9221120237041090560 + i64.and + ) + (func (;13;) (type 3) (param $x i64) (result i64) + f64.const -0x0p+0 (;=-0;) + local.get $x + f64.reinterpret_i64 + f64.sub + i64.reinterpret_f64 + i64.const 9221120237041090560 + i64.and + ) + (func (;14;) (type 3) (param $x i64) (result i64) + local.get $x + f64.reinterpret_i64 + f64.const 0x1p+0 (;=1;) + f64.mul + i64.reinterpret_f64 + i64.const 9221120237041090560 + i64.and + ) + (func (;15;) (type 3) (param $x i64) (result i64) + f64.const -0x1p+0 (;=-1;) + local.get $x + f64.reinterpret_i64 + f64.mul + i64.reinterpret_f64 + i64.const 9221120237041090560 + i64.and + ) + (func (;16;) (type 3) (param $x i64) (result i64) + local.get $x + f64.reinterpret_i64 + f64.const 0x1p+0 (;=1;) + f64.div + i64.reinterpret_f64 + i64.const 9221120237041090560 + i64.and + ) + (func (;17;) (type 3) (param $x i64) (result i64) + local.get $x + f64.reinterpret_i64 + f64.const -0x1p+0 (;=-1;) + f64.div + i64.reinterpret_f64 + i64.const 9221120237041090560 + i64.and + ) + (func (;18;) (type 1) (param $x i32) (result i32) + local.get $x + f32.reinterpret_i32 + f64.promote_f32 + f32.demote_f64 + i32.reinterpret_f32 + i32.const 2143289344 + i32.and + ) + (export "f32.arithmetic_nan_bitpattern" (func 0)) + (export "f32.canonical_nan_bitpattern" (func 1)) + (export "f32.nonarithmetic_nan_bitpattern" (func 2)) + (export "f64.arithmetic_nan_bitpattern" (func 3)) + (export "f64.canonical_nan_bitpattern" (func 4)) + (export "f64.nonarithmetic_nan_bitpattern" (func 5)) + (export "f32.no_fold_sub_zero" (func 6)) + (export "f32.no_fold_neg0_sub" (func 7)) + (export "f32.no_fold_mul_one" (func 8)) + (export "f32.no_fold_neg1_mul" (func 9)) + (export "f32.no_fold_div_one" (func 10)) + (export "f32.no_fold_div_neg1" (func 11)) + (export "f64.no_fold_sub_zero" (func 12)) + (export "f64.no_fold_neg0_sub" (func 13)) + (export "f64.no_fold_mul_one" (func 14)) + (export "f64.no_fold_neg1_mul" (func 15)) + (export "f64.no_fold_div_one" (func 16)) + (export "f64.no_fold_div_neg1" (func 17)) + (export "no_fold_promote_demote" (func 18)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/83.print b/tests/snapshots/testsuite/float_exprs.wast/83.print new file mode 100644 index 0000000000..10258fb07f --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/83.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (result f32) + local.get $x + f32.const 0x1.8p+1 (;=3;) + f32.div + ) + (func (;1;) (type 1) (param $x f64) (result f64) + local.get $x + f64.const 0x1.8p+1 (;=3;) + f64.div + ) + (export "f32.no_fold_div_3" (func 0)) + (export "f64.no_fold_div_3" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/863.print b/tests/snapshots/testsuite/float_exprs.wast/863.print new file mode 100644 index 0000000000..7e9ac5f28b --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/863.print @@ -0,0 +1,39 @@ +(module + (type (;0;) (func (param f64 f64 f64 f64 f64 f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x0 f64) (param $x1 f64) (param $x2 f64) (param $x3 f64) (param $y0 f64) (param $y1 f64) (param $y2 f64) (param $y3 f64) (result f64) + local.get $x0 + local.get $y0 + f64.mul + local.get $x1 + local.get $y1 + f64.mul + f64.add + local.get $x2 + local.get $y2 + f64.mul + f64.add + local.get $x3 + local.get $y3 + f64.mul + f64.add + ) + (func (;1;) (type 0) (param $x0 f64) (param $x1 f64) (param $x2 f64) (param $x3 f64) (param $y0 f64) (param $y1 f64) (param $y2 f64) (param $y3 f64) (result f64) + local.get $x0 + local.get $y0 + f64.mul + local.get $x1 + local.get $y1 + f64.mul + f64.add + local.get $x2 + local.get $y2 + f64.mul + local.get $x3 + local.get $y3 + f64.mul + f64.add + f64.add + ) + (export "dot_product_example" (func 0)) + (export "with_binary_sum_collapse" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/866.print b/tests/snapshots/testsuite/float_exprs.wast/866.print new file mode 100644 index 0000000000..35b0974cac --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/866.print @@ -0,0 +1,26 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $x + f32.mul + local.get $y + local.get $y + f32.mul + f32.sub + f32.sqrt + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $x + f64.mul + local.get $y + local.get $y + f64.mul + f64.sub + f64.sqrt + ) + (export "f32.contract2fma" (func 0)) + (export "f64.contract2fma" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/873.print b/tests/snapshots/testsuite/float_exprs.wast/873.print new file mode 100644 index 0000000000..5db98831b5 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/873.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $a f32) (param $b f32) (param $c f32) (result f32) + local.get $a + local.get $b + local.get $c + f32.div + f32.sub + ) + (func (;1;) (type 1) (param $a f64) (param $b f64) (param $c f64) (result f64) + local.get $a + local.get $b + local.get $c + f64.div + f64.sub + ) + (export "f32.division_by_small_number" (func 0)) + (export "f64.division_by_small_number" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/876.print b/tests/snapshots/testsuite/float_exprs.wast/876.print new file mode 100644 index 0000000000..d9079a01a8 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/876.print @@ -0,0 +1,22 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $a f32) (param $b f32) (param $c f32) (result f32) + local.get $a + local.get $b + local.get $c + f32.sqrt + f32.add + f32.mul + ) + (func (;1;) (type 1) (param $a f64) (param $b f64) (param $c f64) (result f64) + local.get $a + local.get $b + local.get $c + f64.sqrt + f64.add + f64.mul + ) + (export "f32.golden_ratio" (func 0)) + (export "f64.golden_ratio" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/879.print b/tests/snapshots/testsuite/float_exprs.wast/879.print new file mode 100644 index 0000000000..d524b86c99 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/879.print @@ -0,0 +1,30 @@ +(module + (type (;0;) (func (param f32) (result f32))) + (type (;1;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $n f32) (result f32) + f32.const 0x1p-1 (;=0.5;) + local.get $n + local.get $n + local.get $n + f32.mul + f32.const 0x1p+2 (;=4;) + f32.add + f32.sqrt + f32.add + f32.mul + ) + (func (;1;) (type 1) (param $n f64) (result f64) + f64.const 0x1p-1 (;=0.5;) + local.get $n + local.get $n + local.get $n + f64.mul + f64.const 0x1p+2 (;=4;) + f64.add + f64.sqrt + f64.add + f64.mul + ) + (export "f32.silver_means" (func 0)) + (export "f64.silver_means" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/892.print b/tests/snapshots/testsuite/float_exprs.wast/892.print new file mode 100644 index 0000000000..9642663052 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/892.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param f64 f64) (result i32))) + (func (;0;) (type 0) (param $four f64) (param $ten f64) (result i32) + local.get $four + local.get $ten + f64.div + f64.const 0x1.999999999999ap-2 (;=0.4;) + f64.lt + ) + (export "point_four" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/894.print b/tests/snapshots/testsuite/float_exprs.wast/894.print new file mode 100644 index 0000000000..ad995eb522 --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/894.print @@ -0,0 +1,66 @@ +(module + (type (;0;) (func (param i32) (result f64))) + (func (;0;) (type 0) (param i32) (result f64) + (local f64 f64 f64 f64) + f64.const 0x0p+0 (;=0;) + local.set 1 + block ;; label = @1 + local.get 0 + i32.const 1 + i32.lt_s + br_if 0 (;@1;) + f64.const 0x1p+0 (;=1;) + local.set 2 + f64.const 0x0p+0 (;=0;) + local.set 3 + loop ;; label = @2 + local.get 1 + local.get 2 + f64.const 0x1p+3 (;=8;) + local.get 3 + f64.const 0x1p+3 (;=8;) + f64.mul + local.tee 4 + f64.const 0x1p+0 (;=1;) + f64.add + f64.div + f64.const 0x1p+2 (;=4;) + local.get 4 + f64.const 0x1p+2 (;=4;) + f64.add + f64.div + f64.sub + f64.const 0x1p+1 (;=2;) + local.get 4 + f64.const 0x1.4p+2 (;=5;) + f64.add + f64.div + f64.sub + f64.const 0x1p+1 (;=2;) + local.get 4 + f64.const 0x1.8p+2 (;=6;) + f64.add + f64.div + f64.sub + f64.mul + f64.add + local.set 1 + local.get 3 + f64.const 0x1p+0 (;=1;) + f64.add + local.set 3 + local.get 2 + f64.const 0x1p-4 (;=0.0625;) + f64.mul + local.set 2 + local.get 0 + i32.const -1 + i32.add + local.tee 0 + br_if 0 (;@2;) + end + end + local.get 1 + ) + (export "tau" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/897.print b/tests/snapshots/testsuite/float_exprs.wast/897.print new file mode 100644 index 0000000000..8d3632b66c --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/897.print @@ -0,0 +1,26 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $x + f32.const 0x1p+0 (;=1;) + f32.add + local.get $y + f32.const 0x0p+0 (;=0;) + f32.lt + select + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $x + f64.const 0x1p+0 (;=1;) + f64.add + local.get $y + f64.const 0x0p+0 (;=0;) + f64.lt + select + ) + (export "f32.no_fold_conditional_inc" (func 0)) + (export "f64.no_fold_conditional_inc" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_exprs.wast/94.print b/tests/snapshots/testsuite/float_exprs.wast/94.print new file mode 100644 index 0000000000..bfd756771f --- /dev/null +++ b/tests/snapshots/testsuite/float_exprs.wast/94.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param f32 f32 f32) (result f32))) + (type (;1;) (func (param f64 f64 f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (param $z f32) (result f32) + local.get $x + local.get $z + f32.mul + local.get $y + local.get $z + f32.mul + f32.add + ) + (func (;1;) (type 1) (param $x f64) (param $y f64) (param $z f64) (result f64) + local.get $x + local.get $z + f64.mul + local.get $y + local.get $z + f64.mul + f64.add + ) + (export "f32.no_factor" (func 0)) + (export "f64.no_factor" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_literals.wast/0.print b/tests/snapshots/testsuite/float_literals.wast/0.print new file mode 100644 index 0000000000..2f184e283c --- /dev/null +++ b/tests/snapshots/testsuite/float_literals.wast/0.print @@ -0,0 +1,396 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (func (;0;) (type 0) (result i32) + f32.const nan (;=NaN;) + i32.reinterpret_f32 + ) + (func (;1;) (type 0) (result i32) + f32.const nan (;=NaN;) + i32.reinterpret_f32 + ) + (func (;2;) (type 0) (result i32) + f32.const -nan (;=NaN;) + i32.reinterpret_f32 + ) + (func (;3;) (type 0) (result i32) + f32.const nan (;=NaN;) + i32.reinterpret_f32 + ) + (func (;4;) (type 0) (result i32) + f32.const nan:0x200000 (;=NaN;) + i32.reinterpret_f32 + ) + (func (;5;) (type 0) (result i32) + f32.const -nan:0x7fffff (;=NaN;) + i32.reinterpret_f32 + ) + (func (;6;) (type 0) (result i32) + f32.const nan:0x12345 (;=NaN;) + i32.reinterpret_f32 + ) + (func (;7;) (type 0) (result i32) + f32.const nan:0x304050 (;=NaN;) + i32.reinterpret_f32 + ) + (func (;8;) (type 0) (result i32) + f32.const -nan:0x2abcde (;=NaN;) + i32.reinterpret_f32 + ) + (func (;9;) (type 0) (result i32) + f32.const inf (;=inf;) + i32.reinterpret_f32 + ) + (func (;10;) (type 0) (result i32) + f32.const inf (;=inf;) + i32.reinterpret_f32 + ) + (func (;11;) (type 0) (result i32) + f32.const -inf (;=-inf;) + i32.reinterpret_f32 + ) + (func (;12;) (type 0) (result i32) + f32.const 0x0p+0 (;=0;) + i32.reinterpret_f32 + ) + (func (;13;) (type 0) (result i32) + f32.const 0x0p+0 (;=0;) + i32.reinterpret_f32 + ) + (func (;14;) (type 0) (result i32) + f32.const -0x0p+0 (;=-0;) + i32.reinterpret_f32 + ) + (func (;15;) (type 0) (result i32) + f32.const 0x1.921fb6p+2 (;=6.2831855;) + i32.reinterpret_f32 + ) + (func (;16;) (type 0) (result i32) + f32.const 0x1.p-149 (;=0.000000000000000000000000000000000000000000001;) + i32.reinterpret_f32 + ) + (func (;17;) (type 0) (result i32) + f32.const 0x1p-126 (;=0.000000000000000000000000000000000000011754944;) + i32.reinterpret_f32 + ) + (func (;18;) (type 0) (result i32) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + i32.reinterpret_f32 + ) + (func (;19;) (type 0) (result i32) + f32.const 0x1.fffffcp-127 (;=0.000000000000000000000000000000000000011754942;) + i32.reinterpret_f32 + ) + (func (;20;) (type 0) (result i32) + f32.const 0x1p+10 (;=1024;) + i32.reinterpret_f32 + ) + (func (;21;) (type 0) (result i32) + f32.const 0x0p+0 (;=0;) + i32.reinterpret_f32 + ) + (func (;22;) (type 0) (result i32) + f32.const 0x0p+0 (;=0;) + i32.reinterpret_f32 + ) + (func (;23;) (type 0) (result i32) + f32.const -0x0p+0 (;=-0;) + i32.reinterpret_f32 + ) + (func (;24;) (type 0) (result i32) + f32.const 0x1.921fb6p+2 (;=6.2831855;) + i32.reinterpret_f32 + ) + (func (;25;) (type 0) (result i32) + f32.const 0x1.p-149 (;=0.000000000000000000000000000000000000000000001;) + i32.reinterpret_f32 + ) + (func (;26;) (type 0) (result i32) + f32.const 0x1p-126 (;=0.000000000000000000000000000000000000011754944;) + i32.reinterpret_f32 + ) + (func (;27;) (type 0) (result i32) + f32.const 0x1.fffffcp-127 (;=0.000000000000000000000000000000000000011754942;) + i32.reinterpret_f32 + ) + (func (;28;) (type 0) (result i32) + f32.const 0x1.fffffep+127 (;=340282350000000000000000000000000000000;) + i32.reinterpret_f32 + ) + (func (;29;) (type 0) (result i32) + f32.const 0x1.2a05f2p+33 (;=10000000000;) + i32.reinterpret_f32 + ) + (func (;30;) (type 0) (result i32) + f32.const 0x1.000002p+0 (;=1.0000001;) + i32.reinterpret_f32 + ) + (func (;31;) (type 1) (result i64) + f64.const nan (;=NaN;) + i64.reinterpret_f64 + ) + (func (;32;) (type 1) (result i64) + f64.const nan (;=NaN;) + i64.reinterpret_f64 + ) + (func (;33;) (type 1) (result i64) + f64.const -nan (;=NaN;) + i64.reinterpret_f64 + ) + (func (;34;) (type 1) (result i64) + f64.const nan (;=NaN;) + i64.reinterpret_f64 + ) + (func (;35;) (type 1) (result i64) + f64.const nan:0x4000000000000 (;=NaN;) + i64.reinterpret_f64 + ) + (func (;36;) (type 1) (result i64) + f64.const -nan:0xfffffffffffff (;=NaN;) + i64.reinterpret_f64 + ) + (func (;37;) (type 1) (result i64) + f64.const nan:0x123456789abc (;=NaN;) + i64.reinterpret_f64 + ) + (func (;38;) (type 1) (result i64) + f64.const nan:0x3040506070809 (;=NaN;) + i64.reinterpret_f64 + ) + (func (;39;) (type 1) (result i64) + f64.const -nan:0x2abcdef012345 (;=NaN;) + i64.reinterpret_f64 + ) + (func (;40;) (type 1) (result i64) + f64.const inf (;=inf;) + i64.reinterpret_f64 + ) + (func (;41;) (type 1) (result i64) + f64.const inf (;=inf;) + i64.reinterpret_f64 + ) + (func (;42;) (type 1) (result i64) + f64.const -inf (;=-inf;) + i64.reinterpret_f64 + ) + (func (;43;) (type 1) (result i64) + f64.const 0x0p+0 (;=0;) + i64.reinterpret_f64 + ) + (func (;44;) (type 1) (result i64) + f64.const 0x0p+0 (;=0;) + i64.reinterpret_f64 + ) + (func (;45;) (type 1) (result i64) + f64.const -0x0p+0 (;=-0;) + i64.reinterpret_f64 + ) + (func (;46;) (type 1) (result i64) + f64.const 0x1.921fb54442d18p+2 (;=6.283185307179586;) + i64.reinterpret_f64 + ) + (func (;47;) (type 1) (result i64) + f64.const 0x1.p-1074 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + i64.reinterpret_f64 + ) + (func (;48;) (type 1) (result i64) + f64.const 0x1p-1022 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014;) + i64.reinterpret_f64 + ) + (func (;49;) (type 1) (result i64) + f64.const 0x1.ffffffffffffep-1023 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225073858507201;) + i64.reinterpret_f64 + ) + (func (;50;) (type 1) (result i64) + f64.const 0x1.fffffffffffffp+1023 (;=179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + i64.reinterpret_f64 + ) + (func (;51;) (type 1) (result i64) + f64.const 0x1p+100 (;=1267650600228229400000000000000;) + i64.reinterpret_f64 + ) + (func (;52;) (type 1) (result i64) + f64.const 0x0p+0 (;=0;) + i64.reinterpret_f64 + ) + (func (;53;) (type 1) (result i64) + f64.const 0x0p+0 (;=0;) + i64.reinterpret_f64 + ) + (func (;54;) (type 1) (result i64) + f64.const -0x0p+0 (;=-0;) + i64.reinterpret_f64 + ) + (func (;55;) (type 1) (result i64) + f64.const 0x1.921fb54442d18p+2 (;=6.283185307179586;) + i64.reinterpret_f64 + ) + (func (;56;) (type 1) (result i64) + f64.const 0x1.p-1074 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005;) + i64.reinterpret_f64 + ) + (func (;57;) (type 1) (result i64) + f64.const 0x1p-1022 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014;) + i64.reinterpret_f64 + ) + (func (;58;) (type 1) (result i64) + f64.const 0x1.ffffffffffffep-1023 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225073858507201;) + i64.reinterpret_f64 + ) + (func (;59;) (type 1) (result i64) + f64.const 0x1.fffffffffffffp+1023 (;=179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + i64.reinterpret_f64 + ) + (func (;60;) (type 1) (result i64) + f64.const 0x1.249ad2594c37dp+332 (;=10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + i64.reinterpret_f64 + ) + (func (;61;) (type 1) (result i64) + f64.const 0x1.000001ff19e24p+0 (;=1.000000119;) + i64.reinterpret_f64 + ) + (func (;62;) (type 2) (result f32) + f32.const 0x1.e848p+19 (;=1000000;) + ) + (func (;63;) (type 2) (result f32) + f32.const 0x1.f4p+9 (;=1000;) + ) + (func (;64;) (type 2) (result f32) + f32.const 0x1.f5922p+9 (;=1003.1416;) + ) + (func (;65;) (type 2) (result f32) + f32.const 0x1.c2332cp+49 (;=990000000000000;) + ) + (func (;66;) (type 2) (result f32) + f32.const 0x1.3b5ce8p+93 (;=12200012000000000000000000000;) + ) + (func (;67;) (type 2) (result f32) + f32.const 0x1.41e014p+27 (;=168755360;) + ) + (func (;68;) (type 2) (result f32) + f32.const 0x1.aa0fp+16 (;=109071;) + ) + (func (;69;) (type 2) (result f32) + f32.const 0x1.41ffe2p+15 (;=41215.94;) + ) + (func (;70;) (type 2) (result f32) + f32.const 0x1.ep+20 (;=1966080;) + ) + (func (;71;) (type 2) (result f32) + f32.const 0x1.57805p+44 (;=23605224000000;) + ) + (func (;72;) (type 3) (result f64) + f64.const 0x1.e848p+19 (;=1000000;) + ) + (func (;73;) (type 3) (result f64) + f64.const 0x1.f4p+9 (;=1000;) + ) + (func (;74;) (type 3) (result f64) + f64.const 0x1.f5921fafc8bp+9 (;=1003.141592;) + ) + (func (;75;) (type 3) (result f64) + f64.const 0x1.05c735bb7cc45p-402 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000099;) + ) + (func (;76;) (type 3) (result f64) + f64.const 0x1.3b5ce725bde9cp+93 (;=12200011354000000000000000000;) + ) + (func (;77;) (type 3) (result f64) + f64.const 0x1.5e01e00013332p+51 (;=3078696982321561;) + ) + (func (;78;) (type 3) (result f64) + f64.const 0x1.aa0fp+16 (;=109071;) + ) + (func (;79;) (type 3) (result f64) + f64.const 0x1.41ffe2834b34p+15 (;=41215.94240794191;) + ) + (func (;80;) (type 3) (result f64) + f64.const 0x1.ep+20 (;=1966080;) + ) + (func (;81;) (type 3) (result f64) + f64.const 0x1.578050f9f7p+44 (;=23605225168752;) + ) + (export "f32.nan" (func 0)) + (export "f32.positive_nan" (func 1)) + (export "f32.negative_nan" (func 2)) + (export "f32.plain_nan" (func 3)) + (export "f32.informally_known_as_plain_snan" (func 4)) + (export "f32.all_ones_nan" (func 5)) + (export "f32.misc_nan" (func 6)) + (export "f32.misc_positive_nan" (func 7)) + (export "f32.misc_negative_nan" (func 8)) + (export "f32.infinity" (func 9)) + (export "f32.positive_infinity" (func 10)) + (export "f32.negative_infinity" (func 11)) + (export "f32.zero" (func 12)) + (export "f32.positive_zero" (func 13)) + (export "f32.negative_zero" (func 14)) + (export "f32.misc" (func 15)) + (export "f32.min_positive" (func 16)) + (export "f32.min_normal" (func 17)) + (export "f32.max_finite" (func 18)) + (export "f32.max_subnormal" (func 19)) + (export "f32.trailing_dot" (func 20)) + (export "f32_dec.zero" (func 21)) + (export "f32_dec.positive_zero" (func 22)) + (export "f32_dec.negative_zero" (func 23)) + (export "f32_dec.misc" (func 24)) + (export "f32_dec.min_positive" (func 25)) + (export "f32_dec.min_normal" (func 26)) + (export "f32_dec.max_subnormal" (func 27)) + (export "f32_dec.max_finite" (func 28)) + (export "f32_dec.trailing_dot" (func 29)) + (export "f32_dec.root_beer_float" (func 30)) + (export "f64.nan" (func 31)) + (export "f64.positive_nan" (func 32)) + (export "f64.negative_nan" (func 33)) + (export "f64.plain_nan" (func 34)) + (export "f64.informally_known_as_plain_snan" (func 35)) + (export "f64.all_ones_nan" (func 36)) + (export "f64.misc_nan" (func 37)) + (export "f64.misc_positive_nan" (func 38)) + (export "f64.misc_negative_nan" (func 39)) + (export "f64.infinity" (func 40)) + (export "f64.positive_infinity" (func 41)) + (export "f64.negative_infinity" (func 42)) + (export "f64.zero" (func 43)) + (export "f64.positive_zero" (func 44)) + (export "f64.negative_zero" (func 45)) + (export "f64.misc" (func 46)) + (export "f64.min_positive" (func 47)) + (export "f64.min_normal" (func 48)) + (export "f64.max_subnormal" (func 49)) + (export "f64.max_finite" (func 50)) + (export "f64.trailing_dot" (func 51)) + (export "f64_dec.zero" (func 52)) + (export "f64_dec.positive_zero" (func 53)) + (export "f64_dec.negative_zero" (func 54)) + (export "f64_dec.misc" (func 55)) + (export "f64_dec.min_positive" (func 56)) + (export "f64_dec.min_normal" (func 57)) + (export "f64_dec.max_subnormal" (func 58)) + (export "f64_dec.max_finite" (func 59)) + (export "f64_dec.trailing_dot" (func 60)) + (export "f64_dec.root_beer_float" (func 61)) + (export "f32-dec-sep1" (func 62)) + (export "f32-dec-sep2" (func 63)) + (export "f32-dec-sep3" (func 64)) + (export "f32-dec-sep4" (func 65)) + (export "f32-dec-sep5" (func 66)) + (export "f32-hex-sep1" (func 67)) + (export "f32-hex-sep2" (func 68)) + (export "f32-hex-sep3" (func 69)) + (export "f32-hex-sep4" (func 70)) + (export "f32-hex-sep5" (func 71)) + (export "f64-dec-sep1" (func 72)) + (export "f64-dec-sep2" (func 73)) + (export "f64-dec-sep3" (func 74)) + (export "f64-dec-sep4" (func 75)) + (export "f64-dec-sep5" (func 76)) + (export "f64-hex-sep1" (func 77)) + (export "f64-hex-sep2" (func 78)) + (export "f64-hex-sep3" (func 79)) + (export "f64-hex-sep4" (func 80)) + (export "f64-hex-sep5" (func 81)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_literals.wast/83.print b/tests/snapshots/testsuite/float_literals.wast/83.print new file mode 100644 index 0000000000..4c389e8b19 --- /dev/null +++ b/tests/snapshots/testsuite/float_literals.wast/83.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.ffffffa2p+31 (;=4294967249;) + ) + (export "4294967249" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_memory.wast/0.print b/tests/snapshots/testsuite/float_memory.wast/0.print new file mode 100644 index 0000000000..13d69c7cbb --- /dev/null +++ b/tests/snapshots/testsuite/float_memory.wast/0.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f32) + i32.const 0 + f32.load + ) + (func (;1;) (type 1) (result i32) + i32.const 0 + i32.load + ) + (func (;2;) (type 2) + i32.const 0 + f32.const nan:0x200000 (;=NaN;) + f32.store + ) + (func (;3;) (type 2) + i32.const 0 + i32.const 2141192192 + i32.store + ) + (func (;4;) (type 2) + i32.const 0 + i32.const 0 + i32.store + ) + (memory (;0;) 1 1) + (export "f32.load" (func 0)) + (export "i32.load" (func 1)) + (export "f32.store" (func 2)) + (export "i32.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i32.const 0) "\00\00\a0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_memory.wast/15.print b/tests/snapshots/testsuite/float_memory.wast/15.print new file mode 100644 index 0000000000..f4c9200e6a --- /dev/null +++ b/tests/snapshots/testsuite/float_memory.wast/15.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f64))) + (type (;1;) (func (result i64))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f64) + i32.const 0 + f64.load + ) + (func (;1;) (type 1) (result i64) + i32.const 0 + i64.load + ) + (func (;2;) (type 2) + i32.const 0 + f64.const nan:0x4000000000000 (;=NaN;) + f64.store + ) + (func (;3;) (type 2) + i32.const 0 + i64.const 9219994337134247936 + i64.store + ) + (func (;4;) (type 2) + i32.const 0 + i64.const 0 + i64.store + ) + (memory (;0;) 1 1) + (export "f64.load" (func 0)) + (export "i64.load" (func 1)) + (export "f64.store" (func 2)) + (export "i64.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i32.const 0) "\00\00\00\00\00\00\f4\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_memory.wast/30.print b/tests/snapshots/testsuite/float_memory.wast/30.print new file mode 100644 index 0000000000..257a57f962 --- /dev/null +++ b/tests/snapshots/testsuite/float_memory.wast/30.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f32) + i32.const 1 + f32.load + ) + (func (;1;) (type 1) (result i32) + i32.const 1 + i32.load + ) + (func (;2;) (type 2) + i32.const 1 + f32.const nan:0x200000 (;=NaN;) + f32.store + ) + (func (;3;) (type 2) + i32.const 1 + i32.const 2141192192 + i32.store + ) + (func (;4;) (type 2) + i32.const 1 + i32.const 0 + i32.store + ) + (memory (;0;) 1 1) + (export "f32.load" (func 0)) + (export "i32.load" (func 1)) + (export "f32.store" (func 2)) + (export "i32.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i32.const 0) "\00\00\00\a0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_memory.wast/45.print b/tests/snapshots/testsuite/float_memory.wast/45.print new file mode 100644 index 0000000000..708557b0b1 --- /dev/null +++ b/tests/snapshots/testsuite/float_memory.wast/45.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f64))) + (type (;1;) (func (result i64))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f64) + i32.const 1 + f64.load + ) + (func (;1;) (type 1) (result i64) + i32.const 1 + i64.load + ) + (func (;2;) (type 2) + i32.const 1 + f64.const nan:0x4000000000000 (;=NaN;) + f64.store + ) + (func (;3;) (type 2) + i32.const 1 + i64.const 9219994337134247936 + i64.store + ) + (func (;4;) (type 2) + i32.const 1 + i64.const 0 + i64.store + ) + (memory (;0;) 1 1) + (export "f64.load" (func 0)) + (export "i64.load" (func 1)) + (export "f64.store" (func 2)) + (export "i64.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i32.const 0) "\00\00\00\00\00\00\00\f4\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_memory.wast/60.print b/tests/snapshots/testsuite/float_memory.wast/60.print new file mode 100644 index 0000000000..c5b2781d39 --- /dev/null +++ b/tests/snapshots/testsuite/float_memory.wast/60.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f32) + i32.const 0 + f32.load + ) + (func (;1;) (type 1) (result i32) + i32.const 0 + i32.load + ) + (func (;2;) (type 2) + i32.const 0 + f32.const nan:0x500001 (;=NaN;) + f32.store + ) + (func (;3;) (type 2) + i32.const 0 + i32.const 2144337921 + i32.store + ) + (func (;4;) (type 2) + i32.const 0 + i32.const 0 + i32.store + ) + (memory (;0;) 1 1) + (export "f32.load" (func 0)) + (export "i32.load" (func 1)) + (export "f32.store" (func 2)) + (export "i32.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i32.const 0) "\01\00\d0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_memory.wast/75.print b/tests/snapshots/testsuite/float_memory.wast/75.print new file mode 100644 index 0000000000..c5da336dc0 --- /dev/null +++ b/tests/snapshots/testsuite/float_memory.wast/75.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f64))) + (type (;1;) (func (result i64))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f64) + i32.const 0 + f64.load + ) + (func (;1;) (type 1) (result i64) + i32.const 0 + i64.load + ) + (func (;2;) (type 2) + i32.const 0 + f64.const nan:0xc000000000001 (;=NaN;) + f64.store + ) + (func (;3;) (type 2) + i32.const 0 + i64.const 9222246136947933185 + i64.store + ) + (func (;4;) (type 2) + i32.const 0 + i64.const 0 + i64.store + ) + (memory (;0;) 1 1) + (export "f64.load" (func 0)) + (export "i64.load" (func 1)) + (export "f64.store" (func 2)) + (export "i64.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i32.const 0) "\01\00\00\00\00\00\fc\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/float_misc.wast/0.print b/tests/snapshots/testsuite/float_misc.wast/0.print new file mode 100644 index 0000000000..c72e266281 --- /dev/null +++ b/tests/snapshots/testsuite/float_misc.wast/0.print @@ -0,0 +1,160 @@ +(module + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param f32) (result f32))) + (type (;2;) (func (param f64 f64) (result f64))) + (type (;3;) (func (param f64) (result f64))) + (func (;0;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.add + ) + (func (;1;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.sub + ) + (func (;2;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.mul + ) + (func (;3;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.div + ) + (func (;4;) (type 1) (param $x f32) (result f32) + local.get $x + f32.sqrt + ) + (func (;5;) (type 1) (param $x f32) (result f32) + local.get $x + f32.abs + ) + (func (;6;) (type 1) (param $x f32) (result f32) + local.get $x + f32.neg + ) + (func (;7;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.copysign + ) + (func (;8;) (type 1) (param $x f32) (result f32) + local.get $x + f32.ceil + ) + (func (;9;) (type 1) (param $x f32) (result f32) + local.get $x + f32.floor + ) + (func (;10;) (type 1) (param $x f32) (result f32) + local.get $x + f32.trunc + ) + (func (;11;) (type 1) (param $x f32) (result f32) + local.get $x + f32.nearest + ) + (func (;12;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.min + ) + (func (;13;) (type 0) (param $x f32) (param $y f32) (result f32) + local.get $x + local.get $y + f32.max + ) + (func (;14;) (type 2) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.add + ) + (func (;15;) (type 2) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.sub + ) + (func (;16;) (type 2) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.mul + ) + (func (;17;) (type 2) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.div + ) + (func (;18;) (type 3) (param $x f64) (result f64) + local.get $x + f64.sqrt + ) + (func (;19;) (type 3) (param $x f64) (result f64) + local.get $x + f64.abs + ) + (func (;20;) (type 3) (param $x f64) (result f64) + local.get $x + f64.neg + ) + (func (;21;) (type 2) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.copysign + ) + (func (;22;) (type 3) (param $x f64) (result f64) + local.get $x + f64.ceil + ) + (func (;23;) (type 3) (param $x f64) (result f64) + local.get $x + f64.floor + ) + (func (;24;) (type 3) (param $x f64) (result f64) + local.get $x + f64.trunc + ) + (func (;25;) (type 3) (param $x f64) (result f64) + local.get $x + f64.nearest + ) + (func (;26;) (type 2) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.min + ) + (func (;27;) (type 2) (param $x f64) (param $y f64) (result f64) + local.get $x + local.get $y + f64.max + ) + (export "f32.add" (func 0)) + (export "f32.sub" (func 1)) + (export "f32.mul" (func 2)) + (export "f32.div" (func 3)) + (export "f32.sqrt" (func 4)) + (export "f32.abs" (func 5)) + (export "f32.neg" (func 6)) + (export "f32.copysign" (func 7)) + (export "f32.ceil" (func 8)) + (export "f32.floor" (func 9)) + (export "f32.trunc" (func 10)) + (export "f32.nearest" (func 11)) + (export "f32.min" (func 12)) + (export "f32.max" (func 13)) + (export "f64.add" (func 14)) + (export "f64.sub" (func 15)) + (export "f64.mul" (func 16)) + (export "f64.div" (func 17)) + (export "f64.sqrt" (func 18)) + (export "f64.abs" (func 19)) + (export "f64.neg" (func 20)) + (export "f64.copysign" (func 21)) + (export "f64.ceil" (func 22)) + (export "f64.floor" (func 23)) + (export "f64.trunc" (func 24)) + (export "f64.nearest" (func 25)) + (export "f64.min" (func 26)) + (export "f64.max" (func 27)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/forward.wast/0.print b/tests/snapshots/testsuite/forward.wast/0.print new file mode 100644 index 0000000000..0a7aace018 --- /dev/null +++ b/tests/snapshots/testsuite/forward.wast/0.print @@ -0,0 +1,31 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func $even (;0;) (type 0) (param $n i32) (result i32) + local.get $n + i32.const 0 + i32.eq + if (result i32) ;; label = @1 + i32.const 1 + else + local.get $n + i32.const 1 + i32.sub + call $odd + end + ) + (func $odd (;1;) (type 0) (param $n i32) (result i32) + local.get $n + i32.const 0 + i32.eq + if (result i32) ;; label = @1 + i32.const 0 + else + local.get $n + i32.const 1 + i32.sub + call $even + end + ) + (export "even" (func $even)) + (export "odd" (func $odd)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/func.wast/0.print b/tests/snapshots/testsuite/func.wast/0.print new file mode 100644 index 0000000000..dcc8fe2c04 --- /dev/null +++ b/tests/snapshots/testsuite/func.wast/0.print @@ -0,0 +1,504 @@ +(module + (type $sig (;0;) (func)) + (type $sig-1 (;1;) (func)) + (type $sig-2 (;2;) (func (result i32))) + (type $sig-3 (;3;) (func (param i32))) + (type $sig-4 (;4;) (func (param i32 f64 i32) (result i32))) + (type $forward (;5;) (func)) + (type (;6;) (func (param i32 f64 i64))) + (type (;7;) (func (param i32 f64))) + (type (;8;) (func (param i32 f32 i64 i32 f64))) + (type (;9;) (func (result i32 f64 f32))) + (type (;10;) (func (result i32 f64))) + (type (;11;) (func (result i32 f32 i64 i32 f64))) + (type (;12;) (func (param i32 f32 i64 i32) (result i32 i64 i32))) + (type (;13;) (func (result i64))) + (type (;14;) (func (result f32))) + (type (;15;) (func (result f64))) + (type (;16;) (func (param i32 i32) (result i32))) + (type (;17;) (func (param i64 i64) (result i64))) + (type (;18;) (func (param f32 f32) (result f32))) + (type (;19;) (func (param f64 f64) (result f64))) + (type (;20;) (func (param f32 i32 i64 i32 f64 i32) (result f64))) + (type (;21;) (func (result i32 i32 i32))) + (type (;22;) (func (result i32 i64))) + (type (;23;) (func (param i32) (result i32))) + (type (;24;) (func (param i32) (result i32 i64))) + (type (;25;) (func (param i32) (result i32 i32))) + (type (;26;) (func (result i32 i32))) + (type (;27;) (func (param i32 i64 f32 f32 i32 f64 f32 i32 i32 i32 f32 f64 f64 f64 i32 i32 f32) (result f64 f32 i32 i32 i32 i64 f32 i32 i32 f32 f64 f64 i32 f32 i32 f64))) + (func $dummy (;0;) (type $sig)) + (func (;1;) (type $sig)) + (func (;2;) (type $sig)) + (func $f (;3;) (type $sig)) + (func $h (;4;) (type $sig)) + (func (;5;) (type $sig)) + (func (;6;) (type $sig)) + (func (;7;) (type $sig) + (local i32) + ) + (func (;8;) (type $sig) + (local $x i32) + ) + (func (;9;) (type $sig) + (local i32 f64 i64) + ) + (func (;10;) (type $sig) + (local i32 f64) + ) + (func (;11;) (type $sig) + (local i32 f32) (local $x i64) (local i32 f64) + ) + (func (;12;) (type $sig)) + (func (;13;) (type $sig)) + (func (;14;) (type $sig-3) (param i32)) + (func (;15;) (type $sig-3) (param $x i32)) + (func (;16;) (type 6) (param i32 f64 i64)) + (func (;17;) (type 7) (param i32 f64)) + (func (;18;) (type 8) (param i32 f32) (param $x i64) (param i32 f64)) + (func (;19;) (type $sig)) + (func (;20;) (type $sig)) + (func (;21;) (type $sig-2) (result i32) + unreachable + ) + (func (;22;) (type 9) (result i32 f64 f32) + unreachable + ) + (func (;23;) (type 10) (result i32 f64) + unreachable + ) + (func (;24;) (type 11) (result i32 f32 i64 i32 f64) + unreachable + ) + (func (;25;) (type $sig-1)) + (func (;26;) (type $sig-2) (result i32) + i32.const 0 + ) + (func (;27;) (type $sig-3) (param i32)) + (func (;28;) (type $sig-4) (param i32 f64 i32) (result i32) + i32.const 0 + ) + (func (;29;) (type $sig-2) (result i32) + i32.const 0 + ) + (func (;30;) (type $sig-3) (param i32)) + (func (;31;) (type $sig-4) (param i32 f64 i32) (result i32) + i32.const 0 + ) + (func (;32;) (type $sig)) + (func (;33;) (type $forward)) + (func $complex (;34;) (type 12) (param i32 f32) (param $x i64) (param i32) (result i32 i64 i32) + (local f32) (local $y i32) (local i64 i32 f64 i32) + unreachable + unreachable + ) + (func $complex-sig (;35;) (type $sig) + (local f32) (local $y i32) (local i64 i32 f64 i32) + unreachable + unreachable + ) + (func (;36;) (type $sig-2) (result i32) + (local i32 i32) + local.get 0 + ) + (func (;37;) (type 13) (result i64) + (local i64 i64) + local.get 0 + ) + (func (;38;) (type 14) (result f32) + (local f32 f32) + local.get 0 + ) + (func (;39;) (type 15) (result f64) + (local f64 f64) + local.get 0 + ) + (func (;40;) (type $sig-2) (result i32) + (local i32 i32) + local.get 1 + ) + (func (;41;) (type 13) (result i64) + (local i64 i64) + local.get 1 + ) + (func (;42;) (type 14) (result f32) + (local f32 f32) + local.get 1 + ) + (func (;43;) (type 15) (result f64) + (local f64 f64) + local.get 1 + ) + (func (;44;) (type 15) (result f64) + (local f32) (local $x i32) (local i64 i32 f64 i32) + local.get 0 + f32.neg + drop + local.get $x + i32.eqz + drop + local.get 2 + i64.eqz + drop + local.get 3 + i32.eqz + drop + local.get 4 + f64.neg + drop + local.get 5 + i32.eqz + drop + local.get 4 + ) + (func (;45;) (type 16) (param i32 i32) (result i32) + local.get 0 + ) + (func (;46;) (type 17) (param i64 i64) (result i64) + local.get 0 + ) + (func (;47;) (type 18) (param f32 f32) (result f32) + local.get 0 + ) + (func (;48;) (type 19) (param f64 f64) (result f64) + local.get 0 + ) + (func (;49;) (type 16) (param i32 i32) (result i32) + local.get 1 + ) + (func (;50;) (type 17) (param i64 i64) (result i64) + local.get 1 + ) + (func (;51;) (type 18) (param f32 f32) (result f32) + local.get 1 + ) + (func (;52;) (type 19) (param f64 f64) (result f64) + local.get 1 + ) + (func (;53;) (type 20) (param f32 i32) (param $x i64) (param i32 f64 i32) (result f64) + local.get 0 + f32.neg + drop + local.get 1 + i32.eqz + drop + local.get $x + i64.eqz + drop + local.get 3 + i32.eqz + drop + local.get 4 + f64.neg + drop + local.get 5 + i32.eqz + drop + local.get 4 + ) + (func (;54;) (type $sig)) + (func (;55;) (type $sig) + call $dummy + ) + (func (;56;) (type $sig-2) (result i32) + i32.const 77 + ) + (func (;57;) (type 13) (result i64) + i64.const 7777 + ) + (func (;58;) (type 14) (result f32) + f32.const 0x1.36ccccp+6 (;=77.7;) + ) + (func (;59;) (type 15) (result f64) + f64.const 0x1.37147ae147ae1p+6 (;=77.77;) + ) + (func (;60;) (type 10) (result i32 f64) + i32.const 77 + f64.const 0x1.cp+2 (;=7;) + ) + (func (;61;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + ) + (func (;62;) (type $sig) + block ;; label = @1 + call $dummy + call $dummy + end + ) + (func (;63;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + ) + (func (;64;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + ) + (func (;65;) (type $sig) + return + ) + (func (;66;) (type $sig-2) (result i32) + i32.const 78 + return + ) + (func (;67;) (type 13) (result i64) + i64.const 7878 + return + ) + (func (;68;) (type 14) (result f32) + f32.const 0x1.3accccp+6 (;=78.7;) + return + ) + (func (;69;) (type 15) (result f64) + f64.const 0x1.3b1eb851eb852p+6 (;=78.78;) + return + ) + (func (;70;) (type 10) (result i32 f64) + i32.const 78 + f64.const 0x1.3b1eb851eb852p+6 (;=78.78;) + return + ) + (func (;71;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + return + ) + (func (;72;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + return + ) + (func (;73;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + return + ) + (func (;74;) (type $sig) + br 0 (;@0;) + ) + (func (;75;) (type $sig-2) (result i32) + i32.const 79 + br 0 (;@0;) + ) + (func (;76;) (type 13) (result i64) + i64.const 7979 + br 0 (;@0;) + ) + (func (;77;) (type 14) (result f32) + f32.const 0x1.3f999ap+6 (;=79.9;) + br 0 (;@0;) + ) + (func (;78;) (type 15) (result f64) + f64.const 0x1.3f28f5c28f5c3p+6 (;=79.79;) + br 0 (;@0;) + ) + (func (;79;) (type 10) (result i32 f64) + i32.const 79 + f64.const 0x1.3f28f5c28f5c3p+6 (;=79.79;) + br 0 (;@0;) + ) + (func (;80;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + br 0 (;@0;) + ) + (func (;81;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + br 0 (;@0;) + ) + (func (;82;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + br 0 (;@0;) + ) + (func (;83;) (type $sig-3) (param i32) + local.get 0 + br_if 0 (;@0;) + ) + (func (;84;) (type 23) (param i32) (result i32) + i32.const 50 + local.get 0 + br_if 0 (;@0;) + drop + i32.const 51 + ) + (func (;85;) (type 24) (param i32) (result i32 i64) + i32.const 50 + i64.const 51 + local.get 0 + br_if 0 (;@0;) + drop + drop + i32.const 51 + i64.const 52 + ) + (func (;86;) (type $sig-3) (param i32) + local.get 0 + br_table 0 (;@0;) 0 (;@0;) 0 (;@0;) + ) + (func (;87;) (type 23) (param i32) (result i32) + i32.const 50 + local.get 0 + br_table 0 (;@0;) 0 (;@0;) + i32.const 51 + ) + (func (;88;) (type 24) (param i32) (result i32 i64) + i32.const 50 + i64.const 51 + local.get 0 + br_table 0 (;@0;) 0 (;@0;) + i32.const 51 + i64.const 52 + ) + (func (;89;) (type $sig-3) (param i32) + block ;; label = @1 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + end + ) + (func (;90;) (type 23) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 50 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + i32.const 51 + end + i32.const 2 + i32.add + ) + (func (;91;) (type 25) (param i32) (result i32 i32) + block (type 26) (result i32 i32) ;; label = @1 + i32.const 50 + i32.const 51 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + i32.const 51 + i32.const -3 + end + i32.add + i32.const 52 + ) + (func (;92;) (type 27) (param i32 i64 f32 f32 i32 f64 f32 i32 i32 i32 f32 f64 f64 f64 i32 i32 f32) (result f64 f32 i32 i32 i32 i64 f32 i32 i32 f32 f64 f64 i32 f32 i32 f64) + local.get 5 + local.get 2 + local.get 0 + local.get 8 + local.get 7 + local.get 1 + local.get 3 + local.get 9 + local.get 4 + local.get 6 + local.get 13 + local.get 11 + local.get 15 + local.get 16 + local.get 14 + local.get 12 + ) + (func (;93;) (type $sig-2) (result i32) + (local i32) + local.get 0 + ) + (func (;94;) (type 13) (result i64) + (local i64) + local.get 0 + ) + (func (;95;) (type 14) (result f32) + (local f32) + local.get 0 + ) + (func (;96;) (type 15) (result f64) + (local f64) + local.get 0 + ) + (export "f" (func 2)) + (export "g" (func $h)) + (export "type-use-1" (func 25)) + (export "type-use-2" (func 26)) + (export "type-use-3" (func 27)) + (export "type-use-4" (func 28)) + (export "type-use-5" (func 29)) + (export "type-use-6" (func 30)) + (export "type-use-7" (func 31)) + (export "local-first-i32" (func 36)) + (export "local-first-i64" (func 37)) + (export "local-first-f32" (func 38)) + (export "local-first-f64" (func 39)) + (export "local-second-i32" (func 40)) + (export "local-second-i64" (func 41)) + (export "local-second-f32" (func 42)) + (export "local-second-f64" (func 43)) + (export "local-mixed" (func 44)) + (export "param-first-i32" (func 45)) + (export "param-first-i64" (func 46)) + (export "param-first-f32" (func 47)) + (export "param-first-f64" (func 48)) + (export "param-second-i32" (func 49)) + (export "param-second-i64" (func 50)) + (export "param-second-f32" (func 51)) + (export "param-second-f64" (func 52)) + (export "param-mixed" (func 53)) + (export "empty" (func 54)) + (export "value-void" (func 55)) + (export "value-i32" (func 56)) + (export "value-i64" (func 57)) + (export "value-f32" (func 58)) + (export "value-f64" (func 59)) + (export "value-i32-f64" (func 60)) + (export "value-i32-i32-i32" (func 61)) + (export "value-block-void" (func 62)) + (export "value-block-i32" (func 63)) + (export "value-block-i32-i64" (func 64)) + (export "return-empty" (func 65)) + (export "return-i32" (func 66)) + (export "return-i64" (func 67)) + (export "return-f32" (func 68)) + (export "return-f64" (func 69)) + (export "return-i32-f64" (func 70)) + (export "return-i32-i32-i32" (func 71)) + (export "return-block-i32" (func 72)) + (export "return-block-i32-i64" (func 73)) + (export "break-empty" (func 74)) + (export "break-i32" (func 75)) + (export "break-i64" (func 76)) + (export "break-f32" (func 77)) + (export "break-f64" (func 78)) + (export "break-i32-f64" (func 79)) + (export "break-i32-i32-i32" (func 80)) + (export "break-block-i32" (func 81)) + (export "break-block-i32-i64" (func 82)) + (export "break-br_if-empty" (func 83)) + (export "break-br_if-num" (func 84)) + (export "break-br_if-num-num" (func 85)) + (export "break-br_table-empty" (func 86)) + (export "break-br_table-num" (func 87)) + (export "break-br_table-num-num" (func 88)) + (export "break-br_table-nested-empty" (func 89)) + (export "break-br_table-nested-num" (func 90)) + (export "break-br_table-nested-num-num" (func 91)) + (export "large-sig" (func 92)) + (export "init-local-i32" (func 93)) + (export "init-local-i64" (func 94)) + (export "init-local-f32" (func 95)) + (export "init-local-f64" (func 96)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/func.wast/90.print b/tests/snapshots/testsuite/func.wast/90.print new file mode 100644 index 0000000000..73664e0df9 --- /dev/null +++ b/tests/snapshots/testsuite/func.wast/90.print @@ -0,0 +1,19 @@ +(module + (type $t (;0;) (func (param i32))) + (type (;1;) (func (result f64))) + (type (;2;) (func)) + (func $f (;0;) (type 1) (result f64) + f64.const 0x0p+0 (;=0;) + ) + (func $g (;1;) (type $t) (param i32)) + (func $i32->void (;2;) (type $t) (param i32)) + (func $void->f64 (;3;) (type 1) (result f64) + f64.const 0x0p+0 (;=0;) + ) + (func $check (;4;) (type 2) + i32.const 0 + call $i32->void + call $void->f64 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/func.wast/93.print b/tests/snapshots/testsuite/func.wast/93.print new file mode 100644 index 0000000000..7748f47f12 --- /dev/null +++ b/tests/snapshots/testsuite/func.wast/93.print @@ -0,0 +1,25 @@ +(module + (type $proc (;0;) (func (result i32))) + (type $sig (;1;) (func (param i32) (result i32))) + (func (;0;) (type $sig) (param $var i32) (result i32) + (local i32) + local.get 1 + ) + (func $g (;1;) (type $sig) (param $var i32) (result i32) + (local i32) + local.get 1 + ) + (func (;2;) (type $sig) (param i32) (result i32) + local.get 0 + call $g + ) + (func (;3;) (type $proc) (result i32) + (local $var i32) + i32.const 42 + local.set $var + local.get $var + ) + (export "f" (func 0)) + (export "g" (func 2)) + (export "p" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/func.wast/97.print b/tests/snapshots/testsuite/func.wast/97.print new file mode 100644 index 0000000000..78856df296 --- /dev/null +++ b/tests/snapshots/testsuite/func.wast/97.print @@ -0,0 +1,83 @@ +(module + (type $sig (;0;) (func)) + (type $empty-sig-duplicate (;1;) (func)) + (type $complex-sig-duplicate (;2;) (func (param i64 i64 f64 i64 f64 i64 f32 i32))) + (type (;3;) (func (param f64 i64 f64 i64 f64 i64 f32 i32))) + (func $empty-sig-1 (;0;) (type $sig)) + (func $complex-sig-1 (;1;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $empty-sig-2 (;2;) (type $sig)) + (func $complex-sig-2 (;3;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-3 (;4;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-4 (;5;) (type $complex-sig-duplicate) (param i64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-5 (;6;) (type $complex-sig-duplicate) (param i64 i64 f64 i64 f64 i64 f32 i32)) + (func (;7;) (type $sig) + i32.const 1 + call_indirect (type $sig) + i32.const 4 + call_indirect (type $sig) + ) + (func (;8;) (type $sig) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 0 + call_indirect (type 3) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 2 + call_indirect (type 3) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 3 + call_indirect (type 3) + ) + (func (;9;) (type $sig) + i32.const 1 + call_indirect (type $empty-sig-duplicate) + ) + (func (;10;) (type $sig) + i64.const 0 + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 5 + call_indirect (type $complex-sig-duplicate) + i64.const 0 + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 6 + call_indirect (type $complex-sig-duplicate) + ) + (table (;0;) 7 7 funcref) + (export "signature-explicit-reused" (func 7)) + (export "signature-implicit-reused" (func 8)) + (export "signature-explicit-duplicate" (func 9)) + (export "signature-implicit-duplicate" (func 10)) + (elem (;0;) (i32.const 0) func $complex-sig-3 $empty-sig-2 $complex-sig-1 $complex-sig-3 $empty-sig-1 $complex-sig-4 $complex-sig-5) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/func_ptrs.wast/0.print b/tests/snapshots/testsuite/func_ptrs.wast/0.print new file mode 100644 index 0000000000..08d9f2c914 --- /dev/null +++ b/tests/snapshots/testsuite/func_ptrs.wast/0.print @@ -0,0 +1,33 @@ +(module + (type (;0;) (func)) + (type $S (;1;) (func)) + (type (;2;) (func)) + (type (;3;) (func (result i32))) + (type (;4;) (func (result i32))) + (type $T (;5;) (func (param i32) (result i32))) + (type $U (;6;) (func (param i32))) + (import "spectest" "print_i32" (func $print (;0;) (type $U))) + (func (;1;) (type 0)) + (func (;2;) (type $S)) + (func (;3;) (type 4) (result i32) + i32.const 13 + ) + (func (;4;) (type $T) (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add + ) + (func (;5;) (type $T) (param $a i32) (result i32) + local.get $a + i32.const 2 + i32.sub + ) + (func (;6;) (type $U) (param i32) + local.get 0 + call $print + ) + (export "one" (func 3)) + (export "two" (func 4)) + (export "three" (func 5)) + (export "four" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/func_ptrs.wast/12.print b/tests/snapshots/testsuite/func_ptrs.wast/12.print new file mode 100644 index 0000000000..e77efbad5f --- /dev/null +++ b/tests/snapshots/testsuite/func_ptrs.wast/12.print @@ -0,0 +1,32 @@ +(module + (type $T (;0;) (func (result i32))) + (type $U (;1;) (func (result i32))) + (type (;2;) (func (param i32) (result i32))) + (func $t1 (;0;) (type $T) (result i32) + i32.const 1 + ) + (func $t2 (;1;) (type $T) (result i32) + i32.const 2 + ) + (func $t3 (;2;) (type $T) (result i32) + i32.const 3 + ) + (func $u1 (;3;) (type $U) (result i32) + i32.const 4 + ) + (func $u2 (;4;) (type $U) (result i32) + i32.const 5 + ) + (func (;5;) (type 2) (param $i i32) (result i32) + local.get $i + call_indirect (type $T) + ) + (func (;6;) (type 2) (param $i i32) (result i32) + local.get $i + call_indirect (type $U) + ) + (table (;0;) 7 7 funcref) + (export "callt" (func 5)) + (export "callu" (func 6)) + (elem (;0;) (i32.const 0) func $t1 $t2 $t3 $u1 $u2 $t1 $t3) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/func_ptrs.wast/33.print b/tests/snapshots/testsuite/func_ptrs.wast/33.print new file mode 100644 index 0000000000..0db94ae75e --- /dev/null +++ b/tests/snapshots/testsuite/func_ptrs.wast/33.print @@ -0,0 +1,17 @@ +(module + (type $T (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (func $t1 (;0;) (type $T) (result i32) + i32.const 1 + ) + (func $t2 (;1;) (type $T) (result i32) + i32.const 2 + ) + (func (;2;) (type 1) (param $i i32) (result i32) + local.get $i + call_indirect (type $T) + ) + (table (;0;) 2 2 funcref) + (export "callt" (func 2)) + (elem (;0;) (i32.const 0) func $t1 $t2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/global.wast/0.print b/tests/snapshots/testsuite/global.wast/0.print new file mode 100644 index 0000000000..bea06e9abd --- /dev/null +++ b/tests/snapshots/testsuite/global.wast/0.print @@ -0,0 +1,328 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (result i64))) + (type (;3;) (func (result externref))) + (type (;4;) (func (param i32))) + (type (;5;) (func (param i64))) + (type (;6;) (func (param externref))) + (type (;7;) (func (result f32))) + (type (;8;) (func (result f64))) + (type (;9;) (func (param f32))) + (type (;10;) (func (param f64))) + (type (;11;) (func)) + (type (;12;) (func (param i32) (result i32))) + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "global_i64" (global (;1;) i64)) + (func (;0;) (type 1) (result i32) + global.get $a + ) + (func (;1;) (type 2) (result i64) + global.get $b + ) + (func (;2;) (type 3) (result externref) + global.get $r + ) + (func (;3;) (type 3) (result externref) + global.get $mr + ) + (func (;4;) (type 1) (result i32) + global.get $x + ) + (func (;5;) (type 2) (result i64) + global.get $y + ) + (func (;6;) (type 1) (result i32) + global.get $z1 + ) + (func (;7;) (type 2) (result i64) + global.get $z2 + ) + (func (;8;) (type 4) (param i32) + local.get 0 + global.set $x + ) + (func (;9;) (type 5) (param i64) + local.get 0 + global.set $y + ) + (func (;10;) (type 6) (param externref) + local.get 0 + global.set $mr + ) + (func (;11;) (type 7) (result f32) + global.get 3 + ) + (func (;12;) (type 8) (result f64) + global.get 4 + ) + (func (;13;) (type 7) (result f32) + global.get 7 + ) + (func (;14;) (type 8) (result f64) + global.get 8 + ) + (func (;15;) (type 9) (param f32) + local.get 0 + global.set 7 + ) + (func (;16;) (type 10) (param f64) + local.get 0 + global.set 8 + ) + (func $dummy (;17;) (type 11)) + (func (;18;) (type 1) (result i32) + global.get $x + i32.const 2 + i32.const 3 + select + ) + (func (;19;) (type 1) (result i32) + i32.const 2 + global.get $x + i32.const 3 + select + ) + (func (;20;) (type 1) (result i32) + i32.const 2 + i32.const 3 + global.get $x + select + ) + (func (;21;) (type 1) (result i32) + loop (result i32) ;; label = @1 + global.get $x + call $dummy + call $dummy + end + ) + (func (;22;) (type 1) (result i32) + loop (result i32) ;; label = @1 + call $dummy + global.get $x + call $dummy + end + ) + (func (;23;) (type 1) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + global.get $x + end + ) + (func (;24;) (type 1) (result i32) + global.get $x + if (result i32) ;; label = @1 + call $dummy + i32.const 2 + else + call $dummy + i32.const 3 + end + ) + (func (;25;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + global.get $x + else + i32.const 2 + end + ) + (func (;26;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 2 + else + global.get $x + end + ) + (func (;27;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;28;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;29;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;30;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;31;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;32;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;33;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + i32.const 0 + call_indirect (type $check) + end + ) + (func (;34;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + global.get $x + call_indirect (type $check) + end + ) + (func (;35;) (type 11) + global.get $x + i32.const 1 + i32.store + ) + (func (;36;) (type 11) + i32.const 0 + global.get $x + i32.store + ) + (func (;37;) (type 1) (result i32) + global.get $x + i32.load + ) + (func (;38;) (type 1) (result i32) + global.get $x + memory.grow + ) + (func $f (;39;) (type 12) (param i32) (result i32) + local.get 0 + ) + (func (;40;) (type 1) (result i32) + global.get $x + call $f + ) + (func (;41;) (type 1) (result i32) + global.get $x + return + ) + (func (;42;) (type 11) + global.get $x + drop + ) + (func (;43;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + br 0 (;@1;) + end + ) + (func (;44;) (type 12) (param i32) (result i32) + global.get $x + local.set 0 + local.get 0 + ) + (func (;45;) (type 12) (param i32) (result i32) + global.get $x + local.tee 0 + ) + (func (;46;) (type 1) (result i32) + global.get $x + global.set $x + global.get $x + ) + (func (;47;) (type 1) (result i32) + global.get $x + i32.eqz + ) + (func (;48;) (type 1) (result i32) + global.get $x + global.get $x + i32.mul + ) + (func (;49;) (type 1) (result i32) + global.get 0 + i32.const 1 + i32.gt_u + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;2;) i32 i32.const -2) + (global (;3;) f32 f32.const -0x1.8p+1 (;=-3;)) + (global (;4;) f64 f64.const -0x1p+2 (;=-4;)) + (global $b (;5;) i64 i64.const -5) + (global $x (;6;) (mut i32) i32.const -12) + (global (;7;) (mut f32) f32.const -0x1.ap+3 (;=-13;)) + (global (;8;) (mut f64) f64.const -0x1.cp+3 (;=-14;)) + (global $y (;9;) (mut i64) i64.const -15) + (global $z1 (;10;) i32 global.get 0) + (global $z2 (;11;) i64 global.get 1) + (global $r (;12;) externref ref.null extern) + (global $mr (;13;) (mut externref) ref.null extern) + (global (;14;) funcref ref.null func) + (export "get-a" (func 0)) + (export "get-b" (func 1)) + (export "get-r" (func 2)) + (export "get-mr" (func 3)) + (export "get-x" (func 4)) + (export "get-y" (func 5)) + (export "get-z1" (func 6)) + (export "get-z2" (func 7)) + (export "set-x" (func 8)) + (export "set-y" (func 9)) + (export "set-mr" (func 10)) + (export "get-3" (func 11)) + (export "get-4" (func 12)) + (export "get-7" (func 13)) + (export "get-8" (func 14)) + (export "set-7" (func 15)) + (export "set-8" (func 16)) + (export "as-select-first" (func 18)) + (export "as-select-mid" (func 19)) + (export "as-select-last" (func 20)) + (export "as-loop-first" (func 21)) + (export "as-loop-mid" (func 22)) + (export "as-loop-last" (func 23)) + (export "as-if-condition" (func 24)) + (export "as-if-then" (func 25)) + (export "as-if-else" (func 26)) + (export "as-br_if-first" (func 27)) + (export "as-br_if-last" (func 28)) + (export "as-br_table-first" (func 29)) + (export "as-br_table-last" (func 30)) + (export "as-call_indirect-first" (func 32)) + (export "as-call_indirect-mid" (func 33)) + (export "as-call_indirect-last" (func 34)) + (export "as-store-first" (func 35)) + (export "as-store-last" (func 36)) + (export "as-load-operand" (func 37)) + (export "as-memory.grow-value" (func 38)) + (export "as-call-value" (func 40)) + (export "as-return-value" (func 41)) + (export "as-drop-operand" (func 42)) + (export "as-br-value" (func 43)) + (export "as-local.set-value" (func 44)) + (export "as-local.tee-value" (func 45)) + (export "as-global.set-value" (func 46)) + (export "as-unary-operand" (func 47)) + (export "as-binary-operand" (func 48)) + (export "as-compare-operand" (func 49)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/global.wast/61.print b/tests/snapshots/testsuite/global.wast/61.print new file mode 100644 index 0000000000..bb29c81054 --- /dev/null +++ b/tests/snapshots/testsuite/global.wast/61.print @@ -0,0 +1,4 @@ +(module + (global (;0;) (mut f32) f32.const 0x0p+0 (;=0;)) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/global.wast/62.print b/tests/snapshots/testsuite/global.wast/62.print new file mode 100644 index 0000000000..bb29c81054 --- /dev/null +++ b/tests/snapshots/testsuite/global.wast/62.print @@ -0,0 +1,4 @@ +(module + (global (;0;) (mut f32) f32.const 0x0p+0 (;=0;)) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/global.wast/81.print b/tests/snapshots/testsuite/global.wast/81.print new file mode 100644 index 0000000000..ca7594713b --- /dev/null +++ b/tests/snapshots/testsuite/global.wast/81.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/global.wast/84.print b/tests/snapshots/testsuite/global.wast/84.print new file mode 100644 index 0000000000..e6b79c4e23 --- /dev/null +++ b/tests/snapshots/testsuite/global.wast/84.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/i32.wast/0.print b/tests/snapshots/testsuite/i32.wast/0.print new file mode 100644 index 0000000000..e1b9509260 --- /dev/null +++ b/tests/snapshots/testsuite/i32.wast/0.print @@ -0,0 +1,184 @@ +(module + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.add + ) + (func (;1;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.sub + ) + (func (;2;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.mul + ) + (func (;3;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.div_s + ) + (func (;4;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.div_u + ) + (func (;5;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.rem_s + ) + (func (;6;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.rem_u + ) + (func (;7;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.and + ) + (func (;8;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.or + ) + (func (;9;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.xor + ) + (func (;10;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.shl + ) + (func (;11;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.shr_s + ) + (func (;12;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.shr_u + ) + (func (;13;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.rotl + ) + (func (;14;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.rotr + ) + (func (;15;) (type 1) (param $x i32) (result i32) + local.get $x + i32.clz + ) + (func (;16;) (type 1) (param $x i32) (result i32) + local.get $x + i32.ctz + ) + (func (;17;) (type 1) (param $x i32) (result i32) + local.get $x + i32.popcnt + ) + (func (;18;) (type 1) (param $x i32) (result i32) + local.get $x + i32.extend8_s + ) + (func (;19;) (type 1) (param $x i32) (result i32) + local.get $x + i32.extend16_s + ) + (func (;20;) (type 1) (param $x i32) (result i32) + local.get $x + i32.eqz + ) + (func (;21;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.eq + ) + (func (;22;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.ne + ) + (func (;23;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.lt_s + ) + (func (;24;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.lt_u + ) + (func (;25;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.le_s + ) + (func (;26;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.le_u + ) + (func (;27;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.gt_s + ) + (func (;28;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.gt_u + ) + (func (;29;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.ge_s + ) + (func (;30;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + local.get $y + i32.ge_u + ) + (export "add" (func 0)) + (export "sub" (func 1)) + (export "mul" (func 2)) + (export "div_s" (func 3)) + (export "div_u" (func 4)) + (export "rem_s" (func 5)) + (export "rem_u" (func 6)) + (export "and" (func 7)) + (export "or" (func 8)) + (export "xor" (func 9)) + (export "shl" (func 10)) + (export "shr_s" (func 11)) + (export "shr_u" (func 12)) + (export "rotl" (func 13)) + (export "rotr" (func 14)) + (export "clz" (func 15)) + (export "ctz" (func 16)) + (export "popcnt" (func 17)) + (export "extend8_s" (func 18)) + (export "extend16_s" (func 19)) + (export "eqz" (func 20)) + (export "eq" (func 21)) + (export "ne" (func 22)) + (export "lt_s" (func 23)) + (export "lt_u" (func 24)) + (export "le_s" (func 25)) + (export "le_u" (func 26)) + (export "gt_s" (func 27)) + (export "gt_u" (func 28)) + (export "ge_s" (func 29)) + (export "ge_u" (func 30)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/i64.wast/0.print b/tests/snapshots/testsuite/i64.wast/0.print new file mode 100644 index 0000000000..947bf515ca --- /dev/null +++ b/tests/snapshots/testsuite/i64.wast/0.print @@ -0,0 +1,191 @@ +(module + (type (;0;) (func (param i64 i64) (result i64))) + (type (;1;) (func (param i64) (result i64))) + (type (;2;) (func (param i64) (result i32))) + (type (;3;) (func (param i64 i64) (result i32))) + (func (;0;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.add + ) + (func (;1;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.sub + ) + (func (;2;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.mul + ) + (func (;3;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.div_s + ) + (func (;4;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.div_u + ) + (func (;5;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.rem_s + ) + (func (;6;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.rem_u + ) + (func (;7;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.and + ) + (func (;8;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.or + ) + (func (;9;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.xor + ) + (func (;10;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.shl + ) + (func (;11;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.shr_s + ) + (func (;12;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.shr_u + ) + (func (;13;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.rotl + ) + (func (;14;) (type 0) (param $x i64) (param $y i64) (result i64) + local.get $x + local.get $y + i64.rotr + ) + (func (;15;) (type 1) (param $x i64) (result i64) + local.get $x + i64.clz + ) + (func (;16;) (type 1) (param $x i64) (result i64) + local.get $x + i64.ctz + ) + (func (;17;) (type 1) (param $x i64) (result i64) + local.get $x + i64.popcnt + ) + (func (;18;) (type 1) (param $x i64) (result i64) + local.get $x + i64.extend8_s + ) + (func (;19;) (type 1) (param $x i64) (result i64) + local.get $x + i64.extend16_s + ) + (func (;20;) (type 1) (param $x i64) (result i64) + local.get $x + i64.extend32_s + ) + (func (;21;) (type 2) (param $x i64) (result i32) + local.get $x + i64.eqz + ) + (func (;22;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.eq + ) + (func (;23;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.ne + ) + (func (;24;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.lt_s + ) + (func (;25;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.lt_u + ) + (func (;26;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.le_s + ) + (func (;27;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.le_u + ) + (func (;28;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.gt_s + ) + (func (;29;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.gt_u + ) + (func (;30;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.ge_s + ) + (func (;31;) (type 3) (param $x i64) (param $y i64) (result i32) + local.get $x + local.get $y + i64.ge_u + ) + (export "add" (func 0)) + (export "sub" (func 1)) + (export "mul" (func 2)) + (export "div_s" (func 3)) + (export "div_u" (func 4)) + (export "rem_s" (func 5)) + (export "rem_u" (func 6)) + (export "and" (func 7)) + (export "or" (func 8)) + (export "xor" (func 9)) + (export "shl" (func 10)) + (export "shr_s" (func 11)) + (export "shr_u" (func 12)) + (export "rotl" (func 13)) + (export "rotr" (func 14)) + (export "clz" (func 15)) + (export "ctz" (func 16)) + (export "popcnt" (func 17)) + (export "extend8_s" (func 18)) + (export "extend16_s" (func 19)) + (export "extend32_s" (func 20)) + (export "eqz" (func 21)) + (export "eq" (func 22)) + (export "ne" (func 23)) + (export "lt_s" (func 24)) + (export "lt_u" (func 25)) + (export "le_s" (func 26)) + (export "le_u" (func 27)) + (export "gt_s" (func 28)) + (export "gt_u" (func 29)) + (export "ge_s" (func 30)) + (export "ge_u" (func 31)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/if.wast/0.print b/tests/snapshots/testsuite/if.wast/0.print new file mode 100644 index 0000000000..148a4b8282 --- /dev/null +++ b/tests/snapshots/testsuite/if.wast/0.print @@ -0,0 +1,918 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type $block-sig-1 (;1;) (func)) + (type $block-sig-2 (;2;) (func (result i32))) + (type $block-sig-3 (;3;) (func (param i32))) + (type $block-sig-4 (;4;) (func (param i32 f64 i32) (result i32 f64 i32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i32) (result i32 i32))) + (type (;7;) (func (result i32 i64 i32))) + (type (;8;) (func (result i32 i32))) + (type (;9;) (func (result f32 f32))) + (type (;10;) (func (param i32) (result i32 i32 i64))) + (type (;11;) (func (result i32 i32 i64))) + (type (;12;) (func (param i32 i32) (result i32 i32))) + (type (;13;) (func (param i64 i64 i32) (result i64 i32))) + (type (;14;) (func (param i64 i64) (result i64))) + (type (;15;) (func (param i64) (result i64))) + (func $dummy (;0;) (type $block-sig-1)) + (func (;1;) (type $block-sig-3) (param i32) + local.get 0 + if ;; label = @1 + end + local.get 0 + if ;; label = @1 + else + end + local.get 0 + if $l ;; label = @1 + end + local.get 0 + if $l ;; label = @1 + else + end + ) + (func (;2;) (type 5) (param i32) (result i32) + local.get 0 + if ;; label = @1 + nop + end + local.get 0 + if ;; label = @1 + nop + else + nop + end + local.get 0 + if (result i32) ;; label = @1 + i32.const 7 + else + i32.const 8 + end + ) + (func (;3;) (type 6) (param i32) (result i32 i32) + local.get 0 + if ;; label = @1 + call $dummy + call $dummy + call $dummy + end + local.get 0 + if ;; label = @1 + else + call $dummy + call $dummy + call $dummy + end + local.get 0 + if (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 8 + call $dummy + else + call $dummy + call $dummy + i32.const 9 + call $dummy + end + local.get 0 + if (type 7) (result i32 i64 i32) ;; label = @1 + call $dummy + call $dummy + i32.const 1 + call $dummy + call $dummy + call $dummy + i64.const 2 + call $dummy + call $dummy + call $dummy + i32.const 3 + call $dummy + else + call $dummy + call $dummy + i32.const -1 + call $dummy + call $dummy + call $dummy + i64.const -2 + call $dummy + call $dummy + call $dummy + i32.const -3 + call $dummy + end + drop + drop + ) + (func (;4;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 1 + if ;; label = @2 + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if ;; label = @2 + else + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if (result i32) ;; label = @2 + call $dummy + i32.const 9 + else + call $dummy + i32.const 10 + end + else + local.get 1 + if ;; label = @2 + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if ;; label = @2 + else + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if (result i32) ;; label = @2 + call $dummy + i32.const 10 + else + call $dummy + i32.const 11 + end + end + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.const 3 + select + ) + (func (;6;) (type 5) (param i32) (result i32) + i32.const 2 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 3 + select + ) + (func (;7;) (type 5) (param i32) (result i32) + i32.const 2 + i32.const 3 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + select + ) + (func (;8;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call $dummy + call $dummy + end + ) + (func (;9;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call $dummy + end + ) + (func (;10;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + end + ) + (func (;11;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + if (result i32) ;; label = @1 + call $dummy + i32.const 2 + else + call $dummy + i32.const 3 + end + ) + (func (;12;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;13;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;14;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;15;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;16;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;17;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;18;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 0 + call_indirect (type $check) + end + ) + (func (;19;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call_indirect (type $check) + end + ) + (func (;20;) (type $block-sig-3) (param i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.store + ) + (func (;21;) (type $block-sig-3) (param i32) + i32.const 2 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.store + ) + (func (;22;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + memory.grow + ) + (func $f (;23;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;24;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + call $f + ) + (func (;25;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + return + ) + (func (;26;) (type $block-sig-3) (param i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + drop + ) + (func (;27;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + i32.const 1 + else + i32.const 0 + end + br 0 (;@1;) + end + ) + (func (;28;) (type 5) (param i32) (result i32) + (local i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + local.set 0 + local.get 0 + ) + (func (;29;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + local.tee 0 + ) + (func (;30;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + global.set $a + global.get $a + ) + (func (;31;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 11 + else + i32.const 10 + end + i32.load + ) + (func (;32;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 13 + else + call $dummy + i32.const -13 + end + i32.ctz + ) + (func (;33;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 3 + else + call $dummy + i32.const -3 + end + local.get 1 + if (result i32) ;; label = @1 + call $dummy + i32.const 4 + else + call $dummy + i32.const -5 + end + i32.mul + ) + (func (;34;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 13 + else + call $dummy + i32.const 0 + end + i32.eqz + ) + (func (;35;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + else + call $dummy + f32.const -0x1.8p+1 (;=-3;) + end + local.get 1 + if (result f32) ;; label = @1 + call $dummy + f32.const 0x1p+2 (;=4;) + else + call $dummy + f32.const -0x1p+2 (;=-4;) + end + f32.gt + ) + (func (;36;) (type 5) (param i32) (result i32) + local.get 0 + if (type 8) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + else + call $dummy + i32.const 3 + call $dummy + i32.const -4 + end + i32.mul + ) + (func (;37;) (type 5) (param i32) (result i32) + local.get 0 + if (type 9) (result f32 f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + call $dummy + f32.const 0x1.8p+1 (;=3;) + else + call $dummy + f32.const -0x1p+1 (;=-2;) + call $dummy + f32.const -0x1.8p+1 (;=-3;) + end + f32.gt + ) + (func (;38;) (type 5) (param i32) (result i32) + local.get 0 + if (type 8) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + else + call $dummy + i32.const -3 + call $dummy + i32.const -4 + end + i32.const 5 + i32.add + i32.mul + ) + (func (;39;) (type $block-sig-2) (result i32) + i32.const 1 + if ;; label = @1 + br 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + br 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + br 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 1 + br_if 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 1 + br_if 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + i32.const 1 + br_if 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + i32.const 0 + br_table 0 (;@1;) + unreachable + end + i32.const 19 + ) + (func (;40;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 18 + br 0 (;@1;) + i32.const 19 + else + i32.const 21 + br 0 (;@1;) + i32.const 20 + end + ) + (func (;41;) (type 10) (param i32) (result i32 i32 i64) + local.get 0 + if (type 11) (result i32 i32 i64) ;; label = @1 + i32.const 18 + i32.const -18 + i64.const 18 + br 0 (;@1;) + i32.const 19 + i32.const -19 + i64.const 19 + else + i32.const -18 + i32.const 18 + i64.const -18 + br 0 (;@1;) + i32.const -19 + i32.const 19 + i64.const -19 + end + ) + (func (;42;) (type 5) (param i32) (result i32) + i32.const 1 + local.get 0 + if (type 5) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + else + i32.const -2 + i32.add + end + ) + (func (;43;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + else + i32.sub + end + ) + (func (;44;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type 12) (param i32 i32) (result i32 i32) ;; label = @1 + end + i32.add + ) + (func (;45;) (type 5) (param i32) (result i32) + i32.const 1 + local.get 0 + if (type 5) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + br 0 (;@1;) + else + i32.const -2 + i32.add + br 0 (;@1;) + end + ) + (func (;46;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + br 0 (;@1;) + else + i32.sub + br 0 (;@1;) + end + ) + (func (;47;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type 12) (param i32 i32) (result i32 i32) ;; label = @1 + br 0 (;@1;) + end + i32.add + ) + (func (;48;) (type 5) (param i32) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + local.set 1 + local.get 0 + end + if ;; label = @1 + local.get 1 + i32.const 3 + i32.mul + local.set 1 + local.get 1 + i32.const 5 + i32.sub + local.set 1 + local.get 1 + i32.const 7 + i32.mul + local.set 1 + br 0 (;@1;) + local.get 1 + i32.const 100 + i32.mul + local.set 1 + else + local.get 1 + i32.const 5 + i32.mul + local.set 1 + local.get 1 + i32.const 7 + i32.sub + local.set 1 + local.get 1 + i32.const 3 + i32.mul + local.set 1 + br 0 (;@1;) + local.get 1 + i32.const 1000 + i32.mul + local.set 1 + end + local.get 1 + ) + (func $add64_u_with_carry (;49;) (type 13) (param $i i64) (param $j i64) (param $c i32) (result i64 i32) + (local $k i64) + local.get $i + local.get $j + i64.add + local.get $c + i64.extend_i32_u + i64.add + local.set $k + local.get $k + local.get $k + local.get $i + i64.lt_u + return + ) + (func $add64_u_saturated (;50;) (type 14) (param i64 i64) (result i64) + local.get 0 + local.get 1 + i32.const 0 + call $add64_u_with_carry + if (type 15) (param i64) (result i64) ;; label = @1 + drop + i64.const -1 + end + ) + (func (;51;) (type $block-sig-1) + i32.const 1 + if (type $block-sig-1) ;; label = @1 + end + i32.const 1 + if (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + else + i32.const 2 + end + i32.const 1 + if (type $block-sig-3) (param i32) ;; label = @1 + drop + else + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 1 + if (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + i32.const 1 + if (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + else + i32.const 2 + end + i32.const 1 + if (type $block-sig-3) (param i32) ;; label = @1 + drop + else + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 1 + if (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "empty" (func 1)) + (export "singular" (func 2)) + (export "multi" (func 3)) + (export "nested" (func 4)) + (export "as-select-first" (func 5)) + (export "as-select-mid" (func 6)) + (export "as-select-last" (func 7)) + (export "as-loop-first" (func 8)) + (export "as-loop-mid" (func 9)) + (export "as-loop-last" (func 10)) + (export "as-if-condition" (func 11)) + (export "as-br_if-first" (func 12)) + (export "as-br_if-last" (func 13)) + (export "as-br_table-first" (func 14)) + (export "as-br_table-last" (func 15)) + (export "as-call_indirect-first" (func 17)) + (export "as-call_indirect-mid" (func 18)) + (export "as-call_indirect-last" (func 19)) + (export "as-store-first" (func 20)) + (export "as-store-last" (func 21)) + (export "as-memory.grow-value" (func 22)) + (export "as-call-value" (func 24)) + (export "as-return-value" (func 25)) + (export "as-drop-operand" (func 26)) + (export "as-br-value" (func 27)) + (export "as-local.set-value" (func 28)) + (export "as-local.tee-value" (func 29)) + (export "as-global.set-value" (func 30)) + (export "as-load-operand" (func 31)) + (export "as-unary-operand" (func 32)) + (export "as-binary-operand" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-operand" (func 35)) + (export "as-binary-operands" (func 36)) + (export "as-compare-operands" (func 37)) + (export "as-mixed-operands" (func 38)) + (export "break-bare" (func 39)) + (export "break-value" (func 40)) + (export "break-multi-value" (func 41)) + (export "param" (func 42)) + (export "params" (func 43)) + (export "params-id" (func 44)) + (export "param-break" (func 45)) + (export "params-break" (func 46)) + (export "params-id-break" (func 47)) + (export "effects" (func 48)) + (export "add64_u_with_carry" (func $add64_u_with_carry)) + (export "add64_u_saturated" (func $add64_u_saturated)) + (export "type-use" (func 51)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/0.print b/tests/snapshots/testsuite/imports.wast/0.print new file mode 100644 index 0000000000..08ee68f308 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/0.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (result i32))) + (type (;4;) (func (result f32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i64) (result i64))) + (func (;0;) (type 0)) + (func (;1;) (type 1) (param i32)) + (func (;2;) (type 2) (param f32)) + (func (;3;) (type 3) (result i32) + i32.const 22 + ) + (func (;4;) (type 4) (result f32) + f32.const 0x1.6p+3 (;=11;) + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;6;) (type 6) (param i64) (result i64) + local.get 0 + ) + (table (;0;) 10 funcref) + (table (;1;) 10 20 funcref) + (memory (;0;) 2) + (global (;0;) i32 i32.const 55) + (global (;1;) f32 f32.const 0x1.6p+5 (;=44;)) + (global (;2;) (mut i64) i64.const 66) + (export "func" (func 0)) + (export "func-i32" (func 1)) + (export "func-f32" (func 2)) + (export "func->i32" (func 3)) + (export "func->f32" (func 4)) + (export "func-i32->i32" (func 5)) + (export "func-i64->i64" (func 6)) + (export "global-i32" (global 0)) + (export "global-f32" (global 1)) + (export "global-mut-i64" (global 2)) + (export "table-10-inf" (table 0)) + (export "table-10-20" (table 1)) + (export "memory-2-inf" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/10.print b/tests/snapshots/testsuite/imports.wast/10.print new file mode 100644 index 0000000000..22a02a9053 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/10.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (import "test" "func" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/100.print b/tests/snapshots/testsuite/imports.wast/100.print new file mode 100644 index 0000000000..9c95837f51 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/100.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/101.print b/tests/snapshots/testsuite/imports.wast/101.print new file mode 100644 index 0000000000..45fc077841 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/101.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/11.print b/tests/snapshots/testsuite/imports.wast/11.print new file mode 100644 index 0000000000..782997f244 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/11.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "test" "func-i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/114.print b/tests/snapshots/testsuite/imports.wast/114.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/114.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/119.print b/tests/snapshots/testsuite/imports.wast/119.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/119.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/12.print b/tests/snapshots/testsuite/imports.wast/12.print new file mode 100644 index 0000000000..ace1d7c959 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/12.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param f32))) + (import "test" "func-f32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/127.print b/tests/snapshots/testsuite/imports.wast/127.print new file mode 100644 index 0000000000..1aad2d0f8d --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/127.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/128.print b/tests/snapshots/testsuite/imports.wast/128.print new file mode 100644 index 0000000000..546d8eaedc --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/128.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/129.print b/tests/snapshots/testsuite/imports.wast/129.print new file mode 100644 index 0000000000..e40926e430 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/129.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/13.print b/tests/snapshots/testsuite/imports.wast/13.print new file mode 100644 index 0000000000..0744a46fba --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/13.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (result i32))) + (import "test" "func->i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/130.print b/tests/snapshots/testsuite/imports.wast/130.print new file mode 100644 index 0000000000..3c97146026 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/130.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/131.print b/tests/snapshots/testsuite/imports.wast/131.print new file mode 100644 index 0000000000..83efcab834 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/131.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/132.print b/tests/snapshots/testsuite/imports.wast/132.print new file mode 100644 index 0000000000..404698c724 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/132.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/133.print b/tests/snapshots/testsuite/imports.wast/133.print new file mode 100644 index 0000000000..39db875587 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/133.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/134.print b/tests/snapshots/testsuite/imports.wast/134.print new file mode 100644 index 0000000000..897e9b716b --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/134.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/135.print b/tests/snapshots/testsuite/imports.wast/135.print new file mode 100644 index 0000000000..c0d28c6be7 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/135.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/14.print b/tests/snapshots/testsuite/imports.wast/14.print new file mode 100644 index 0000000000..3b07b2a04c --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/14.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (result f32))) + (import "test" "func->f32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/15.print b/tests/snapshots/testsuite/imports.wast/15.print new file mode 100644 index 0000000000..e6ddafe344 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/15.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "test" "func-i32->i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/150.print b/tests/snapshots/testsuite/imports.wast/150.print new file mode 100644 index 0000000000..73ee1fb50c --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/150.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 0 3)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/156.print b/tests/snapshots/testsuite/imports.wast/156.print new file mode 100644 index 0000000000..7efe25f1d8 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/156.print @@ -0,0 +1,10 @@ +(module $Mgm + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + memory.grow + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/159.print b/tests/snapshots/testsuite/imports.wast/159.print new file mode 100644 index 0000000000..477ca763be --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/159.print @@ -0,0 +1,10 @@ +(module $Mgim1 + (type (;0;) (func (result i32))) + (import "grown-memory" "memory" (memory (;0;) 2)) + (func (;0;) (type 0) (result i32) + i32.const 1 + memory.grow + ) + (export "memory" (memory 0)) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/16.print b/tests/snapshots/testsuite/imports.wast/16.print new file mode 100644 index 0000000000..c5ca6af197 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/16.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (import "test" "func-i64->i64" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/162.print b/tests/snapshots/testsuite/imports.wast/162.print new file mode 100644 index 0000000000..80793cacec --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/162.print @@ -0,0 +1,8 @@ +(module $Mgim2 + (type (;0;) (func (result i32))) + (import "grown-imported-memory" "memory" (memory (;0;) 3)) + (func (;0;) (type 0) (result i32) + memory.size + ) + (export "size" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/180.print b/tests/snapshots/testsuite/imports.wast/180.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/180.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/2.print b/tests/snapshots/testsuite/imports.wast/2.print new file mode 100644 index 0000000000..2387bf04da --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/2.print @@ -0,0 +1,83 @@ +(module + (type $func_i32 (;0;) (func (param i32))) + (type $func_i64 (;1;) (func (param i64))) + (type $func_f32 (;2;) (func (param f32))) + (type $func_f64 (;3;) (func (param f64))) + (type $forward (;4;) (func (param i32))) + (type (;5;) (func (param i32 f32))) + (type (;6;) (func (param f64 f64))) + (type (;7;) (func (param i64) (result i64))) + (import "spectest" "print_i32" (func (;0;) (type $func_i32))) + (import "spectest" "print_i64" (func (;1;) (type $func_i64))) + (import "spectest" "print_i32" (func $print_i32 (;2;) (type $func_i32))) + (import "spectest" "print_i64" (func $print_i64 (;3;) (type $func_i64))) + (import "spectest" "print_f32" (func $print_f32 (;4;) (type $func_f32))) + (import "spectest" "print_f64" (func $print_f64 (;5;) (type $func_f64))) + (import "spectest" "print_i32_f32" (func $print_i32_f32 (;6;) (type 5))) + (import "spectest" "print_f64_f64" (func $print_f64_f64 (;7;) (type 6))) + (import "spectest" "print_i32" (func $print_i32-2 (;8;) (type $func_i32))) + (import "spectest" "print_f64" (func $print_f64-2 (;9;) (type $func_f64))) + (import "test" "func-i64->i64" (func $i64->i64 (;10;) (type 7))) + (import "spectest" "print_i32" (func (;11;) (type $func_i32))) + (import "spectest" "print_i32" (func $p (;12;) (type $func_i32))) + (import "spectest" "print_i32" (func (;13;) (type $func_i32))) + (import "spectest" "print_i32" (func (;14;) (type $func_i32))) + (import "spectest" "print_i32" (func (;15;) (type $func_i32))) + (import "spectest" "print_i32" (func (;16;) (type $forward))) + (import "spectest" "print_i32" (func (;17;) (type $forward))) + (func (;18;) (type $func_i32) (param $i i32) + (local $x f32) + local.get $i + f32.convert_i32_s + local.set $x + local.get $i + call 0 + local.get $i + i32.const 1 + i32.add + f32.const 0x1.5p+5 (;=42;) + call $print_i32_f32 + local.get $i + call $print_i32 + local.get $i + call $print_i32-2 + local.get $x + call $print_f32 + local.get $i + i32.const 0 + call_indirect (type $func_i32) + ) + (func (;19;) (type $func_i64) (param $i i64) + (local $x f64) + local.get $i + call $i64->i64 + f64.convert_i64_s + local.set $x + local.get $i + call 1 + local.get $x + f64.const 0x1p+0 (;=1;) + f64.add + f64.const 0x1.a8p+5 (;=53;) + call $print_f64_f64 + local.get $i + call $print_i64 + local.get $x + call $print_f64 + local.get $x + call $print_f64-2 + local.get $x + i32.const 1 + call_indirect (type $func_f64) + ) + (table (;0;) 2 2 funcref) + (export "p1" (func 11)) + (export "p2" (func $p)) + (export "p3" (func 13)) + (export "p4" (func 13)) + (export "p5" (func 14)) + (export "p6" (func 15)) + (export "print32" (func 18)) + (export "print64" (func 19)) + (elem (;0;) (i32.const 0) func $print_i32 $print_f64) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/41.print b/tests/snapshots/testsuite/imports.wast/41.print new file mode 100644 index 0000000000..0693cbec34 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/41.print @@ -0,0 +1,26 @@ +(module + (type (;0;) (func (result i32))) + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "global_i32" (global (;1;) i32)) + (import "spectest" "global_i32" (global $x (;2;) i32)) + (import "spectest" "global_i32" (global $y (;3;) i32)) + (import "spectest" "global_i64" (global (;4;) i64)) + (import "spectest" "global_f32" (global (;5;) f32)) + (import "spectest" "global_f64" (global (;6;) f64)) + (func (;0;) (type 0) (result i32) + global.get 0 + ) + (func (;1;) (type 0) (result i32) + global.get 1 + ) + (func (;2;) (type 0) (result i32) + global.get $x + ) + (func (;3;) (type 0) (result i32) + global.get $y + ) + (export "get-0" (func 0)) + (export "get-1" (func 1)) + (export "get-x" (func 2)) + (export "get-y" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/46.print b/tests/snapshots/testsuite/imports.wast/46.print new file mode 100644 index 0000000000..1b1739a096 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/46.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-i32" (global (;0;) i32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/47.print b/tests/snapshots/testsuite/imports.wast/47.print new file mode 100644 index 0000000000..eae7b7643b --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/47.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-f32" (global (;0;) f32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/48.print b/tests/snapshots/testsuite/imports.wast/48.print new file mode 100644 index 0000000000..8cff34a430 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/48.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-mut-i64" (global (;0;) (mut i64))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/6.print b/tests/snapshots/testsuite/imports.wast/6.print new file mode 100644 index 0000000000..63910ab9f5 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/6.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func $imported_print (;0;) (type 0))) + (func (;1;) (type 0) (param $i i32) + local.get $i + call $imported_print + ) + (export "print_i32" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/69.print b/tests/snapshots/testsuite/imports.wast/69.print new file mode 100644 index 0000000000..d06f6c7555 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/69.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "spectest" "table" (table $tab (;0;) 10 20 funcref)) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func $f (;1;) (type 0) (result i32) + i32.const 11 + ) + (func $g (;2;) (type 0) (result i32) + i32.const 22 + ) + (export "call" (func 0)) + (elem (;0;) (i32.const 1) func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/75.print b/tests/snapshots/testsuite/imports.wast/75.print new file mode 100644 index 0000000000..d06f6c7555 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/75.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "spectest" "table" (table $tab (;0;) 10 20 funcref)) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func $f (;1;) (type 0) (result i32) + i32.const 11 + ) + (func $g (;2;) (type 0) (result i32) + i32.const 22 + ) + (export "call" (func 0)) + (elem (;0;) (i32.const 1) func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/8.print b/tests/snapshots/testsuite/imports.wast/8.print new file mode 100644 index 0000000000..a93289d203 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/8.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (import "spectest" "print_i32" (func $imported_print (;0;) (type 0))) + (func (;1;) (type 1) (param $i i32) (param $j i32) (result i32) + local.get $i + local.get $j + i32.add + ) + (export "print_i32" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/81.print b/tests/snapshots/testsuite/imports.wast/81.print new file mode 100644 index 0000000000..9dfcbda865 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/81.print @@ -0,0 +1,6 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (import "spectest" "table" (table (;1;) 0 funcref)) + (table (;2;) 10 funcref) + (table (;3;) 10 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/82.print b/tests/snapshots/testsuite/imports.wast/82.print new file mode 100644 index 0000000000..72f38c2e80 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/82.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/83.print b/tests/snapshots/testsuite/imports.wast/83.print new file mode 100644 index 0000000000..475c251b6e --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/83.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/84.print b/tests/snapshots/testsuite/imports.wast/84.print new file mode 100644 index 0000000000..c8997038cb --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/84.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/85.print b/tests/snapshots/testsuite/imports.wast/85.print new file mode 100644 index 0000000000..f1e8559446 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/85.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/86.print b/tests/snapshots/testsuite/imports.wast/86.print new file mode 100644 index 0000000000..4eca2099fe --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/86.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/87.print b/tests/snapshots/testsuite/imports.wast/87.print new file mode 100644 index 0000000000..18937c5d00 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/87.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/88.print b/tests/snapshots/testsuite/imports.wast/88.print new file mode 100644 index 0000000000..affb91adc7 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/88.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/89.print b/tests/snapshots/testsuite/imports.wast/89.print new file mode 100644 index 0000000000..b27d0a1814 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/89.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/90.print b/tests/snapshots/testsuite/imports.wast/90.print new file mode 100644 index 0000000000..d40ae2d3a4 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/90.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/91.print b/tests/snapshots/testsuite/imports.wast/91.print new file mode 100644 index 0000000000..eea2b23b56 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/91.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/92.print b/tests/snapshots/testsuite/imports.wast/92.print new file mode 100644 index 0000000000..339f1e02ed --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/92.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/93.print b/tests/snapshots/testsuite/imports.wast/93.print new file mode 100644 index 0000000000..5c845b5cc2 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/93.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/94.print b/tests/snapshots/testsuite/imports.wast/94.print new file mode 100644 index 0000000000..64a52acf28 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/94.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/95.print b/tests/snapshots/testsuite/imports.wast/95.print new file mode 100644 index 0000000000..218d7d9bdc --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/95.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/96.print b/tests/snapshots/testsuite/imports.wast/96.print new file mode 100644 index 0000000000..2a0fa834a7 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/96.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/97.print b/tests/snapshots/testsuite/imports.wast/97.print new file mode 100644 index 0000000000..03446a5f52 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/97.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/98.print b/tests/snapshots/testsuite/imports.wast/98.print new file mode 100644 index 0000000000..d1cff0037a --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/98.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/imports.wast/99.print b/tests/snapshots/testsuite/imports.wast/99.print new file mode 100644 index 0000000000..65ae983998 --- /dev/null +++ b/tests/snapshots/testsuite/imports.wast/99.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 0 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/inline-module.wast/0.print b/tests/snapshots/testsuite/inline-module.wast/0.print new file mode 100644 index 0000000000..439287fa50 --- /dev/null +++ b/tests/snapshots/testsuite/inline-module.wast/0.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) + (memory (;0;) 0) + (export "f" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/0.print b/tests/snapshots/testsuite/int_exprs.wast/0.print new file mode 100644 index 0000000000..a4de12fe55 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/0.print @@ -0,0 +1,44 @@ +(module + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i64 i64) (result i32))) + (func (;0;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + i32.const 1 + i32.add + local.get $y + i32.const 1 + i32.add + i32.lt_s + ) + (func (;1;) (type 0) (param $x i32) (param $y i32) (result i32) + local.get $x + i32.const 1 + i32.add + local.get $y + i32.const 1 + i32.add + i32.lt_u + ) + (func (;2;) (type 1) (param $x i64) (param $y i64) (result i32) + local.get $x + i64.const 1 + i64.add + local.get $y + i64.const 1 + i64.add + i64.lt_s + ) + (func (;3;) (type 1) (param $x i64) (param $y i64) (result i32) + local.get $x + i64.const 1 + i64.add + local.get $y + i64.const 1 + i64.add + i64.lt_u + ) + (export "i32.no_fold_cmp_s_offset" (func 0)) + (export "i32.no_fold_cmp_u_offset" (func 1)) + (export "i64.no_fold_cmp_s_offset" (func 2)) + (export "i64.no_fold_cmp_u_offset" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/10.print b/tests/snapshots/testsuite/int_exprs.wast/10.print new file mode 100644 index 0000000000..a30edd784f --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/10.print @@ -0,0 +1,36 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 1 + i32.shl + i32.const 1 + i32.shr_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 1 + i32.shl + i32.const 1 + i32.shr_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 1 + i64.shl + i64.const 1 + i64.shr_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 1 + i64.shl + i64.const 1 + i64.shr_u + ) + (export "i32.no_fold_shl_shr_s" (func 0)) + (export "i32.no_fold_shl_shr_u" (func 1)) + (export "i64.no_fold_shl_shr_s" (func 2)) + (export "i64.no_fold_shl_shr_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/105.print b/tests/snapshots/testsuite/int_exprs.wast/105.print new file mode 100644 index 0000000000..decdee7c1f --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/105.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const -1 + i32.div_s + ) + (func (;1;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const -1 + i64.div_s + ) + (export "i32.no_fold_div_neg1" (func 0)) + (export "i64.no_fold_div_neg1" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/15.print b/tests/snapshots/testsuite/int_exprs.wast/15.print new file mode 100644 index 0000000000..b7a6ff8b71 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/15.print @@ -0,0 +1,36 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 1 + i32.shr_s + i32.const 1 + i32.shl + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 1 + i32.shr_u + i32.const 1 + i32.shl + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 1 + i64.shr_s + i64.const 1 + i64.shl + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 1 + i64.shr_u + i64.const 1 + i64.shl + ) + (export "i32.no_fold_shr_s_shl" (func 0)) + (export "i32.no_fold_shr_u_shl" (func 1)) + (export "i64.no_fold_shr_s_shl" (func 2)) + (export "i64.no_fold_shr_u_shl" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/20.print b/tests/snapshots/testsuite/int_exprs.wast/20.print new file mode 100644 index 0000000000..e128104751 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/20.print @@ -0,0 +1,36 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 6 + i32.div_s + i32.const 6 + i32.mul + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 6 + i32.div_u + i32.const 6 + i32.mul + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 6 + i64.div_s + i64.const 6 + i64.mul + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 6 + i64.div_u + i64.const 6 + i64.mul + ) + (export "i32.no_fold_div_s_mul" (func 0)) + (export "i32.no_fold_div_u_mul" (func 1)) + (export "i64.no_fold_div_s_mul" (func 2)) + (export "i64.no_fold_div_u_mul" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/25.print b/tests/snapshots/testsuite/int_exprs.wast/25.print new file mode 100644 index 0000000000..3f7d9e49c4 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/25.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + local.get $x + i32.div_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + local.get $x + i32.div_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + local.get $x + i64.div_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + local.get $x + i64.div_u + ) + (export "i32.no_fold_div_s_self" (func 0)) + (export "i32.no_fold_div_u_self" (func 1)) + (export "i64.no_fold_div_s_self" (func 2)) + (export "i64.no_fold_div_u_self" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/30.print b/tests/snapshots/testsuite/int_exprs.wast/30.print new file mode 100644 index 0000000000..56b9b8399e --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/30.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + local.get $x + i32.rem_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + local.get $x + i32.rem_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + local.get $x + i64.rem_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + local.get $x + i64.rem_u + ) + (export "i32.no_fold_rem_s_self" (func 0)) + (export "i32.no_fold_rem_u_self" (func 1)) + (export "i64.no_fold_rem_s_self" (func 2)) + (export "i64.no_fold_rem_u_self" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/35.print b/tests/snapshots/testsuite/int_exprs.wast/35.print new file mode 100644 index 0000000000..a5f5befee5 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/35.print @@ -0,0 +1,36 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 6 + i32.mul + i32.const 6 + i32.div_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 6 + i32.mul + i32.const 6 + i32.div_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 6 + i64.mul + i64.const 6 + i64.div_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 6 + i64.mul + i64.const 6 + i64.div_u + ) + (export "i32.no_fold_mul_div_s" (func 0)) + (export "i32.no_fold_mul_div_u" (func 1)) + (export "i64.no_fold_mul_div_s" (func 2)) + (export "i64.no_fold_mul_div_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/40.print b/tests/snapshots/testsuite/int_exprs.wast/40.print new file mode 100644 index 0000000000..e35bbe6a1b --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/40.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 2 + i32.div_s + ) + (func (;1;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 2 + i64.div_s + ) + (export "i32.no_fold_div_s_2" (func 0)) + (export "i64.no_fold_div_s_2" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/43.print b/tests/snapshots/testsuite/int_exprs.wast/43.print new file mode 100644 index 0000000000..0e10c6ffc6 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/43.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 2 + i32.rem_s + ) + (func (;1;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 2 + i64.rem_s + ) + (export "i32.no_fold_rem_s_2" (func 0)) + (export "i64.no_fold_rem_s_2" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/46.print b/tests/snapshots/testsuite/int_exprs.wast/46.print new file mode 100644 index 0000000000..9946e69510 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/46.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 0 + i32.div_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 0 + i32.div_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 0 + i64.div_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 0 + i64.div_u + ) + (export "i32.div_s_0" (func 0)) + (export "i32.div_u_0" (func 1)) + (export "i64.div_s_0" (func 2)) + (export "i64.div_u_0" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/5.print b/tests/snapshots/testsuite/int_exprs.wast/5.print new file mode 100644 index 0000000000..5bd45e372b --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/5.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i64) (result i64) + local.get $x + i32.wrap_i64 + i64.extend_i32_s + ) + (export "i64.no_fold_wrap_extend_s" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/51.print b/tests/snapshots/testsuite/int_exprs.wast/51.print new file mode 100644 index 0000000000..ef40e749cf --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/51.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 3 + i32.div_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 3 + i32.div_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 3 + i64.div_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 3 + i64.div_u + ) + (export "i32.div_s_3" (func 0)) + (export "i32.div_u_3" (func 1)) + (export "i64.div_s_3" (func 2)) + (export "i64.div_u_3" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/60.print b/tests/snapshots/testsuite/int_exprs.wast/60.print new file mode 100644 index 0000000000..da80cea801 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/60.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 5 + i32.div_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 5 + i32.div_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 5 + i64.div_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 5 + i64.div_u + ) + (export "i32.div_s_5" (func 0)) + (export "i32.div_u_5" (func 1)) + (export "i64.div_s_5" (func 2)) + (export "i64.div_u_5" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/69.print b/tests/snapshots/testsuite/int_exprs.wast/69.print new file mode 100644 index 0000000000..51e01f233d --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/69.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 7 + i32.div_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 7 + i32.div_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 7 + i64.div_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 7 + i64.div_u + ) + (export "i32.div_s_7" (func 0)) + (export "i32.div_u_7" (func 1)) + (export "i64.div_s_7" (func 2)) + (export "i64.div_u_7" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/78.print b/tests/snapshots/testsuite/int_exprs.wast/78.print new file mode 100644 index 0000000000..586e8f6a87 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/78.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 3 + i32.rem_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 3 + i32.rem_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 3 + i64.rem_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 3 + i64.rem_u + ) + (export "i32.rem_s_3" (func 0)) + (export "i32.rem_u_3" (func 1)) + (export "i64.rem_s_3" (func 2)) + (export "i64.rem_u_3" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/8.print b/tests/snapshots/testsuite/int_exprs.wast/8.print new file mode 100644 index 0000000000..8bc9b71496 --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/8.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i64) (result i64) + local.get $x + i32.wrap_i64 + i64.extend_i32_u + ) + (export "i64.no_fold_wrap_extend_u" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/87.print b/tests/snapshots/testsuite/int_exprs.wast/87.print new file mode 100644 index 0000000000..a3ca21a2ac --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/87.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 5 + i32.rem_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 5 + i32.rem_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 5 + i64.rem_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 5 + i64.rem_u + ) + (export "i32.rem_s_5" (func 0)) + (export "i32.rem_u_5" (func 1)) + (export "i64.rem_s_5" (func 2)) + (export "i64.rem_u_5" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_exprs.wast/96.print b/tests/snapshots/testsuite/int_exprs.wast/96.print new file mode 100644 index 0000000000..ed86fa961e --- /dev/null +++ b/tests/snapshots/testsuite/int_exprs.wast/96.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 7 + i32.rem_s + ) + (func (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 7 + i32.rem_u + ) + (func (;2;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 7 + i64.rem_s + ) + (func (;3;) (type 1) (param $x i64) (result i64) + local.get $x + i64.const 7 + i64.rem_u + ) + (export "i32.rem_s_7" (func 0)) + (export "i32.rem_u_7" (func 1)) + (export "i64.rem_s_7" (func 2)) + (export "i64.rem_u_7" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/int_literals.wast/0.print b/tests/snapshots/testsuite/int_literals.wast/0.print new file mode 100644 index 0000000000..1ae64147b1 --- /dev/null +++ b/tests/snapshots/testsuite/int_literals.wast/0.print @@ -0,0 +1,150 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (func (;0;) (type 0) (result i32) + i32.const 195940365 + return + ) + (func (;1;) (type 0) (result i32) + i32.const -1 + return + ) + (func (;2;) (type 0) (result i32) + i32.const 2147483647 + return + ) + (func (;3;) (type 0) (result i32) + i32.const -2147483647 + return + ) + (func (;4;) (type 0) (result i32) + i32.const -2147483648 + return + ) + (func (;5;) (type 0) (result i32) + i32.const -2147483648 + return + ) + (func (;6;) (type 0) (result i32) + i32.const -2147483648 + i32.const 1 + i32.add + return + ) + (func (;7;) (type 0) (result i32) + i32.const 0 + return + ) + (func (;8;) (type 0) (result i32) + i32.const 10 + return + ) + (func (;9;) (type 0) (result i32) + i32.const -1 + return + ) + (func (;10;) (type 0) (result i32) + i32.const 42 + return + ) + (func (;11;) (type 1) (result i64) + i64.const 913028331277281902 + return + ) + (func (;12;) (type 1) (result i64) + i64.const -1 + return + ) + (func (;13;) (type 1) (result i64) + i64.const 9223372036854775807 + return + ) + (func (;14;) (type 1) (result i64) + i64.const -9223372036854775807 + return + ) + (func (;15;) (type 1) (result i64) + i64.const -9223372036854775808 + return + ) + (func (;16;) (type 1) (result i64) + i64.const -9223372036854775808 + return + ) + (func (;17;) (type 1) (result i64) + i64.const -9223372036854775808 + i64.const 1 + i64.add + return + ) + (func (;18;) (type 1) (result i64) + i64.const 0 + return + ) + (func (;19;) (type 1) (result i64) + i64.const 10 + return + ) + (func (;20;) (type 1) (result i64) + i64.const -1 + return + ) + (func (;21;) (type 1) (result i64) + i64.const 42 + return + ) + (func (;22;) (type 0) (result i32) + i32.const 1000000 + ) + (func (;23;) (type 0) (result i32) + i32.const 1000 + ) + (func (;24;) (type 0) (result i32) + i32.const 168755353 + ) + (func (;25;) (type 0) (result i32) + i32.const 109071 + ) + (func (;26;) (type 1) (result i64) + i64.const 1000000 + ) + (func (;27;) (type 1) (result i64) + i64.const 1000 + ) + (func (;28;) (type 1) (result i64) + i64.const 3078696982321561 + ) + (func (;29;) (type 1) (result i64) + i64.const 109071 + ) + (export "i32.test" (func 0)) + (export "i32.umax" (func 1)) + (export "i32.smax" (func 2)) + (export "i32.neg_smax" (func 3)) + (export "i32.smin" (func 4)) + (export "i32.alt_smin" (func 5)) + (export "i32.inc_smin" (func 6)) + (export "i32.neg_zero" (func 7)) + (export "i32.not_octal" (func 8)) + (export "i32.unsigned_decimal" (func 9)) + (export "i32.plus_sign" (func 10)) + (export "i64.test" (func 11)) + (export "i64.umax" (func 12)) + (export "i64.smax" (func 13)) + (export "i64.neg_smax" (func 14)) + (export "i64.smin" (func 15)) + (export "i64.alt_smin" (func 16)) + (export "i64.inc_smin" (func 17)) + (export "i64.neg_zero" (func 18)) + (export "i64.not_octal" (func 19)) + (export "i64.unsigned_decimal" (func 20)) + (export "i64.plus_sign" (func 21)) + (export "i32-dec-sep1" (func 22)) + (export "i32-dec-sep2" (func 23)) + (export "i32-hex-sep1" (func 24)) + (export "i32-hex-sep2" (func 25)) + (export "i64-dec-sep1" (func 26)) + (export "i64-dec-sep2" (func 27)) + (export "i64-hex-sep1" (func 28)) + (export "i64-hex-sep2" (func 29)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/labels.wast/0.print b/tests/snapshots/testsuite/labels.wast/0.print new file mode 100644 index 0000000000..b370a57b62 --- /dev/null +++ b/tests/snapshots/testsuite/labels.wast/0.print @@ -0,0 +1,456 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (result i32) + block $exit (result i32) ;; label = @1 + i32.const 1 + br 0 (;@1;) + i32.const 0 + end + ) + (func (;1;) (type 0) (result i32) + (local $i i32) + i32.const 0 + local.set $i + block $exit (result i32) ;; label = @1 + loop $cont (result i32) ;; label = @2 + local.get $i + i32.const 1 + i32.add + local.set $i + local.get $i + i32.const 5 + i32.eq + if ;; label = @3 + local.get $i + br 2 (;@1;) + end + br 0 (;@2;) + end + end + ) + (func (;2;) (type 0) (result i32) + (local $i i32) + i32.const 0 + local.set $i + block $exit (result i32) ;; label = @1 + loop $cont (result i32) ;; label = @2 + local.get $i + i32.const 1 + i32.add + local.set $i + local.get $i + i32.const 5 + i32.eq + if ;; label = @3 + br 1 (;@2;) + end + local.get $i + i32.const 8 + i32.eq + if ;; label = @3 + local.get $i + br 2 (;@1;) + end + local.get $i + i32.const 1 + i32.add + local.set $i + br 0 (;@2;) + end + end + ) + (func (;3;) (type 0) (result i32) + (local $i i32) + i32.const 0 + local.set $i + block $exit (result i32) ;; label = @1 + loop $cont (result i32) ;; label = @2 + local.get $i + i32.const 1 + i32.add + local.set $i + local.get $i + i32.const 5 + i32.eq + if ;; label = @3 + local.get $i + br 2 (;@1;) + end + local.get $i + end + end + ) + (func (;4;) (type 1) (param $max i32) (result i32) + (local $i i32) + i32.const 1 + local.set $i + block $exit (result i32) ;; label = @1 + loop $cont (result i32) ;; label = @2 + local.get $i + local.get $i + i32.add + local.set $i + local.get $i + local.get $max + i32.gt_u + if ;; label = @3 + local.get $i + br 2 (;@1;) + end + br 0 (;@2;) + end + end + ) + (func (;5;) (type 0) (result i32) + loop $l (result i32) ;; label = @1 + i32.const 1 + end + i32.const 1 + i32.add + ) + (func (;6;) (type 0) (result i32) + loop (result i32) ;; label = @1 + i32.const 0 + br_if 0 (;@1;) + i32.const 3 + end + ) + (func (;7;) (type 0) (result i32) + (local $i i32) + i32.const 0 + local.set $i + block ;; label = @1 + i32.const 1 + if $l ;; label = @2 + br 0 (;@2;) + i32.const 666 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + i32.const 1 + if $l ;; label = @2 + br 0 (;@2;) + i32.const 666 + local.set $i + else + i32.const 888 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + i32.const 1 + if $l ;; label = @2 + br 0 (;@2;) + i32.const 666 + local.set $i + else + i32.const 888 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + i32.const 0 + if $l ;; label = @2 + i32.const 888 + local.set $i + else + br 0 (;@2;) + i32.const 666 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + i32.const 0 + if $l ;; label = @2 + i32.const 888 + local.set $i + else + br 0 (;@2;) + i32.const 666 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + end + local.get $i + ) + (func (;8;) (type 0) (result i32) + (local $i i32) + i32.const 0 + local.set $i + block ;; label = @1 + i32.const 1 + if ;; label = @2 + br 0 (;@2;) + i32.const 666 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + i32.const 1 + if ;; label = @2 + br 0 (;@2;) + i32.const 666 + local.set $i + else + i32.const 888 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + i32.const 1 + if ;; label = @2 + br 0 (;@2;) + i32.const 666 + local.set $i + else + i32.const 888 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + i32.const 0 + if ;; label = @2 + i32.const 888 + local.set $i + else + br 0 (;@2;) + i32.const 666 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + i32.const 0 + if ;; label = @2 + i32.const 888 + local.set $i + else + br 0 (;@2;) + i32.const 666 + local.set $i + end + local.get $i + i32.const 1 + i32.add + local.set $i + end + local.get $i + ) + (func (;9;) (type 1) (param i32) (result i32) + block $ret (result i32) ;; label = @1 + i32.const 10 + block $exit (result i32) ;; label = @2 + block $0 ;; label = @3 + block $default ;; label = @4 + block $3 ;; label = @5 + block $2 ;; label = @6 + block $1 ;; label = @7 + local.get 0 + br_table 4 (;@3;) 0 (;@7;) 1 (;@6;) 2 (;@5;) 3 (;@4;) + end + end + i32.const 2 + br 3 (;@2;) + end + i32.const 3 + br 3 (;@1;) + end + end + i32.const 5 + end + i32.mul + end + ) + (func (;10;) (type 1) (param i32) (result i32) + block $default ;; label = @1 + block $1 ;; label = @2 + block $0 ;; label = @3 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) + br 2 (;@1;) + end + i32.const 0 + return + end + end + i32.const 2 + ) + (func (;11;) (type 0) (result i32) + (local $i i32) + i32.const 0 + local.set $i + block $outer (result i32) ;; label = @1 + block $inner ;; label = @2 + i32.const 0 + br_if 0 (;@2;) + local.get $i + i32.const 1 + i32.or + local.set $i + i32.const 1 + br_if 0 (;@2;) + local.get $i + i32.const 2 + i32.or + local.set $i + end + block (result i32) ;; label = @2 + local.get $i + i32.const 4 + i32.or + local.set $i + local.get $i + end + i32.const 0 + br_if 0 (;@1;) + drop + local.get $i + i32.const 8 + i32.or + local.set $i + block (result i32) ;; label = @2 + local.get $i + i32.const 16 + i32.or + local.set $i + local.get $i + end + i32.const 1 + br_if 0 (;@1;) + drop + local.get $i + i32.const 32 + i32.or + local.set $i + local.get $i + end + ) + (func (;12;) (type 0) (result i32) + block $l0 (result i32) ;; label = @1 + block $l1 (result i32) ;; label = @2 + i32.const 1 + br 0 (;@2;) + end + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 0 + end + ) + (func (;13;) (type 0) (result i32) + block $l0 (result i32) ;; label = @1 + i32.const 1 + if ;; label = @2 + block $l1 (result i32) ;; label = @3 + i32.const 1 + br 0 (;@3;) + end + i32.const 1 + br_if 1 (;@1;) + drop + end + i32.const 0 + end + ) + (func (;14;) (type 0) (result i32) + (local $i1 i32) + block $l0 (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 1 + local.set $i1 + local.get $i1 + end + block (result i32) ;; label = @2 + i32.const 2 + local.set $i1 + local.get $i1 + end + br_if 0 (;@1;) + drop + i32.const 0 + end + i32.const 0 + i32.add + drop + local.get $i1 + ) + (func (;15;) (type 0) (result i32) + block $l0 (result i32) ;; label = @1 + i32.const 1 + if ;; label = @2 + block $l1 (result i32) ;; label = @3 + i32.const 1 + br 0 (;@3;) + end + br 1 (;@1;) + else + block ;; label = @3 + block $l1 (result i32) ;; label = @4 + i32.const 1 + br 0 (;@4;) + end + drop + end + end + i32.const 1 + end + ) + (func (;16;) (type 0) (result i32) + block $l1 (result i32) ;; label = @1 + i32.const 1 + br 0 (;@1;) + i32.const 2 + i32.xor + end + ) + (func (;17;) (type 0) (result i32) + block $l1 (result i32) ;; label = @1 + block $l1 (result i32) ;; label = @2 + i32.const 2 + end + block $l1 (result i32) ;; label = @2 + i32.const 3 + br 0 (;@2;) + end + i32.add + end + ) + (export "block" (func 0)) + (export "loop1" (func 1)) + (export "loop2" (func 2)) + (export "loop3" (func 3)) + (export "loop4" (func 4)) + (export "loop5" (func 5)) + (export "loop6" (func 6)) + (export "if" (func 7)) + (export "if2" (func 8)) + (export "switch" (func 9)) + (export "return" (func 10)) + (export "br_if0" (func 11)) + (export "br_if1" (func 12)) + (export "br_if2" (func 13)) + (export "br_if3" (func 14)) + (export "br" (func 15)) + (export "shadowing" (func 16)) + (export "redefinition" (func 17)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/left-to-right.wast/0.print b/tests/snapshots/testsuite/left-to-right.wast/0.print new file mode 100644 index 0000000000..b8b5c3fc4f --- /dev/null +++ b/tests/snapshots/testsuite/left-to-right.wast/0.print @@ -0,0 +1,1070 @@ +(module + (type $i32_T (;0;) (func (param i32 i32) (result i32))) + (type $i64_T (;1;) (func (param i64 i64) (result i32))) + (type $f32_T (;2;) (func (param f32 f32) (result i32))) + (type $f64_T (;3;) (func (param f64 f64) (result i32))) + (type (;4;) (func)) + (type (;5;) (func (result i32))) + (type (;6;) (func (result i64))) + (type (;7;) (func (result f32))) + (type (;8;) (func (result f64))) + (type (;9;) (func (param i32 i32))) + (type (;10;) (func (param i64 i64))) + (type (;11;) (func (param f32 f32))) + (type (;12;) (func (param f64 f64))) + (func $i32_t0 (;0;) (type $i32_T) (param i32 i32) (result i32) + i32.const -1 + ) + (func $i32_t1 (;1;) (type $i32_T) (param i32 i32) (result i32) + i32.const -2 + ) + (func $i64_t0 (;2;) (type $i64_T) (param i64 i64) (result i32) + i32.const -1 + ) + (func $i64_t1 (;3;) (type $i64_T) (param i64 i64) (result i32) + i32.const -2 + ) + (func $f32_t0 (;4;) (type $f32_T) (param f32 f32) (result i32) + i32.const -1 + ) + (func $f32_t1 (;5;) (type $f32_T) (param f32 f32) (result i32) + i32.const -2 + ) + (func $f64_t0 (;6;) (type $f64_T) (param f64 f64) (result i32) + i32.const -1 + ) + (func $f64_t1 (;7;) (type $f64_T) (param f64 f64) (result i32) + i32.const -2 + ) + (func $reset (;8;) (type 4) + i32.const 8 + i32.const 0 + i32.store + ) + (func $bump (;9;) (type 4) + i32.const 11 + i32.const 10 + i32.load8_u + i32.store8 + i32.const 10 + i32.const 9 + i32.load8_u + i32.store8 + i32.const 9 + i32.const 8 + i32.load8_u + i32.store8 + i32.const 8 + i32.const -3 + i32.store8 + ) + (func $get (;10;) (type 5) (result i32) + i32.const 8 + i32.load + ) + (func $i32_left (;11;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 1 + i32.store8 + i32.const 0 + ) + (func $i32_right (;12;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 2 + i32.store8 + i32.const 1 + ) + (func $i32_another (;13;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 3 + i32.store8 + i32.const 1 + ) + (func $i32_callee (;14;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 4 + i32.store8 + i32.const 0 + ) + (func $i32_bool (;15;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 5 + i32.store8 + i32.const 0 + ) + (func $i64_left (;16;) (type 6) (result i64) + call $bump + i32.const 8 + i32.const 1 + i32.store8 + i64.const 0 + ) + (func $i64_right (;17;) (type 6) (result i64) + call $bump + i32.const 8 + i32.const 2 + i32.store8 + i64.const 1 + ) + (func $i64_another (;18;) (type 6) (result i64) + call $bump + i32.const 8 + i32.const 3 + i32.store8 + i64.const 1 + ) + (func $i64_callee (;19;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 4 + i32.store8 + i32.const 2 + ) + (func $i64_bool (;20;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 5 + i32.store8 + i32.const 0 + ) + (func $f32_left (;21;) (type 7) (result f32) + call $bump + i32.const 8 + i32.const 1 + i32.store8 + f32.const 0x0p+0 (;=0;) + ) + (func $f32_right (;22;) (type 7) (result f32) + call $bump + i32.const 8 + i32.const 2 + i32.store8 + f32.const 0x1p+0 (;=1;) + ) + (func $f32_another (;23;) (type 7) (result f32) + call $bump + i32.const 8 + i32.const 3 + i32.store8 + f32.const 0x1p+0 (;=1;) + ) + (func $f32_callee (;24;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 4 + i32.store8 + i32.const 4 + ) + (func $f32_bool (;25;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 5 + i32.store8 + i32.const 0 + ) + (func $f64_left (;26;) (type 8) (result f64) + call $bump + i32.const 8 + i32.const 1 + i32.store8 + f64.const 0x0p+0 (;=0;) + ) + (func $f64_right (;27;) (type 8) (result f64) + call $bump + i32.const 8 + i32.const 2 + i32.store8 + f64.const 0x1p+0 (;=1;) + ) + (func $f64_another (;28;) (type 8) (result f64) + call $bump + i32.const 8 + i32.const 3 + i32.store8 + f64.const 0x1p+0 (;=1;) + ) + (func $f64_callee (;29;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 4 + i32.store8 + i32.const 6 + ) + (func $f64_bool (;30;) (type 5) (result i32) + call $bump + i32.const 8 + i32.const 5 + i32.store8 + i32.const 0 + ) + (func $i32_dummy (;31;) (type 9) (param i32 i32)) + (func $i64_dummy (;32;) (type 10) (param i64 i64)) + (func $f32_dummy (;33;) (type 11) (param f32 f32)) + (func $f64_dummy (;34;) (type 12) (param f64 f64)) + (func (;35;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.add + drop + call $get + ) + (func (;36;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.sub + drop + call $get + ) + (func (;37;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.mul + drop + call $get + ) + (func (;38;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.div_s + drop + call $get + ) + (func (;39;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.div_u + drop + call $get + ) + (func (;40;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.rem_s + drop + call $get + ) + (func (;41;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.rem_u + drop + call $get + ) + (func (;42;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.and + drop + call $get + ) + (func (;43;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.or + drop + call $get + ) + (func (;44;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.xor + drop + call $get + ) + (func (;45;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.shl + drop + call $get + ) + (func (;46;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.shr_u + drop + call $get + ) + (func (;47;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.shr_s + drop + call $get + ) + (func (;48;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.eq + drop + call $get + ) + (func (;49;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.ne + drop + call $get + ) + (func (;50;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.lt_s + drop + call $get + ) + (func (;51;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.le_s + drop + call $get + ) + (func (;52;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.lt_u + drop + call $get + ) + (func (;53;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.le_u + drop + call $get + ) + (func (;54;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.gt_s + drop + call $get + ) + (func (;55;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.ge_s + drop + call $get + ) + (func (;56;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.gt_u + drop + call $get + ) + (func (;57;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.ge_u + drop + call $get + ) + (func (;58;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.store + call $get + ) + (func (;59;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.store8 + call $get + ) + (func (;60;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + i32.store16 + call $get + ) + (func (;61;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + call $i32_dummy + call $get + ) + (func (;62;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + call $i32_callee + call_indirect (type $i32_T) + drop + call $get + ) + (func (;63;) (type 5) (result i32) + call $reset + call $i32_left + call $i32_right + call $i32_bool + select + drop + call $get + ) + (func (;64;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.add + drop + call $get + ) + (func (;65;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.sub + drop + call $get + ) + (func (;66;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.mul + drop + call $get + ) + (func (;67;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.div_s + drop + call $get + ) + (func (;68;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.div_u + drop + call $get + ) + (func (;69;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.rem_s + drop + call $get + ) + (func (;70;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.rem_u + drop + call $get + ) + (func (;71;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.and + drop + call $get + ) + (func (;72;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.or + drop + call $get + ) + (func (;73;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.xor + drop + call $get + ) + (func (;74;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.shl + drop + call $get + ) + (func (;75;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.shr_u + drop + call $get + ) + (func (;76;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.shr_s + drop + call $get + ) + (func (;77;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.eq + drop + call $get + ) + (func (;78;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.ne + drop + call $get + ) + (func (;79;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.lt_s + drop + call $get + ) + (func (;80;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.le_s + drop + call $get + ) + (func (;81;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.lt_u + drop + call $get + ) + (func (;82;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.le_u + drop + call $get + ) + (func (;83;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.gt_s + drop + call $get + ) + (func (;84;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.ge_s + drop + call $get + ) + (func (;85;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.gt_u + drop + call $get + ) + (func (;86;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + i64.ge_u + drop + call $get + ) + (func (;87;) (type 5) (result i32) + call $reset + call $i32_left + call $i64_right + i64.store + call $get + ) + (func (;88;) (type 5) (result i32) + call $reset + call $i32_left + call $i64_right + i64.store8 + call $get + ) + (func (;89;) (type 5) (result i32) + call $reset + call $i32_left + call $i64_right + i64.store16 + call $get + ) + (func (;90;) (type 5) (result i32) + call $reset + call $i32_left + call $i64_right + i64.store32 + call $get + ) + (func (;91;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + call $i64_dummy + call $get + ) + (func (;92;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + call $i64_callee + call_indirect (type $i64_T) + drop + call $get + ) + (func (;93;) (type 5) (result i32) + call $reset + call $i64_left + call $i64_right + call $i64_bool + select + drop + call $get + ) + (func (;94;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.add + drop + call $get + ) + (func (;95;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.sub + drop + call $get + ) + (func (;96;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.mul + drop + call $get + ) + (func (;97;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.div + drop + call $get + ) + (func (;98;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.copysign + drop + call $get + ) + (func (;99;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.eq + drop + call $get + ) + (func (;100;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.ne + drop + call $get + ) + (func (;101;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.lt + drop + call $get + ) + (func (;102;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.le + drop + call $get + ) + (func (;103;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.gt + drop + call $get + ) + (func (;104;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.ge + drop + call $get + ) + (func (;105;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.min + drop + call $get + ) + (func (;106;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + f32.max + drop + call $get + ) + (func (;107;) (type 5) (result i32) + call $reset + call $i32_left + call $f32_right + f32.store + call $get + ) + (func (;108;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + call $f32_dummy + call $get + ) + (func (;109;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + call $f32_callee + call_indirect (type $f32_T) + drop + call $get + ) + (func (;110;) (type 5) (result i32) + call $reset + call $f32_left + call $f32_right + call $f32_bool + select + drop + call $get + ) + (func (;111;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.add + drop + call $get + ) + (func (;112;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.sub + drop + call $get + ) + (func (;113;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.mul + drop + call $get + ) + (func (;114;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.div + drop + call $get + ) + (func (;115;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.copysign + drop + call $get + ) + (func (;116;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.eq + drop + call $get + ) + (func (;117;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.ne + drop + call $get + ) + (func (;118;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.lt + drop + call $get + ) + (func (;119;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.le + drop + call $get + ) + (func (;120;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.gt + drop + call $get + ) + (func (;121;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.ge + drop + call $get + ) + (func (;122;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.min + drop + call $get + ) + (func (;123;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + f64.max + drop + call $get + ) + (func (;124;) (type 5) (result i32) + call $reset + call $i32_left + call $f64_right + f64.store + call $get + ) + (func (;125;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + call $f64_dummy + call $get + ) + (func (;126;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + call $f64_callee + call_indirect (type $f64_T) + drop + call $get + ) + (func (;127;) (type 5) (result i32) + call $reset + call $f64_left + call $f64_right + call $f64_bool + select + drop + call $get + ) + (func (;128;) (type 5) (result i32) + block (result i32) ;; label = @1 + call $reset + call $i32_left + call $i32_right + i32.const 0 + i32.and + br_if 0 (;@1;) + drop + call $get + end + ) + (func (;129;) (type 5) (result i32) + block $a (result i32) ;; label = @1 + call $reset + block $b (result i32) ;; label = @2 + call $i32_left + call $i32_right + br_table 1 (;@1;) 0 (;@2;) + end + drop + call $get + end + ) + (table (;0;) 8 8 funcref) + (memory (;0;) 1) + (export "i32_add" (func 35)) + (export "i32_sub" (func 36)) + (export "i32_mul" (func 37)) + (export "i32_div_s" (func 38)) + (export "i32_div_u" (func 39)) + (export "i32_rem_s" (func 40)) + (export "i32_rem_u" (func 41)) + (export "i32_and" (func 42)) + (export "i32_or" (func 43)) + (export "i32_xor" (func 44)) + (export "i32_shl" (func 45)) + (export "i32_shr_u" (func 46)) + (export "i32_shr_s" (func 47)) + (export "i32_eq" (func 48)) + (export "i32_ne" (func 49)) + (export "i32_lt_s" (func 50)) + (export "i32_le_s" (func 51)) + (export "i32_lt_u" (func 52)) + (export "i32_le_u" (func 53)) + (export "i32_gt_s" (func 54)) + (export "i32_ge_s" (func 55)) + (export "i32_gt_u" (func 56)) + (export "i32_ge_u" (func 57)) + (export "i32_store" (func 58)) + (export "i32_store8" (func 59)) + (export "i32_store16" (func 60)) + (export "i32_call" (func 61)) + (export "i32_call_indirect" (func 62)) + (export "i32_select" (func 63)) + (export "i64_add" (func 64)) + (export "i64_sub" (func 65)) + (export "i64_mul" (func 66)) + (export "i64_div_s" (func 67)) + (export "i64_div_u" (func 68)) + (export "i64_rem_s" (func 69)) + (export "i64_rem_u" (func 70)) + (export "i64_and" (func 71)) + (export "i64_or" (func 72)) + (export "i64_xor" (func 73)) + (export "i64_shl" (func 74)) + (export "i64_shr_u" (func 75)) + (export "i64_shr_s" (func 76)) + (export "i64_eq" (func 77)) + (export "i64_ne" (func 78)) + (export "i64_lt_s" (func 79)) + (export "i64_le_s" (func 80)) + (export "i64_lt_u" (func 81)) + (export "i64_le_u" (func 82)) + (export "i64_gt_s" (func 83)) + (export "i64_ge_s" (func 84)) + (export "i64_gt_u" (func 85)) + (export "i64_ge_u" (func 86)) + (export "i64_store" (func 87)) + (export "i64_store8" (func 88)) + (export "i64_store16" (func 89)) + (export "i64_store32" (func 90)) + (export "i64_call" (func 91)) + (export "i64_call_indirect" (func 92)) + (export "i64_select" (func 93)) + (export "f32_add" (func 94)) + (export "f32_sub" (func 95)) + (export "f32_mul" (func 96)) + (export "f32_div" (func 97)) + (export "f32_copysign" (func 98)) + (export "f32_eq" (func 99)) + (export "f32_ne" (func 100)) + (export "f32_lt" (func 101)) + (export "f32_le" (func 102)) + (export "f32_gt" (func 103)) + (export "f32_ge" (func 104)) + (export "f32_min" (func 105)) + (export "f32_max" (func 106)) + (export "f32_store" (func 107)) + (export "f32_call" (func 108)) + (export "f32_call_indirect" (func 109)) + (export "f32_select" (func 110)) + (export "f64_add" (func 111)) + (export "f64_sub" (func 112)) + (export "f64_mul" (func 113)) + (export "f64_div" (func 114)) + (export "f64_copysign" (func 115)) + (export "f64_eq" (func 116)) + (export "f64_ne" (func 117)) + (export "f64_lt" (func 118)) + (export "f64_le" (func 119)) + (export "f64_gt" (func 120)) + (export "f64_ge" (func 121)) + (export "f64_min" (func 122)) + (export "f64_max" (func 123)) + (export "f64_store" (func 124)) + (export "f64_call" (func 125)) + (export "f64_call_indirect" (func 126)) + (export "f64_select" (func 127)) + (export "br_if" (func 128)) + (export "br_table" (func 129)) + (elem (;0;) (i32.const 0) func $i32_t0 $i32_t1 $i64_t0 $i64_t1 $f32_t0 $f32_t1 $f64_t0 $f64_t1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/0.print b/tests/snapshots/testsuite/linking.wast/0.print new file mode 100644 index 0000000000..a9214ac0e3 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/0.print @@ -0,0 +1,10 @@ +(module $Mf + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + call $g + ) + (func $g (;1;) (type 0) (result i32) + i32.const 2 + ) + (export "call" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/100.print b/tests/snapshots/testsuite/linking.wast/100.print new file mode 100644 index 0000000000..b2d41df30d --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/100.print @@ -0,0 +1,12 @@ +(module $Nm + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "load" (func $loadM (;0;) (type 0))) + (func (;1;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (memory (;0;) 1) + (export "Mm.load" (func $loadM)) + (export "load" (func 1)) + (data (;0;) (i32.const 10) "\f0\f1\f2\f3\f4\f5") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/104.print b/tests/snapshots/testsuite/linking.wast/104.print new file mode 100644 index 0000000000..31afc29676 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/104.print @@ -0,0 +1,10 @@ +(module $Om + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "mem" (memory (;0;) 1)) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (export "load" (func 0)) + (data (;0;) (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/109.print b/tests/snapshots/testsuite/linking.wast/109.print new file mode 100644 index 0000000000..56c92a9af5 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/109.print @@ -0,0 +1,4 @@ +(module + (import "Mm" "mem" (memory (;0;) 0)) + (data (;0;) (i32.const 65535) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/11.print b/tests/snapshots/testsuite/linking.wast/11.print new file mode 100644 index 0000000000..12315604a6 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/11.print @@ -0,0 +1,21 @@ +(module $Mg + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + global.get $glob + ) + (func (;1;) (type 0) (result i32) + global.get $mut_glob + ) + (func (;2;) (type 1) (param i32) + local.get 0 + global.set $mut_glob + ) + (global $glob (;0;) i32 i32.const 42) + (global $mut_glob (;1;) (mut i32) i32.const 142) + (export "glob" (global $glob)) + (export "get" (func 0)) + (export "mut_glob" (global $mut_glob)) + (export "get_mut" (func 1)) + (export "set_mut" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/111.print b/tests/snapshots/testsuite/linking.wast/111.print new file mode 100644 index 0000000000..17368b7ad7 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/111.print @@ -0,0 +1,9 @@ +(module $Pm + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "mem" (memory (;0;) 1 8)) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + memory.grow + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/127.print b/tests/snapshots/testsuite/linking.wast/127.print new file mode 100644 index 0000000000..24a36bdfab --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/127.print @@ -0,0 +1,17 @@ +(module $Ms + (type $t (;0;) (func (result i32))) + (func (;0;) (type $t) (result i32) + i32.const 0 + i32.load8_u + ) + (func (;1;) (type $t) (result i32) + i32.const 0 + call_indirect (type $t) + ) + (table (;0;) 1 funcref) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "table" (table 0)) + (export "get memory[0]" (func 0)) + (export "get table[0]" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/13.print b/tests/snapshots/testsuite/linking.wast/13.print new file mode 100644 index 0000000000..45ee840475 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/13.print @@ -0,0 +1,20 @@ +(module $Ng + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (import "Mg" "glob" (global $x (;0;) i32)) + (import "Mg" "mut_glob" (global $mut_glob (;1;) (mut i32))) + (import "Mg" "get" (func $f (;0;) (type 0))) + (import "Mg" "get_mut" (func $get_mut (;1;) (type 0))) + (import "Mg" "set_mut" (func $set_mut (;2;) (type 1))) + (func (;3;) (type 0) (result i32) + global.get $glob + ) + (global $glob (;2;) i32 i32.const 43) + (export "Mg.glob" (global $x)) + (export "Mg.get" (func $f)) + (export "glob" (global $glob)) + (export "get" (func 3)) + (export "Mg.mut_glob" (global $mut_glob)) + (export "Mg.get_mut" (func $get_mut)) + (export "Mg.set_mut" (func $set_mut)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/2.print b/tests/snapshots/testsuite/linking.wast/2.print new file mode 100644 index 0000000000..20a34e4785 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/2.print @@ -0,0 +1,16 @@ +(module $Nf + (type (;0;) (func (result i32))) + (import "Mf" "call" (func $f (;0;) (type 0))) + (func (;1;) (type 0) (result i32) + call $f + ) + (func (;2;) (type 0) (result i32) + call $g + ) + (func $g (;3;) (type 0) (result i32) + i32.const 3 + ) + (export "Mf.call" (func $f)) + (export "call Mf.call" (func 1)) + (export "call" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/31.print b/tests/snapshots/testsuite/linking.wast/31.print new file mode 100644 index 0000000000..c564e674ce --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/31.print @@ -0,0 +1,10 @@ +(module $Mref_ex + (global (;0;) funcref ref.null func) + (global (;1;) (mut funcref) ref.null func) + (global (;2;) externref ref.null extern) + (global (;3;) (mut externref) ref.null extern) + (export "g-const-func" (global 0)) + (export "g-var-func" (global 1)) + (export "g-const-extern" (global 2)) + (export "g-var-extern" (global 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/33.print b/tests/snapshots/testsuite/linking.wast/33.print new file mode 100644 index 0000000000..3e29b4c2e3 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/33.print @@ -0,0 +1,6 @@ +(module $Mref_im + (import "Mref_ex" "g-const-func" (global (;0;) funcref)) + (import "Mref_ex" "g-const-extern" (global (;1;) externref)) + (import "Mref_ex" "g-var-func" (global (;2;) (mut funcref))) + (import "Mref_ex" "g-var-extern" (global (;3;) (mut externref))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/38.print b/tests/snapshots/testsuite/linking.wast/38.print new file mode 100644 index 0000000000..045b7e0e24 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/38.print @@ -0,0 +1,20 @@ +(module $Mt + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (func $g (;0;) (type 0) (result i32) + i32.const 4 + ) + (func (;1;) (type 0) (result i32) + i32.const -4 + ) + (func (;2;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table (;0;) 10 funcref) + (export "tab" (table 0)) + (export "h" (func 1)) + (export "call" (func 2)) + (elem (;0;) (i32.const 2) func $g $g $g $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/40.print b/tests/snapshots/testsuite/linking.wast/40.print new file mode 100644 index 0000000000..7021967aba --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/40.print @@ -0,0 +1,23 @@ +(module $Nt + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32) (result i32))) + (import "Mt" "call" (func $f (;0;) (type 2))) + (import "Mt" "h" (func $h (;1;) (type 1))) + (func $g (;2;) (type 1) (result i32) + i32.const 5 + ) + (func (;3;) (type 2) (param i32) (result i32) + local.get 0 + call $f + ) + (func (;4;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 1) + ) + (table (;0;) 5 5 funcref) + (export "Mt.call" (func $f)) + (export "call Mt.call" (func 3)) + (export "call" (func 4)) + (elem (;0;) (i32.const 0) func $g $g $g $h $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/59.print b/tests/snapshots/testsuite/linking.wast/59.print new file mode 100644 index 0000000000..a9da3390ae --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/59.print @@ -0,0 +1,15 @@ +(module $Ot + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "Mt" "h" (func $h (;0;) (type 0))) + (import "Mt" "tab" (table (;0;) 5 funcref)) + (func $i (;1;) (type 0) (result i32) + i32.const 6 + ) + (func (;2;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (export "call" (func 2)) + (elem (;0;) (i32.const 1) func $i $h) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/7.print b/tests/snapshots/testsuite/linking.wast/7.print new file mode 100644 index 0000000000..ba4140f49a --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/7.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func $f (;0;) (type 0))) + (export "print" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/80.print b/tests/snapshots/testsuite/linking.wast/80.print new file mode 100644 index 0000000000..c3d1cec142 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/80.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "Mt" "tab" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/81.print b/tests/snapshots/testsuite/linking.wast/81.print new file mode 100644 index 0000000000..f11c4feb9d --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/81.print @@ -0,0 +1,4 @@ +(module $G1 + (global (;0;) i32 i32.const 5) + (export "g" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/83.print b/tests/snapshots/testsuite/linking.wast/83.print new file mode 100644 index 0000000000..5950d0a90b --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/83.print @@ -0,0 +1,5 @@ +(module $G2 + (import "G1" "g" (global (;0;) i32)) + (global (;1;) i32 global.get 0) + (export "g" (global 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/93.print b/tests/snapshots/testsuite/linking.wast/93.print new file mode 100644 index 0000000000..bcb7458ffb --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/93.print @@ -0,0 +1,6 @@ +(module $Mtable_ex + (table $t1 (;0;) 1 funcref) + (table $t2 (;1;) 1 externref) + (export "t-func" (table $t1)) + (export "t-extern" (table $t2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/95.print b/tests/snapshots/testsuite/linking.wast/95.print new file mode 100644 index 0000000000..741610f5da --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/95.print @@ -0,0 +1,4 @@ +(module + (import "Mtable_ex" "t-func" (table (;0;) 1 funcref)) + (import "Mtable_ex" "t-extern" (table (;1;) 1 externref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/linking.wast/98.print b/tests/snapshots/testsuite/linking.wast/98.print new file mode 100644 index 0000000000..4bc82eb617 --- /dev/null +++ b/tests/snapshots/testsuite/linking.wast/98.print @@ -0,0 +1,11 @@ +(module $Mm + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (memory (;0;) 1 5) + (export "mem" (memory 0)) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/load.wast/0.print b/tests/snapshots/testsuite/load.wast/0.print new file mode 100644 index 0000000000..d513949b27 --- /dev/null +++ b/tests/snapshots/testsuite/load.wast/0.print @@ -0,0 +1,306 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (type (;3;) (func (param i32 i32) (result i32))) + (func (;0;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load + br 0 (;@1;) + end + ) + (func (;1;) (type 2) + block ;; label = @1 + i32.const 0 + i32.load + br_if 0 (;@1;) + end + ) + (func (;2;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;3;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + i32.load + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;4;) (type 2) + block ;; label = @1 + i32.const 0 + i32.load + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;5;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;6;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + i32.load + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;7;) (type 1) (result i32) + i32.const 0 + i32.load + return + ) + (func (;8;) (type 1) (result i32) + i32.const 0 + i32.load + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;9;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 0 + i32.load + else + i32.const 0 + end + ) + (func (;10;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 0 + i32.load + end + ) + (func (;11;) (type 3) (param i32 i32) (result i32) + i32.const 0 + i32.load + local.get 0 + local.get 1 + select + ) + (func (;12;) (type 3) (param i32 i32) (result i32) + local.get 0 + i32.const 0 + i32.load + local.get 1 + select + ) + (func (;13;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i32.const 0 + i32.load + select + ) + (func $f (;14;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;15;) (type 1) (result i32) + i32.const 0 + i32.load + i32.const 2 + i32.const 3 + call $f + ) + (func (;16;) (type 1) (result i32) + i32.const 1 + i32.const 0 + i32.load + i32.const 3 + call $f + ) + (func (;17;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + i32.load + call $f + ) + (func (;18;) (type 1) (result i32) + i32.const 0 + i32.load + i32.const 2 + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;19;) (type 1) (result i32) + i32.const 1 + i32.const 0 + i32.load + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;20;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + i32.load + i32.const 0 + call_indirect (type $sig) + ) + (func (;21;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 0 + i32.load + call_indirect (type $sig) + ) + (func (;22;) (type 2) + (local i32) + i32.const 0 + i32.load + local.set 0 + ) + (func (;23;) (type 1) (result i32) + (local i32) + i32.const 0 + i32.load + local.tee 0 + ) + (func (;24;) (type 2) + (local i32) + i32.const 0 + i32.load + global.set $g + ) + (func (;25;) (type 1) (result i32) + i32.const 0 + i32.load + i32.load + ) + (func (;26;) (type 1) (result i32) + i32.const 0 + i32.load + i32.load8_s + ) + (func (;27;) (type 2) + i32.const 0 + i32.load + i32.const 7 + i32.store + ) + (func (;28;) (type 2) + i32.const 2 + i32.const 0 + i32.load + i32.store + ) + (func (;29;) (type 2) + i32.const 0 + i32.load8_s + i32.const 7 + i32.store8 + ) + (func (;30;) (type 2) + i32.const 2 + i32.const 0 + i32.load + i32.store16 + ) + (func (;31;) (type 1) (result i32) + i32.const 100 + i32.load + i32.clz + ) + (func (;32;) (type 1) (result i32) + i32.const 100 + i32.load + i32.const 10 + i32.add + ) + (func (;33;) (type 1) (result i32) + i32.const 10 + i32.const 100 + i32.load + i32.sub + ) + (func (;34;) (type 1) (result i32) + i32.const 100 + i32.load + i32.eqz + ) + (func (;35;) (type 1) (result i32) + i32.const 100 + i32.load + i32.const 10 + i32.le_s + ) + (func (;36;) (type 1) (result i32) + i32.const 10 + i32.const 100 + i32.load + i32.ne + ) + (func (;37;) (type 1) (result i32) + i32.const 100 + i32.load + memory.grow + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $g (;0;) (mut i32) i32.const 0) + (export "as-br-value" (func 0)) + (export "as-br_if-cond" (func 1)) + (export "as-br_if-value" (func 2)) + (export "as-br_if-value-cond" (func 3)) + (export "as-br_table-index" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-br_table-value-index" (func 6)) + (export "as-return-value" (func 7)) + (export "as-if-cond" (func 8)) + (export "as-if-then" (func 9)) + (export "as-if-else" (func 10)) + (export "as-select-first" (func 11)) + (export "as-select-second" (func 12)) + (export "as-select-cond" (func 13)) + (export "as-call-first" (func 15)) + (export "as-call-mid" (func 16)) + (export "as-call-last" (func 17)) + (export "as-call_indirect-first" (func 18)) + (export "as-call_indirect-mid" (func 19)) + (export "as-call_indirect-last" (func 20)) + (export "as-call_indirect-index" (func 21)) + (export "as-local.set-value" (func 22)) + (export "as-local.tee-value" (func 23)) + (export "as-global.set-value" (func 24)) + (export "as-load-address" (func 25)) + (export "as-loadN-address" (func 26)) + (export "as-store-address" (func 27)) + (export "as-store-value" (func 28)) + (export "as-storeN-address" (func 29)) + (export "as-storeN-value" (func 30)) + (export "as-unary-operand" (func 31)) + (export "as-binary-left" (func 32)) + (export "as-binary-right" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-left" (func 35)) + (export "as-compare-right" (func 36)) + (export "as-memory.grow-size" (func 37)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/local_get.wast/0.print b/tests/snapshots/testsuite/local_get.wast/0.print new file mode 100644 index 0000000000..8016de3d6b --- /dev/null +++ b/tests/snapshots/testsuite/local_get.wast/0.print @@ -0,0 +1,189 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (type (;4;) (func (param i32) (result i32))) + (type (;5;) (func (param i64) (result i64))) + (type (;6;) (func (param f32) (result f32))) + (type (;7;) (func (param f64) (result f64))) + (type (;8;) (func (param i64 f32 f64 i32 i32))) + (type (;9;) (func (param i64 f32 f64 i32 i32) (result f64))) + (func (;0;) (type 0) (result i32) + (local i32) + local.get 0 + ) + (func (;1;) (type 1) (result i64) + (local i64) + local.get 0 + ) + (func (;2;) (type 2) (result f32) + (local f32) + local.get 0 + ) + (func (;3;) (type 3) (result f64) + (local f64) + local.get 0 + ) + (func (;4;) (type 4) (param i32) (result i32) + local.get 0 + ) + (func (;5;) (type 5) (param i64) (result i64) + local.get 0 + ) + (func (;6;) (type 6) (param f32) (result f32) + local.get 0 + ) + (func (;7;) (type 7) (param f64) (result f64) + local.get 0 + ) + (func (;8;) (type 8) (param i64 f32 f64 i32 i32) + (local f32 i64 i64 f64) + local.get 0 + i64.eqz + drop + local.get 1 + f32.neg + drop + local.get 2 + f64.neg + drop + local.get 3 + i32.eqz + drop + local.get 4 + i32.eqz + drop + local.get 5 + f32.neg + drop + local.get 6 + i64.eqz + drop + local.get 7 + i64.eqz + drop + local.get 8 + f64.neg + drop + ) + (func (;9;) (type 9) (param i64 f32 f64 i32 i32) (result f64) + (local f32 i64 i64 f64) + f32.const 0x1.6p+2 (;=5.5;) + local.set 5 + i64.const 6 + local.set 6 + f64.const 0x1p+3 (;=8;) + local.set 8 + local.get 0 + f64.convert_i64_u + local.get 1 + f64.promote_f32 + local.get 2 + local.get 3 + f64.convert_i32_u + local.get 4 + f64.convert_i32_s + local.get 5 + f64.promote_f32 + local.get 6 + f64.convert_i64_u + local.get 7 + f64.convert_i64_u + local.get 8 + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + ) + (func (;10;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + end + ) + (func (;11;) (type 4) (param i32) (result i32) + loop (result i32) ;; label = @1 + local.get 0 + end + ) + (func (;12;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + br 0 (;@1;) + end + ) + (func (;13;) (type 4) (param i32) (result i32) + block $l0 (result i32) ;; label = @1 + local.get 0 + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;14;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + local.get 0 + br_if 0 (;@1;) + end + ) + (func (;15;) (type 4) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 0 + return + end + i32.const 1 + return + end + i32.const 2 + return + end + i32.const 3 + ) + (func (;16;) (type 4) (param i32) (result i32) + local.get 0 + return + ) + (func (;17;) (type 4) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 0 + else + i32.const 0 + end + ) + (func (;18;) (type 4) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + local.get 0 + end + ) + (export "type-local-i32" (func 0)) + (export "type-local-i64" (func 1)) + (export "type-local-f32" (func 2)) + (export "type-local-f64" (func 3)) + (export "type-param-i32" (func 4)) + (export "type-param-i64" (func 5)) + (export "type-param-f32" (func 6)) + (export "type-param-f64" (func 7)) + (export "type-mixed" (func 8)) + (export "read" (func 9)) + (export "as-block-value" (func 10)) + (export "as-loop-value" (func 11)) + (export "as-br-value" (func 12)) + (export "as-br_if-value" (func 13)) + (export "as-br_if-value-cond" (func 14)) + (export "as-br_table-value" (func 15)) + (export "as-return-value" (func 16)) + (export "as-if-then" (func 17)) + (export "as-if-else" (func 18)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/local_set.wast/0.print b/tests/snapshots/testsuite/local_set.wast/0.print new file mode 100644 index 0000000000..ad7f6a14fc --- /dev/null +++ b/tests/snapshots/testsuite/local_set.wast/0.print @@ -0,0 +1,188 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i64))) + (type (;3;) (func (param f32))) + (type (;4;) (func (param f64))) + (type (;5;) (func (param i64 f32 f64 i32 i32))) + (type (;6;) (func (param i64 f32 f64 i32 i32) (result i64))) + (func (;0;) (type 0) + (local i32) + i32.const 0 + local.set 0 + ) + (func (;1;) (type 0) + (local i64) + i64.const 0 + local.set 0 + ) + (func (;2;) (type 0) + (local f32) + f32.const 0x0p+0 (;=0;) + local.set 0 + ) + (func (;3;) (type 0) + (local f64) + f64.const 0x0p+0 (;=0;) + local.set 0 + ) + (func (;4;) (type 1) (param i32) + i32.const 10 + local.set 0 + ) + (func (;5;) (type 2) (param i64) + i64.const 11 + local.set 0 + ) + (func (;6;) (type 3) (param f32) + f32.const 0x1.633334p+3 (;=11.1;) + local.set 0 + ) + (func (;7;) (type 4) (param f64) + f64.const 0x1.8666666666666p+3 (;=12.2;) + local.set 0 + ) + (func (;8;) (type 5) (param i64 f32 f64 i32 i32) + (local f32 i64 i64 f64) + i64.const 0 + local.set 0 + f32.const 0x0p+0 (;=0;) + local.set 1 + f64.const 0x0p+0 (;=0;) + local.set 2 + i32.const 0 + local.set 3 + i32.const 0 + local.set 4 + f32.const 0x0p+0 (;=0;) + local.set 5 + i64.const 0 + local.set 6 + i64.const 0 + local.set 7 + f64.const 0x0p+0 (;=0;) + local.set 8 + ) + (func (;9;) (type 6) (param i64 f32 f64 i32 i32) (result i64) + (local f32 i64 i64 f64) + f32.const -0x1.333334p-2 (;=-0.3;) + local.set 1 + i32.const 40 + local.set 3 + i32.const -7 + local.set 4 + f32.const 0x1.6p+2 (;=5.5;) + local.set 5 + i64.const 6 + local.set 6 + f64.const 0x1p+3 (;=8;) + local.set 8 + local.get 0 + f64.convert_i64_u + local.get 1 + f64.promote_f32 + local.get 2 + local.get 3 + f64.convert_i32_u + local.get 4 + f64.convert_i32_s + local.get 5 + f64.promote_f32 + local.get 6 + f64.convert_i64_u + local.get 7 + f64.convert_i64_u + local.get 8 + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + i64.trunc_f64_s + ) + (func (;10;) (type 1) (param i32) + block ;; label = @1 + i32.const 1 + local.set 0 + end + ) + (func (;11;) (type 1) (param i32) + loop ;; label = @1 + i32.const 3 + local.set 0 + end + ) + (func (;12;) (type 1) (param i32) + block ;; label = @1 + i32.const 9 + local.set 0 + br 0 (;@1;) + end + ) + (func (;13;) (type 1) (param i32) + block ;; label = @1 + i32.const 8 + local.set 0 + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;14;) (type 1) (param i32) + block ;; label = @1 + i32.const 6 + i32.const 9 + local.set 0 + br_if 0 (;@1;) + end + ) + (func (;15;) (type 1) (param i32) + block ;; label = @1 + i32.const 10 + local.set 0 + i32.const 1 + br_table 0 (;@1;) + end + ) + (func (;16;) (type 1) (param i32) + i32.const 7 + local.set 0 + return + ) + (func (;17;) (type 1) (param i32) + local.get 0 + if ;; label = @1 + i32.const 3 + local.set 0 + end + ) + (func (;18;) (type 1) (param i32) + local.get 0 + if ;; label = @1 + else + i32.const 1 + local.set 0 + end + ) + (export "type-local-i32" (func 0)) + (export "type-local-i64" (func 1)) + (export "type-local-f32" (func 2)) + (export "type-local-f64" (func 3)) + (export "type-param-i32" (func 4)) + (export "type-param-i64" (func 5)) + (export "type-param-f32" (func 6)) + (export "type-param-f64" (func 7)) + (export "type-mixed" (func 8)) + (export "write" (func 9)) + (export "as-block-value" (func 10)) + (export "as-loop-value" (func 11)) + (export "as-br-value" (func 12)) + (export "as-br_if-value" (func 13)) + (export "as-br_if-value-cond" (func 14)) + (export "as-br_table-value" (func 15)) + (export "as-return-value" (func 16)) + (export "as-if-then" (func 17)) + (export "as-if-else" (func 18)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/local_tee.wast/0.print b/tests/snapshots/testsuite/local_tee.wast/0.print new file mode 100644 index 0000000000..55b74a95d9 --- /dev/null +++ b/tests/snapshots/testsuite/local_tee.wast/0.print @@ -0,0 +1,544 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (result i64))) + (type (;3;) (func (result f32))) + (type (;4;) (func (result f64))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i64) (result i64))) + (type (;7;) (func (param f32) (result f32))) + (type (;8;) (func (param f64) (result f64))) + (type (;9;) (func (param i64 f32 f64 i32 i32))) + (type (;10;) (func (param i64 f32 f64 i32 i32) (result i64))) + (type (;11;) (func (param i64 f32 f64 i32 i32) (result f64))) + (type (;12;) (func)) + (type (;13;) (func (param i32))) + (type (;14;) (func (param i32 i32) (result i32))) + (type (;15;) (func (param i64) (result i32))) + (func (;0;) (type 1) (result i32) + (local i32) + i32.const 0 + local.tee 0 + ) + (func (;1;) (type 2) (result i64) + (local i64) + i64.const 0 + local.tee 0 + ) + (func (;2;) (type 3) (result f32) + (local f32) + f32.const 0x0p+0 (;=0;) + local.tee 0 + ) + (func (;3;) (type 4) (result f64) + (local f64) + f64.const 0x0p+0 (;=0;) + local.tee 0 + ) + (func (;4;) (type 5) (param i32) (result i32) + i32.const 10 + local.tee 0 + ) + (func (;5;) (type 6) (param i64) (result i64) + i64.const 11 + local.tee 0 + ) + (func (;6;) (type 7) (param f32) (result f32) + f32.const 0x1.633334p+3 (;=11.1;) + local.tee 0 + ) + (func (;7;) (type 8) (param f64) (result f64) + f64.const 0x1.8666666666666p+3 (;=12.2;) + local.tee 0 + ) + (func (;8;) (type 9) (param i64 f32 f64 i32 i32) + (local f32 i64 i64 f64) + i64.const 0 + local.tee 0 + i64.eqz + drop + f32.const 0x0p+0 (;=0;) + local.tee 1 + f32.neg + drop + f64.const 0x0p+0 (;=0;) + local.tee 2 + f64.neg + drop + i32.const 0 + local.tee 3 + i32.eqz + drop + i32.const 0 + local.tee 4 + i32.eqz + drop + f32.const 0x0p+0 (;=0;) + local.tee 5 + f32.neg + drop + i64.const 0 + local.tee 6 + i64.eqz + drop + i64.const 0 + local.tee 7 + i64.eqz + drop + f64.const 0x0p+0 (;=0;) + local.tee 8 + f64.neg + drop + ) + (func (;9;) (type 10) (param i64 f32 f64 i32 i32) (result i64) + (local f32 i64 i64 f64) + f32.const -0x1.333334p-2 (;=-0.3;) + local.tee 1 + drop + i32.const 40 + local.tee 3 + drop + i32.const -7 + local.tee 4 + drop + f32.const 0x1.6p+2 (;=5.5;) + local.tee 5 + drop + i64.const 6 + local.tee 6 + drop + f64.const 0x1p+3 (;=8;) + local.tee 8 + drop + local.get 0 + f64.convert_i64_u + local.get 1 + f64.promote_f32 + local.get 2 + local.get 3 + f64.convert_i32_u + local.get 4 + f64.convert_i32_s + local.get 5 + f64.promote_f32 + local.get 6 + f64.convert_i64_u + local.get 7 + f64.convert_i64_u + local.get 8 + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + i64.trunc_f64_s + ) + (func (;10;) (type 11) (param i64 f32 f64 i32 i32) (result f64) + (local f32 i64 i64 f64) + i64.const 1 + local.tee 0 + f64.convert_i64_u + f32.const 0x1p+1 (;=2;) + local.tee 1 + f64.promote_f32 + f64.const 0x1.a666666666666p+1 (;=3.3;) + local.tee 2 + i32.const 4 + local.tee 3 + f64.convert_i32_u + i32.const 5 + local.tee 4 + f64.convert_i32_s + f32.const 0x1.6p+2 (;=5.5;) + local.tee 5 + f64.promote_f32 + i64.const 6 + local.tee 6 + f64.convert_i64_u + i64.const 0 + local.tee 7 + f64.convert_i64_u + f64.const 0x1p+3 (;=8;) + local.tee 8 + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + ) + (func $dummy (;11;) (type 12)) + (func (;12;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + local.tee 0 + call $dummy + end + ) + (func (;13;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 1 + local.tee 0 + call $dummy + end + ) + (func (;14;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 1 + local.tee 0 + end + ) + (func (;15;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + i32.const 3 + local.tee 0 + call $dummy + end + ) + (func (;16;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 4 + local.tee 0 + call $dummy + end + ) + (func (;17;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 5 + local.tee 0 + end + ) + (func (;18;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 9 + local.tee 0 + br 0 (;@1;) + end + ) + (func (;19;) (type 13) (param i32) + block ;; label = @1 + i32.const 1 + local.tee 0 + br_if 0 (;@1;) + end + ) + (func (;20;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 8 + local.tee 0 + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;21;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 9 + local.tee 0 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;22;) (type 13) (param i32) + block ;; label = @1 + i32.const 0 + local.tee 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;23;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + local.tee 0 + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;24;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 11 + local.tee 0 + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;25;) (type 5) (param i32) (result i32) + i32.const 7 + local.tee 0 + return + ) + (func (;26;) (type 5) (param i32) (result i32) + i32.const 2 + local.tee 0 + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;27;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 3 + local.tee 0 + else + local.get 0 + end + ) + (func (;28;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 0 + else + i32.const 4 + local.tee 0 + end + ) + (func (;29;) (type 14) (param i32 i32) (result i32) + i32.const 5 + local.tee 0 + local.get 0 + local.get 1 + select + ) + (func (;30;) (type 14) (param i32 i32) (result i32) + local.get 0 + i32.const 6 + local.tee 0 + local.get 1 + select + ) + (func (;31;) (type 5) (param i32) (result i32) + i32.const 0 + i32.const 1 + i32.const 7 + local.tee 0 + select + ) + (func $f (;32;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;33;) (type 5) (param i32) (result i32) + i32.const 12 + local.tee 0 + i32.const 2 + i32.const 3 + call $f + ) + (func (;34;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 13 + local.tee 0 + i32.const 3 + call $f + ) + (func (;35;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + i32.const 14 + local.tee 0 + call $f + ) + (func (;36;) (type 5) (param i32) (result i32) + i32.const 1 + local.tee 0 + i32.const 2 + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;37;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.tee 0 + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;38;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + local.tee 0 + i32.const 0 + call_indirect (type $sig) + ) + (func (;39;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 0 + local.tee 0 + call_indirect (type $sig) + ) + (func (;40;) (type 12) + (local i32) + i32.const 1 + local.tee 0 + local.set 0 + ) + (func (;41;) (type 5) (param i32) (result i32) + i32.const 1 + local.tee 0 + local.tee 0 + ) + (func (;42;) (type 12) + (local i32) + i32.const 1 + local.tee 0 + global.set $g + ) + (func (;43;) (type 5) (param i32) (result i32) + i32.const 1 + local.tee 0 + i32.load + ) + (func (;44;) (type 5) (param i32) (result i32) + i32.const 3 + local.tee 0 + i32.load8_s + ) + (func (;45;) (type 13) (param i32) + i32.const 30 + local.tee 0 + i32.const 7 + i32.store + ) + (func (;46;) (type 13) (param i32) + i32.const 2 + i32.const 1 + local.tee 0 + i32.store + ) + (func (;47;) (type 13) (param i32) + i32.const 1 + local.tee 0 + i32.const 7 + i32.store8 + ) + (func (;48;) (type 13) (param i32) + i32.const 2 + i32.const 1 + local.tee 0 + i32.store16 + ) + (func (;49;) (type 7) (param f32) (result f32) + f32.const nan:0xf1e2 (;=NaN;) + local.tee 0 + f32.neg + ) + (func (;50;) (type 5) (param i32) (result i32) + i32.const 3 + local.tee 0 + i32.const 10 + i32.add + ) + (func (;51;) (type 5) (param i32) (result i32) + i32.const 10 + i32.const 4 + local.tee 0 + i32.sub + ) + (func (;52;) (type 5) (param i32) (result i32) + i32.const 0 + local.tee 0 + i32.eqz + ) + (func (;53;) (type 5) (param i32) (result i32) + i32.const 43 + local.tee 0 + i32.const 10 + i32.le_s + ) + (func (;54;) (type 5) (param i32) (result i32) + i32.const 10 + i32.const 42 + local.tee 0 + i32.ne + ) + (func (;55;) (type 15) (param i64) (result i32) + i64.const 41 + local.tee 0 + i32.wrap_i64 + ) + (func (;56;) (type 5) (param i32) (result i32) + i32.const 40 + local.tee 0 + memory.grow + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $g (;0;) (mut i32) i32.const 0) + (export "type-local-i32" (func 0)) + (export "type-local-i64" (func 1)) + (export "type-local-f32" (func 2)) + (export "type-local-f64" (func 3)) + (export "type-param-i32" (func 4)) + (export "type-param-i64" (func 5)) + (export "type-param-f32" (func 6)) + (export "type-param-f64" (func 7)) + (export "type-mixed" (func 8)) + (export "write" (func 9)) + (export "result" (func 10)) + (export "as-block-first" (func 12)) + (export "as-block-mid" (func 13)) + (export "as-block-last" (func 14)) + (export "as-loop-first" (func 15)) + (export "as-loop-mid" (func 16)) + (export "as-loop-last" (func 17)) + (export "as-br-value" (func 18)) + (export "as-br_if-cond" (func 19)) + (export "as-br_if-value" (func 20)) + (export "as-br_if-value-cond" (func 21)) + (export "as-br_table-index" (func 22)) + (export "as-br_table-value" (func 23)) + (export "as-br_table-value-index" (func 24)) + (export "as-return-value" (func 25)) + (export "as-if-cond" (func 26)) + (export "as-if-then" (func 27)) + (export "as-if-else" (func 28)) + (export "as-select-first" (func 29)) + (export "as-select-second" (func 30)) + (export "as-select-cond" (func 31)) + (export "as-call-first" (func 33)) + (export "as-call-mid" (func 34)) + (export "as-call-last" (func 35)) + (export "as-call_indirect-first" (func 36)) + (export "as-call_indirect-mid" (func 37)) + (export "as-call_indirect-last" (func 38)) + (export "as-call_indirect-index" (func 39)) + (export "as-local.set-value" (func 40)) + (export "as-local.tee-value" (func 41)) + (export "as-global.set-value" (func 42)) + (export "as-load-address" (func 43)) + (export "as-loadN-address" (func 44)) + (export "as-store-address" (func 45)) + (export "as-store-value" (func 46)) + (export "as-storeN-address" (func 47)) + (export "as-storeN-value" (func 48)) + (export "as-unary-operand" (func 49)) + (export "as-binary-left" (func 50)) + (export "as-binary-right" (func 51)) + (export "as-test-operand" (func 52)) + (export "as-compare-left" (func 53)) + (export "as-compare-right" (func 54)) + (export "as-convert-operand" (func 55)) + (export "as-memory.grow-size" (func 56)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/loop.wast/0.print b/tests/snapshots/testsuite/loop.wast/0.print new file mode 100644 index 0000000000..db81e22883 --- /dev/null +++ b/tests/snapshots/testsuite/loop.wast/0.print @@ -0,0 +1,889 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type $block-sig-1 (;1;) (func)) + (type $block-sig-2 (;2;) (func (result i32))) + (type $block-sig-3 (;3;) (func (param i32))) + (type $block-sig-4 (;4;) (func (param i32 f64 i32) (result i32 f64 i32))) + (type (;5;) (func (result i32 i64 i32))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (result i32 i32))) + (type (;8;) (func (result f32 f32))) + (type (;9;) (func (result i32 i32 i64))) + (type (;10;) (func (param i32 i32 i64))) + (type (;11;) (func (param i32 i32) (result i32 i32))) + (type (;12;) (func (param i64) (result i64))) + (type (;13;) (func (param f32 f32) (result f32))) + (func $dummy (;0;) (type $block-sig-1)) + (func (;1;) (type $block-sig-1) + loop ;; label = @1 + end + loop $l ;; label = @1 + end + ) + (func (;2;) (type $block-sig-2) (result i32) + loop ;; label = @1 + nop + end + loop (result i32) ;; label = @1 + i32.const 7 + end + ) + (func (;3;) (type $block-sig-2) (result i32) + loop ;; label = @1 + call $dummy + call $dummy + call $dummy + call $dummy + end + loop (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 8 + call $dummy + end + drop + loop (type 5) (result i32 i64 i32) ;; label = @1 + call $dummy + call $dummy + call $dummy + i32.const 8 + call $dummy + call $dummy + call $dummy + call $dummy + i64.const 7 + call $dummy + call $dummy + call $dummy + call $dummy + i32.const 9 + call $dummy + end + drop + drop + ) + (func (;4;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + loop ;; label = @2 + call $dummy + block ;; label = @3 + end + nop + end + loop (result i32) ;; label = @2 + call $dummy + i32.const 9 + end + end + ) + (func (;5;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + block (result i32) ;; label = @2 + loop (result i32) ;; label = @3 + block (result i32) ;; label = @4 + loop (result i32) ;; label = @5 + block (result i32) ;; label = @6 + loop (result i32) ;; label = @7 + block (result i32) ;; label = @8 + loop (result i32) ;; label = @9 + block (result i32) ;; label = @10 + loop (result i32) ;; label = @11 + block (result i32) ;; label = @12 + loop (result i32) ;; label = @13 + block (result i32) ;; label = @14 + loop (result i32) ;; label = @15 + block (result i32) ;; label = @16 + loop (result i32) ;; label = @17 + block (result i32) ;; label = @18 + loop (result i32) ;; label = @19 + block (result i32) ;; label = @20 + loop (result i32) ;; label = @21 + block (result i32) ;; label = @22 + loop (result i32) ;; label = @23 + block (result i32) ;; label = @24 + loop (result i32) ;; label = @25 + block (result i32) ;; label = @26 + loop (result i32) ;; label = @27 + block (result i32) ;; label = @28 + loop (result i32) ;; label = @29 + block (result i32) ;; label = @30 + loop (result i32) ;; label = @31 + block (result i32) ;; label = @32 + loop (result i32) ;; label = @33 + block (result i32) ;; label = @34 + loop (result i32) ;; label = @35 + block (result i32) ;; label = @36 + loop (result i32) ;; label = @37 + block (result i32) ;; label = @38 + loop (result i32) ;; label = @39 + block (result i32) ;; label = @40 + call $dummy + i32.const 150 + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + ) + (func (;6;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + i32.const 1 + end + i32.const 2 + i32.const 3 + select + ) + (func (;7;) (type $block-sig-2) (result i32) + i32.const 2 + loop (result i32) ;; label = @1 + i32.const 1 + end + i32.const 3 + select + ) + (func (;8;) (type $block-sig-2) (result i32) + i32.const 2 + i32.const 3 + loop (result i32) ;; label = @1 + i32.const 1 + end + select + ) + (func (;9;) (type $block-sig-1) + loop (result i32) ;; label = @1 + i32.const 1 + end + if ;; label = @1 + call $dummy + end + ) + (func (;10;) (type $block-sig-2) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 1 + end + else + i32.const 2 + end + ) + (func (;11;) (type $block-sig-2) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 2 + else + loop (result i32) ;; label = @2 + i32.const 1 + end + end + ) + (func (;12;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 1 + end + i32.const 2 + br_if 0 (;@1;) + end + ) + (func (;13;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + loop (result i32) ;; label = @2 + i32.const 1 + end + br_if 0 (;@1;) + end + ) + (func (;14;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 1 + end + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;15;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + loop (result i32) ;; label = @2 + i32.const 1 + end + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;16;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;17;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 1 + end + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;18;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + loop (result i32) ;; label = @2 + i32.const 1 + end + i32.const 0 + call_indirect (type $check) + end + ) + (func (;19;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + loop (result i32) ;; label = @2 + i32.const 0 + end + call_indirect (type $check) + end + ) + (func (;20;) (type $block-sig-1) + loop (result i32) ;; label = @1 + i32.const 1 + end + i32.const 1 + i32.store + ) + (func (;21;) (type $block-sig-1) + i32.const 10 + loop (result i32) ;; label = @1 + i32.const 1 + end + i32.store + ) + (func (;22;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + i32.const 1 + end + memory.grow + ) + (func $f (;23;) (type 6) (param i32) (result i32) + local.get 0 + ) + (func (;24;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + i32.const 1 + end + call $f + ) + (func (;25;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + i32.const 1 + end + return + ) + (func (;26;) (type $block-sig-1) + loop (result i32) ;; label = @1 + i32.const 1 + end + drop + ) + (func (;27;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 1 + end + br 0 (;@1;) + end + ) + (func (;28;) (type $block-sig-2) (result i32) + (local i32) + loop (result i32) ;; label = @1 + i32.const 1 + end + local.set 0 + local.get 0 + ) + (func (;29;) (type $block-sig-2) (result i32) + (local i32) + loop (result i32) ;; label = @1 + i32.const 1 + end + local.tee 0 + ) + (func (;30;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + i32.const 1 + end + global.set $a + global.get $a + ) + (func (;31;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + i32.const 1 + end + i32.load + ) + (func (;32;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 13 + end + i32.ctz + ) + (func (;33;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 3 + end + loop (result i32) ;; label = @1 + call $dummy + i32.const 4 + end + i32.mul + ) + (func (;34;) (type $block-sig-2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 13 + end + i32.eqz + ) + (func (;35;) (type $block-sig-2) (result i32) + loop (result f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + end + loop (result f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + end + f32.gt + ) + (func (;36;) (type $block-sig-2) (result i32) + loop (type 7) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + end + i32.mul + ) + (func (;37;) (type $block-sig-2) (result i32) + loop (type 8) (result f32 f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + call $dummy + f32.const 0x1.8p+1 (;=3;) + end + f32.gt + ) + (func (;38;) (type $block-sig-2) (result i32) + loop (type 7) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + end + i32.const 5 + i32.add + i32.mul + ) + (func (;39;) (type $block-sig-2) (result i32) + block ;; label = @1 + loop ;; label = @2 + br 1 (;@1;) + br 0 (;@2;) + unreachable + end + end + block ;; label = @1 + loop ;; label = @2 + i32.const 1 + br_if 1 (;@1;) + unreachable + end + end + block ;; label = @1 + loop ;; label = @2 + i32.const 0 + br_table 1 (;@1;) + unreachable + end + end + block ;; label = @1 + loop ;; label = @2 + i32.const 1 + br_table 1 (;@1;) 1 (;@1;) 1 (;@1;) + unreachable + end + end + i32.const 19 + ) + (func (;40;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + loop (type $block-sig-3) (param i32) ;; label = @2 + block ;; label = @3 + i32.const 18 + br 2 (;@1;) + end + i32.const 20 + br 0 (;@2;) + end + i32.const 19 + end + ) + (func (;41;) (type 9) (result i32 i32 i64) + block (type 9) (result i32 i32 i64) ;; label = @1 + i32.const 0 + i32.const 0 + i64.const 0 + loop (type 10) (param i32 i32 i64) ;; label = @2 + block ;; label = @3 + i32.const 18 + i32.const -18 + i64.const 18 + br 2 (;@1;) + end + i32.const 20 + i32.const -20 + i64.const 20 + br 0 (;@2;) + end + i32.const 19 + i32.const -19 + i64.const 19 + end + ) + (func (;42;) (type $block-sig-2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 18 + br 1 (;@1;) + i32.const 19 + br 1 (;@1;) + i32.const 20 + i32.const 0 + br_if 1 (;@1;) + drop + i32.const 20 + i32.const 1 + br_if 1 (;@1;) + drop + i32.const 21 + br 1 (;@1;) + i32.const 22 + i32.const 0 + br_table 1 (;@1;) + i32.const 23 + i32.const 1 + br_table 1 (;@1;) 1 (;@1;) 1 (;@1;) + i32.const 21 + end + end + ) + (func (;43;) (type $block-sig-2) (result i32) + (local i32) + i32.const 0 + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + block (result i32) ;; label = @3 + i32.const 1 + br 2 (;@1;) + end + end + end + i32.add + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + loop (result i32) ;; label = @3 + i32.const 2 + br 2 (;@1;) + end + end + end + i32.add + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + block (result i32) ;; label = @3 + loop (result i32) ;; label = @4 + i32.const 4 + br 1 (;@3;) + end + end + end + end + i32.add + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 8 + br 1 (;@1;) + i32.ctz + end + end + i32.add + local.set 0 + local.get 0 + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + loop (result i32) ;; label = @3 + i32.const 16 + br 2 (;@1;) + end + i32.ctz + end + end + i32.add + local.set 0 + local.get 0 + ) + (func (;44;) (type $block-sig-2) (result i32) + (local i32) + i32.const 0 + local.set 0 + local.get 0 + loop (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + br 1 (;@1;) + end + end + i32.add + local.set 0 + local.get 0 + loop (result i32) ;; label = @1 + br 0 (;@1;) + i32.ctz + end + i32.add + local.set 0 + local.get 0 + loop (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + br 1 (;@1;) + end + i32.ctz + end + i32.add + local.set 0 + local.get 0 + ) + (func (;45;) (type $block-sig-2) (result i32) + i32.const 1 + loop (type 6) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + end + ) + (func (;46;) (type $block-sig-2) (result i32) + i32.const 1 + i32.const 2 + loop (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + end + ) + (func (;47;) (type $block-sig-2) (result i32) + i32.const 1 + i32.const 2 + loop (type 11) (param i32 i32) (result i32 i32) ;; label = @1 + end + i32.add + ) + (func (;48;) (type $block-sig-2) (result i32) + (local $x i32) + i32.const 1 + loop (type 6) (param i32) (result i32) ;; label = @1 + i32.const 4 + i32.add + local.tee $x + local.get $x + i32.const 10 + i32.lt_u + br_if 0 (;@1;) + end + ) + (func (;49;) (type $block-sig-2) (result i32) + (local $x i32) + i32.const 1 + i32.const 2 + loop (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + local.tee $x + i32.const 3 + local.get $x + i32.const 10 + i32.lt_u + br_if 0 (;@1;) + drop + end + ) + (func (;50;) (type $block-sig-2) (result i32) + (local $x i32) + i32.const 0 + local.set $x + i32.const 1 + i32.const 2 + loop (type 11) (param i32 i32) (result i32 i32) ;; label = @1 + local.get $x + i32.const 1 + i32.add + local.set $x + local.get $x + i32.const 10 + i32.lt_u + br_if 0 (;@1;) + end + i32.add + ) + (func $fx (;51;) (type $block-sig-2) (result i32) + (local i32) + block ;; label = @1 + loop ;; label = @2 + i32.const 1 + local.set 0 + local.get 0 + i32.const 3 + i32.mul + local.set 0 + local.get 0 + i32.const 5 + i32.sub + local.set 0 + local.get 0 + i32.const 7 + i32.mul + local.set 0 + br 1 (;@1;) + local.get 0 + i32.const 100 + i32.mul + local.set 0 + end + end + local.get 0 + i32.const -14 + i32.eq + ) + (func (;52;) (type 12) (param i64) (result i64) + (local i64) + i64.const 1 + local.set 1 + block ;; label = @1 + loop ;; label = @2 + local.get 0 + i64.eqz + br_if 1 (;@1;) + local.get 0 + local.get 1 + i64.mul + local.set 1 + local.get 0 + i64.const 1 + i64.sub + local.set 0 + br 0 (;@2;) + end + end + local.get 1 + ) + (func (;53;) (type 12) (param i64) (result i64) + (local i64 i64) + i64.const 1 + local.set 1 + i64.const 2 + local.set 2 + block ;; label = @1 + loop ;; label = @2 + local.get 2 + local.get 0 + i64.gt_u + br_if 1 (;@1;) + local.get 1 + local.get 2 + i64.mul + local.set 1 + local.get 2 + i64.const 1 + i64.add + local.set 2 + br 0 (;@2;) + end + end + local.get 1 + ) + (func (;54;) (type 13) (param f32 f32) (result f32) + (local f32 f32) + block ;; label = @1 + loop ;; label = @2 + local.get 0 + f32.const 0x0p+0 (;=0;) + f32.eq + br_if 1 (;@1;) + local.get 1 + local.set 2 + block ;; label = @3 + loop ;; label = @4 + local.get 2 + f32.const 0x0p+0 (;=0;) + f32.eq + br_if 1 (;@3;) + local.get 2 + f32.const 0x0p+0 (;=0;) + f32.lt + br_if 3 (;@1;) + local.get 3 + local.get 2 + f32.add + local.set 3 + local.get 2 + f32.const 0x1p+1 (;=2;) + f32.sub + local.set 2 + br 0 (;@4;) + end + end + local.get 3 + local.get 0 + f32.div + local.set 3 + local.get 0 + f32.const 0x1p+0 (;=1;) + f32.sub + local.set 0 + br 0 (;@2;) + end + end + local.get 3 + ) + (func (;55;) (type $block-sig-1) + loop (type $block-sig-1) ;; label = @1 + end + loop (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + end + loop (type $block-sig-3) (param i32) ;; label = @1 + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + loop (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + loop (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + end + loop (type $block-sig-3) (param i32) ;; label = @1 + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + loop (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 0) + (export "empty" (func 1)) + (export "singular" (func 2)) + (export "multi" (func 3)) + (export "nested" (func 4)) + (export "deep" (func 5)) + (export "as-select-first" (func 6)) + (export "as-select-mid" (func 7)) + (export "as-select-last" (func 8)) + (export "as-if-condition" (func 9)) + (export "as-if-then" (func 10)) + (export "as-if-else" (func 11)) + (export "as-br_if-first" (func 12)) + (export "as-br_if-last" (func 13)) + (export "as-br_table-first" (func 14)) + (export "as-br_table-last" (func 15)) + (export "as-call_indirect-first" (func 17)) + (export "as-call_indirect-mid" (func 18)) + (export "as-call_indirect-last" (func 19)) + (export "as-store-first" (func 20)) + (export "as-store-last" (func 21)) + (export "as-memory.grow-value" (func 22)) + (export "as-call-value" (func 24)) + (export "as-return-value" (func 25)) + (export "as-drop-operand" (func 26)) + (export "as-br-value" (func 27)) + (export "as-local.set-value" (func 28)) + (export "as-local.tee-value" (func 29)) + (export "as-global.set-value" (func 30)) + (export "as-load-operand" (func 31)) + (export "as-unary-operand" (func 32)) + (export "as-binary-operand" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-operand" (func 35)) + (export "as-binary-operands" (func 36)) + (export "as-compare-operands" (func 37)) + (export "as-mixed-operands" (func 38)) + (export "break-bare" (func 39)) + (export "break-value" (func 40)) + (export "break-multi-value" (func 41)) + (export "break-repeated" (func 42)) + (export "break-inner" (func 43)) + (export "cont-inner" (func 44)) + (export "param" (func 45)) + (export "params" (func 46)) + (export "params-id" (func 47)) + (export "param-break" (func 48)) + (export "params-break" (func 49)) + (export "params-id-break" (func 50)) + (export "effects" (func $fx)) + (export "while" (func 52)) + (export "for" (func 53)) + (export "nesting" (func 54)) + (export "type-use" (func 55)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/0.print b/tests/snapshots/testsuite/memory.wast/0.print new file mode 100644 index 0000000000..36938759b9 --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/0.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/1.print b/tests/snapshots/testsuite/memory.wast/1.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/1.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/10.print b/tests/snapshots/testsuite/memory.wast/10.print new file mode 100644 index 0000000000..0cdda46d31 --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/10.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0 0) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/12.print b/tests/snapshots/testsuite/memory.wast/12.print new file mode 100644 index 0000000000..94e698954c --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/12.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 1 1) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "x") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/2.print b/tests/snapshots/testsuite/memory.wast/2.print new file mode 100644 index 0000000000..d76aa6a0fa --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/2.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/3.print b/tests/snapshots/testsuite/memory.wast/3.print new file mode 100644 index 0000000000..0f5c3ea229 --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/3.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/33.print b/tests/snapshots/testsuite/memory.wast/33.print new file mode 100644 index 0000000000..1dc6026a7b --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/33.print @@ -0,0 +1,154 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result f64))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i64) (result i64))) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.load8_u + i32.const 65 + i32.eq + i32.const 3 + i32.load8_u + i32.const 167 + i32.eq + i32.and + i32.const 6 + i32.load8_u + i32.const 0 + i32.eq + i32.const 19 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.const 20 + i32.load8_u + i32.const 87 + i32.eq + i32.const 23 + i32.load8_u + i32.const 77 + i32.eq + i32.and + i32.const 24 + i32.load8_u + i32.const 0 + i32.eq + i32.const 1023 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.and + ) + (func (;1;) (type 1) (result f64) + i32.const 8 + i64.const -12345 + i64.store + i32.const 8 + f64.load + i64.const -12345 + f64.reinterpret_i64 + f64.eq + if ;; label = @1 + f64.const 0x0p+0 (;=0;) + return + end + i32.const 9 + i64.const 0 + i64.store align=1 + i32.const 15 + i32.const 16453 + i32.store16 align=1 + i32.const 9 + f64.load align=1 + ) + (func (;2;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store8 + i32.const 8 + i32.load8_s + ) + (func (;3;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store8 + i32.const 8 + i32.load8_u + ) + (func (;4;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store16 + i32.const 8 + i32.load16_s + ) + (func (;5;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store16 + i32.const 8 + i32.load16_u + ) + (func (;6;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store8 + i32.const 8 + i64.load8_s + ) + (func (;7;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store8 + i32.const 8 + i64.load8_u + ) + (func (;8;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store16 + i32.const 8 + i64.load16_s + ) + (func (;9;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store16 + i32.const 8 + i64.load16_u + ) + (func (;10;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store32 + i32.const 8 + i64.load32_s + ) + (func (;11;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store32 + i32.const 8 + i64.load32_u + ) + (memory (;0;) 1) + (export "data" (func 0)) + (export "cast" (func 1)) + (export "i32_load8_s" (func 2)) + (export "i32_load8_u" (func 3)) + (export "i32_load16_s" (func 4)) + (export "i32_load16_u" (func 5)) + (export "i64_load8_s" (func 6)) + (export "i64_load8_u" (func 7)) + (export "i64_load16_s" (func 8)) + (export "i64_load16_u" (func 9)) + (export "i64_load32_s" (func 10)) + (export "i64_load32_u" (func 11)) + (data (;0;) (i32.const 0) "ABC\a7D") + (data (;1;) (i32.const 20) "WASM") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/4.print b/tests/snapshots/testsuite/memory.wast/4.print new file mode 100644 index 0000000000..d280c1e33b --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/4.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1 256) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/5.print b/tests/snapshots/testsuite/memory.wast/5.print new file mode 100644 index 0000000000..21d5f6b5c9 --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/5.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 65536) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory.wast/8.print b/tests/snapshots/testsuite/memory.wast/8.print new file mode 100644 index 0000000000..0cdda46d31 --- /dev/null +++ b/tests/snapshots/testsuite/memory.wast/8.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0 0) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/0.print b/tests/snapshots/testsuite/memory_copy.wast/0.print new file mode 100644 index 0000000000..70fd2c3e66 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/0.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + nop + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) (i32.const 12) "\07\05\02\03\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/128.print b/tests/snapshots/testsuite/memory_copy.wast/128.print new file mode 100644 index 0000000000..7f95e7bc2a --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/128.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 20 + i32.const 22 + i32.const 4 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) (i32.const 12) "\07\05\02\03\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/1310.print b/tests/snapshots/testsuite/memory_copy.wast/1310.print new file mode 100644 index 0000000000..2ab72e8b7b --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/1310.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 65515) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/160.print b/tests/snapshots/testsuite/memory_copy.wast/160.print new file mode 100644 index 0000000000..55d249f5f9 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/160.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 25 + i32.const 1 + i32.const 3 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) (i32.const 12) "\07\05\02\03\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/1662.print b/tests/snapshots/testsuite/memory_copy.wast/1662.print new file mode 100644 index 0000000000..1f391903f2 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/1662.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 65486) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/192.print b/tests/snapshots/testsuite/memory_copy.wast/192.print new file mode 100644 index 0000000000..36e54f9097 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/192.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 10 + i32.const 12 + i32.const 7 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) (i32.const 12) "\07\05\02\03\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/2013.print b/tests/snapshots/testsuite/memory_copy.wast/2013.print new file mode 100644 index 0000000000..20dbbc631a --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/2013.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/224.print b/tests/snapshots/testsuite/memory_copy.wast/224.print new file mode 100644 index 0000000000..213240a99a --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/224.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 12 + i32.const 10 + i32.const 7 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) (i32.const 12) "\07\05\02\03\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/2364.print b/tests/snapshots/testsuite/memory_copy.wast/2364.print new file mode 100644 index 0000000000..7233a9535a --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/2364.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 65506) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/256.print b/tests/snapshots/testsuite/memory_copy.wast/256.print new file mode 100644 index 0000000000..2b12e8a97e --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/256.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/2715.print b/tests/snapshots/testsuite/memory_copy.wast/2715.print new file mode 100644 index 0000000000..20dbbc631a --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/2715.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/3066.print b/tests/snapshots/testsuite/memory_copy.wast/3066.print new file mode 100644 index 0000000000..20dbbc631a --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/3066.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/32.print b/tests/snapshots/testsuite/memory_copy.wast/32.print new file mode 100644 index 0000000000..693fc1a40c --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/32.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 13 + i32.const 2 + i32.const 3 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) (i32.const 12) "\07\05\02\03\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/3417.print b/tests/snapshots/testsuite/memory_copy.wast/3417.print new file mode 100644 index 0000000000..29df390150 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/3417.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/3768.print b/tests/snapshots/testsuite/memory_copy.wast/3768.print new file mode 100644 index 0000000000..80d7791181 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/3768.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 61440) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4183.print b/tests/snapshots/testsuite/memory_copy.wast/4183.print new file mode 100644 index 0000000000..58eb71b25f --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4183.print @@ -0,0 +1,41 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32 i32 i32) (result i32))) + (func (;0;) (type 0) + i32.const 10 + i32.const 85 + i32.const 10 + memory.fill + i32.const 9 + i32.const 10 + i32.const 5 + memory.copy + ) + (func (;1;) (type 1) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (memory (;0;) 1 1) + (export "test" (func 0)) + (export "checkRange" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4188.print b/tests/snapshots/testsuite/memory_copy.wast/4188.print new file mode 100644 index 0000000000..0c745c28f1 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4188.print @@ -0,0 +1,41 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32 i32 i32) (result i32))) + (func (;0;) (type 0) + i32.const 10 + i32.const 85 + i32.const 10 + memory.fill + i32.const 16 + i32.const 15 + i32.const 5 + memory.copy + ) + (func (;1;) (type 1) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (memory (;0;) 1 1) + (export "test" (func 0)) + (export "checkRange" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4193.print b/tests/snapshots/testsuite/memory_copy.wast/4193.print new file mode 100644 index 0000000000..5c72ff3007 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4193.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 65280 + i32.const 32768 + i32.const 257 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4195.print b/tests/snapshots/testsuite/memory_copy.wast/4195.print new file mode 100644 index 0000000000..17e7ac1d07 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4195.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const -256 + i32.const 16384 + i32.const 257 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4197.print b/tests/snapshots/testsuite/memory_copy.wast/4197.print new file mode 100644 index 0000000000..f4a2cd0b24 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4197.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 32768 + i32.const 65280 + i32.const 257 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4199.print b/tests/snapshots/testsuite/memory_copy.wast/4199.print new file mode 100644 index 0000000000..490b808f80 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4199.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 16384 + i32.const -256 + i32.const 257 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4201.print b/tests/snapshots/testsuite/memory_copy.wast/4201.print new file mode 100644 index 0000000000..b39d231fcf --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4201.print @@ -0,0 +1,45 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32 i32 i32) (result i32))) + (func (;0;) (type 0) + i32.const 0 + i32.const 85 + i32.const 32768 + memory.fill + i32.const 32768 + i32.const 170 + i32.const 32768 + memory.fill + i32.const 36864 + i32.const 28672 + i32.const 0 + memory.copy + ) + (func (;1;) (type 1) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (memory (;0;) 1 1) + (export "test" (func 0)) + (export "checkRange" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4205.print b/tests/snapshots/testsuite/memory_copy.wast/4205.print new file mode 100644 index 0000000000..864301c65e --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4205.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 65536 + i32.const 28672 + i32.const 0 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4207.print b/tests/snapshots/testsuite/memory_copy.wast/4207.print new file mode 100644 index 0000000000..51894173c0 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4207.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 131072 + i32.const 28672 + i32.const 0 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4209.print b/tests/snapshots/testsuite/memory_copy.wast/4209.print new file mode 100644 index 0000000000..6cec3052ba --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4209.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 36864 + i32.const 65536 + i32.const 0 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4211.print b/tests/snapshots/testsuite/memory_copy.wast/4211.print new file mode 100644 index 0000000000..b9c3141a43 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4211.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 36864 + i32.const 131072 + i32.const 0 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4213.print b/tests/snapshots/testsuite/memory_copy.wast/4213.print new file mode 100644 index 0000000000..42fd6cad20 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4213.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 65536 + i32.const 65536 + i32.const 0 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4215.print b/tests/snapshots/testsuite/memory_copy.wast/4215.print new file mode 100644 index 0000000000..a25435e973 --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4215.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 131072 + i32.const 131072 + i32.const 0 + memory.copy + ) + (memory (;0;) 1 1) + (export "test" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/4217.print b/tests/snapshots/testsuite/memory_copy.wast/4217.print new file mode 100644 index 0000000000..71447380aa --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/4217.print @@ -0,0 +1,833 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32 i32 i32) (result i32))) + (func (;0;) (type 0) + i32.const 17767 + i32.const 1 + i32.const 1344 + memory.fill + i32.const 39017 + i32.const 2 + i32.const 1055 + memory.fill + i32.const 56401 + i32.const 3 + i32.const 988 + memory.fill + i32.const 37962 + i32.const 4 + i32.const 322 + memory.fill + i32.const 7977 + i32.const 5 + i32.const 1994 + memory.fill + i32.const 22714 + i32.const 6 + i32.const 3036 + memory.fill + i32.const 16882 + i32.const 7 + i32.const 2372 + memory.fill + i32.const 43491 + i32.const 8 + i32.const 835 + memory.fill + i32.const 124 + i32.const 9 + i32.const 1393 + memory.fill + i32.const 2132 + i32.const 10 + i32.const 2758 + memory.fill + i32.const 8987 + i32.const 11 + i32.const 3098 + memory.fill + i32.const 52711 + i32.const 12 + i32.const 741 + memory.fill + i32.const 3958 + i32.const 13 + i32.const 2823 + memory.fill + i32.const 49715 + i32.const 14 + i32.const 1280 + memory.fill + i32.const 50377 + i32.const 15 + i32.const 1466 + memory.fill + i32.const 20493 + i32.const 16 + i32.const 3158 + memory.fill + i32.const 47665 + i32.const 17 + i32.const 544 + memory.fill + i32.const 12451 + i32.const 18 + i32.const 2669 + memory.fill + i32.const 24869 + i32.const 19 + i32.const 2651 + memory.fill + i32.const 45317 + i32.const 20 + i32.const 1570 + memory.fill + i32.const 43096 + i32.const 21 + i32.const 1691 + memory.fill + i32.const 33886 + i32.const 22 + i32.const 646 + memory.fill + i32.const 48555 + i32.const 23 + i32.const 1858 + memory.fill + i32.const 53453 + i32.const 24 + i32.const 2657 + memory.fill + i32.const 30363 + i32.const 25 + i32.const 981 + memory.fill + i32.const 9300 + i32.const 26 + i32.const 1807 + memory.fill + i32.const 50190 + i32.const 27 + i32.const 487 + memory.fill + i32.const 62753 + i32.const 28 + i32.const 530 + memory.fill + i32.const 36316 + i32.const 29 + i32.const 943 + memory.fill + i32.const 6768 + i32.const 30 + i32.const 381 + memory.fill + i32.const 51262 + i32.const 31 + i32.const 3089 + memory.fill + i32.const 49729 + i32.const 32 + i32.const 658 + memory.fill + i32.const 44540 + i32.const 33 + i32.const 1702 + memory.fill + i32.const 33342 + i32.const 34 + i32.const 1092 + memory.fill + i32.const 50814 + i32.const 35 + i32.const 1410 + memory.fill + i32.const 47594 + i32.const 36 + i32.const 2204 + memory.fill + i32.const 54123 + i32.const 37 + i32.const 2394 + memory.fill + i32.const 55183 + i32.const 38 + i32.const 250 + memory.fill + i32.const 22620 + i32.const 39 + i32.const 2097 + memory.fill + i32.const 17132 + i32.const 40 + i32.const 3264 + memory.fill + i32.const 54331 + i32.const 41 + i32.const 3299 + memory.fill + i32.const 39474 + i32.const 42 + i32.const 2796 + memory.fill + i32.const 36156 + i32.const 43 + i32.const 2070 + memory.fill + i32.const 35308 + i32.const 44 + i32.const 2763 + memory.fill + i32.const 32731 + i32.const 45 + i32.const 312 + memory.fill + i32.const 63746 + i32.const 46 + i32.const 192 + memory.fill + i32.const 30974 + i32.const 47 + i32.const 596 + memory.fill + i32.const 16635 + i32.const 48 + i32.const 501 + memory.fill + i32.const 57002 + i32.const 49 + i32.const 686 + memory.fill + i32.const 34299 + i32.const 50 + i32.const 385 + memory.fill + i32.const 60881 + i32.const 51 + i32.const 903 + memory.fill + i32.const 61445 + i32.const 52 + i32.const 2390 + memory.fill + i32.const 46972 + i32.const 53 + i32.const 1441 + memory.fill + i32.const 25973 + i32.const 54 + i32.const 3162 + memory.fill + i32.const 5566 + i32.const 55 + i32.const 2135 + memory.fill + i32.const 35977 + i32.const 56 + i32.const 519 + memory.fill + i32.const 44892 + i32.const 57 + i32.const 3280 + memory.fill + i32.const 46760 + i32.const 58 + i32.const 1678 + memory.fill + i32.const 46607 + i32.const 59 + i32.const 3168 + memory.fill + i32.const 22449 + i32.const 60 + i32.const 1441 + memory.fill + i32.const 58609 + i32.const 61 + i32.const 663 + memory.fill + i32.const 32261 + i32.const 62 + i32.const 1671 + memory.fill + i32.const 3063 + i32.const 63 + i32.const 721 + memory.fill + i32.const 34025 + i32.const 64 + i32.const 84 + memory.fill + i32.const 33338 + i32.const 65 + i32.const 2029 + memory.fill + i32.const 36810 + i32.const 66 + i32.const 29 + memory.fill + i32.const 19147 + i32.const 67 + i32.const 3034 + memory.fill + i32.const 12616 + i32.const 68 + i32.const 1043 + memory.fill + i32.const 18276 + i32.const 69 + i32.const 3324 + memory.fill + i32.const 4639 + i32.const 70 + i32.const 1091 + memory.fill + i32.const 16158 + i32.const 71 + i32.const 1997 + memory.fill + i32.const 18204 + i32.const 72 + i32.const 2259 + memory.fill + i32.const 50532 + i32.const 73 + i32.const 3189 + memory.fill + i32.const 11028 + i32.const 74 + i32.const 1968 + memory.fill + i32.const 15962 + i32.const 75 + i32.const 1455 + memory.fill + i32.const 45406 + i32.const 76 + i32.const 1177 + memory.fill + i32.const 54137 + i32.const 77 + i32.const 1568 + memory.fill + i32.const 33083 + i32.const 78 + i32.const 1642 + memory.fill + i32.const 61028 + i32.const 79 + i32.const 3284 + memory.fill + i32.const 51729 + i32.const 80 + i32.const 223 + memory.fill + i32.const 4361 + i32.const 81 + i32.const 2171 + memory.fill + i32.const 57514 + i32.const 82 + i32.const 1322 + memory.fill + i32.const 55724 + i32.const 83 + i32.const 2648 + memory.fill + i32.const 24091 + i32.const 84 + i32.const 1045 + memory.fill + i32.const 43183 + i32.const 85 + i32.const 3097 + memory.fill + i32.const 32307 + i32.const 86 + i32.const 2796 + memory.fill + i32.const 3811 + i32.const 87 + i32.const 2010 + memory.fill + i32.const 54856 + i32.const 88 + i32.const 0 + memory.fill + i32.const 49941 + i32.const 89 + i32.const 2069 + memory.fill + i32.const 20411 + i32.const 90 + i32.const 2896 + memory.fill + i32.const 33826 + i32.const 91 + i32.const 192 + memory.fill + i32.const 9402 + i32.const 92 + i32.const 2195 + memory.fill + i32.const 12413 + i32.const 93 + i32.const 24 + memory.fill + i32.const 14091 + i32.const 94 + i32.const 577 + memory.fill + i32.const 44058 + i32.const 95 + i32.const 2089 + memory.fill + i32.const 36735 + i32.const 96 + i32.const 3436 + memory.fill + i32.const 23288 + i32.const 97 + i32.const 2765 + memory.fill + i32.const 6392 + i32.const 98 + i32.const 830 + memory.fill + i32.const 33307 + i32.const 99 + i32.const 1938 + memory.fill + i32.const 21941 + i32.const 100 + i32.const 2750 + memory.fill + i32.const 59214 + i32.const 54248 + i32.const 2098 + memory.copy + i32.const 63026 + i32.const 39224 + i32.const 230 + memory.copy + i32.const 51833 + i32.const 23629 + i32.const 2300 + memory.copy + i32.const 6708 + i32.const 23996 + i32.const 639 + memory.copy + i32.const 6990 + i32.const 33399 + i32.const 1097 + memory.copy + i32.const 19403 + i32.const 10348 + i32.const 3197 + memory.copy + i32.const 27308 + i32.const 54406 + i32.const 100 + memory.copy + i32.const 27221 + i32.const 43682 + i32.const 1717 + memory.copy + i32.const 60528 + i32.const 8629 + i32.const 119 + memory.copy + i32.const 5947 + i32.const 2308 + i32.const 658 + memory.copy + i32.const 4787 + i32.const 51631 + i32.const 2269 + memory.copy + i32.const 12617 + i32.const 19197 + i32.const 833 + memory.copy + i32.const 11854 + i32.const 46505 + i32.const 3300 + memory.copy + i32.const 11376 + i32.const 45012 + i32.const 2281 + memory.copy + i32.const 34186 + i32.const 6697 + i32.const 2572 + memory.copy + i32.const 4936 + i32.const 1690 + i32.const 1328 + memory.copy + i32.const 63164 + i32.const 7637 + i32.const 1670 + memory.copy + i32.const 44568 + i32.const 18344 + i32.const 33 + memory.copy + i32.const 43918 + i32.const 22348 + i32.const 1427 + memory.copy + i32.const 46637 + i32.const 49819 + i32.const 1434 + memory.copy + i32.const 63684 + i32.const 8755 + i32.const 834 + memory.copy + i32.const 33485 + i32.const 20131 + i32.const 3317 + memory.copy + i32.const 40575 + i32.const 54317 + i32.const 3201 + memory.copy + i32.const 25812 + i32.const 59254 + i32.const 2452 + memory.copy + i32.const 19678 + i32.const 56882 + i32.const 346 + memory.copy + i32.const 15852 + i32.const 35914 + i32.const 2430 + memory.copy + i32.const 11824 + i32.const 35574 + i32.const 300 + memory.copy + i32.const 59427 + i32.const 13957 + i32.const 3153 + memory.copy + i32.const 34299 + i32.const 60594 + i32.const 1281 + memory.copy + i32.const 8964 + i32.const 12276 + i32.const 943 + memory.copy + i32.const 2827 + i32.const 10425 + i32.const 1887 + memory.copy + i32.const 43194 + i32.const 43910 + i32.const 738 + memory.copy + i32.const 63038 + i32.const 18949 + i32.const 122 + memory.copy + i32.const 24044 + i32.const 44761 + i32.const 1755 + memory.copy + i32.const 22608 + i32.const 14755 + i32.const 702 + memory.copy + i32.const 11284 + i32.const 26579 + i32.const 1830 + memory.copy + i32.const 23092 + i32.const 20471 + i32.const 1064 + memory.copy + i32.const 57248 + i32.const 54770 + i32.const 2631 + memory.copy + i32.const 25492 + i32.const 1025 + i32.const 3113 + memory.copy + i32.const 49588 + i32.const 44220 + i32.const 975 + memory.copy + i32.const 28280 + i32.const 41722 + i32.const 2336 + memory.copy + i32.const 61289 + i32.const 230 + i32.const 2872 + memory.copy + i32.const 22480 + i32.const 52506 + i32.const 2197 + memory.copy + i32.const 40553 + i32.const 9578 + i32.const 1958 + memory.copy + i32.const 29004 + i32.const 20862 + i32.const 2186 + memory.copy + i32.const 53029 + i32.const 43955 + i32.const 1037 + memory.copy + i32.const 25476 + i32.const 35667 + i32.const 1650 + memory.copy + i32.const 58516 + i32.const 45819 + i32.const 1986 + memory.copy + i32.const 38297 + i32.const 5776 + i32.const 1955 + memory.copy + i32.const 28503 + i32.const 55364 + i32.const 2368 + memory.copy + i32.const 62619 + i32.const 18108 + i32.const 1356 + memory.copy + i32.const 50149 + i32.const 13861 + i32.const 382 + memory.copy + i32.const 16904 + i32.const 36341 + i32.const 1900 + memory.copy + i32.const 48098 + i32.const 11358 + i32.const 2807 + memory.copy + i32.const 28512 + i32.const 40362 + i32.const 323 + memory.copy + i32.const 35506 + i32.const 27856 + i32.const 1670 + memory.copy + i32.const 62970 + i32.const 53332 + i32.const 1341 + memory.copy + i32.const 14133 + i32.const 46312 + i32.const 644 + memory.copy + i32.const 29030 + i32.const 19074 + i32.const 496 + memory.copy + i32.const 44952 + i32.const 47577 + i32.const 2784 + memory.copy + i32.const 39559 + i32.const 44661 + i32.const 1350 + memory.copy + i32.const 10352 + i32.const 29274 + i32.const 1475 + memory.copy + i32.const 46911 + i32.const 46178 + i32.const 1467 + memory.copy + i32.const 4905 + i32.const 28740 + i32.const 1895 + memory.copy + i32.const 38012 + i32.const 57253 + i32.const 1751 + memory.copy + i32.const 26446 + i32.const 27223 + i32.const 1127 + memory.copy + i32.const 58835 + i32.const 24657 + i32.const 1063 + memory.copy + i32.const 61356 + i32.const 38790 + i32.const 766 + memory.copy + i32.const 44160 + i32.const 2284 + i32.const 1520 + memory.copy + i32.const 32740 + i32.const 47237 + i32.const 3014 + memory.copy + i32.const 11148 + i32.const 21260 + i32.const 1011 + memory.copy + i32.const 7665 + i32.const 31612 + i32.const 3034 + memory.copy + i32.const 18044 + i32.const 12987 + i32.const 3320 + memory.copy + i32.const 57306 + i32.const 55905 + i32.const 308 + memory.copy + i32.const 24675 + i32.const 16815 + i32.const 1155 + memory.copy + i32.const 19900 + i32.const 10115 + i32.const 722 + memory.copy + i32.const 2921 + i32.const 5935 + i32.const 2370 + memory.copy + i32.const 32255 + i32.const 50095 + i32.const 2926 + memory.copy + i32.const 15126 + i32.const 17299 + i32.const 2607 + memory.copy + i32.const 45575 + i32.const 28447 + i32.const 2045 + memory.copy + i32.const 55149 + i32.const 36113 + i32.const 2596 + memory.copy + i32.const 28461 + i32.const 54157 + i32.const 1168 + memory.copy + i32.const 47951 + i32.const 53385 + i32.const 3137 + memory.copy + i32.const 30646 + i32.const 45155 + i32.const 2649 + memory.copy + i32.const 5057 + i32.const 4295 + i32.const 52 + memory.copy + i32.const 6692 + i32.const 24195 + i32.const 441 + memory.copy + i32.const 32984 + i32.const 27117 + i32.const 3445 + memory.copy + i32.const 32530 + i32.const 59372 + i32.const 2785 + memory.copy + i32.const 34361 + i32.const 8962 + i32.const 2406 + memory.copy + i32.const 17893 + i32.const 54538 + i32.const 3381 + memory.copy + i32.const 22685 + i32.const 44151 + i32.const 136 + memory.copy + i32.const 59089 + i32.const 7077 + i32.const 1045 + memory.copy + i32.const 42945 + i32.const 55028 + i32.const 2389 + memory.copy + i32.const 44693 + i32.const 20138 + i32.const 877 + memory.copy + i32.const 36810 + i32.const 25196 + i32.const 3447 + memory.copy + i32.const 45742 + i32.const 31888 + i32.const 854 + memory.copy + i32.const 24236 + i32.const 31866 + i32.const 1377 + memory.copy + i32.const 33778 + i32.const 692 + i32.const 1594 + memory.copy + i32.const 60618 + i32.const 18585 + i32.const 2987 + memory.copy + i32.const 50370 + i32.const 41271 + i32.const 1406 + memory.copy + ) + (func (;1;) (type 1) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (memory (;0;) 1 1) + (export "test" (func 0)) + (export "checkRange" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/607.print b/tests/snapshots/testsuite/memory_copy.wast/607.print new file mode 100644 index 0000000000..05b470ea4a --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/607.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/64.print b/tests/snapshots/testsuite/memory_copy.wast/64.print new file mode 100644 index 0000000000..543614a16c --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/64.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 25 + i32.const 15 + i32.const 2 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) (i32.const 12) "\07\05\02\03\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/959.print b/tests/snapshots/testsuite/memory_copy.wast/959.print new file mode 100644 index 0000000000..20dbbc631a --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/959.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "mem" (memory 0)) + (export "run" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_copy.wast/96.print b/tests/snapshots/testsuite/memory_copy.wast/96.print new file mode 100644 index 0000000000..868e51fb4d --- /dev/null +++ b/tests/snapshots/testsuite/memory_copy.wast/96.print @@ -0,0 +1,20 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 13 + i32.const 25 + i32.const 3 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) (i32.const 12) "\07\05\02\03\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/0.print b/tests/snapshots/testsuite/memory_fill.wast/0.print new file mode 100644 index 0000000000..f2b7dabbb6 --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/0.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) + i32.const 65280 + i32.const 85 + i32.const 256 + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "test" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/11.print b/tests/snapshots/testsuite/memory_fill.wast/11.print new file mode 100644 index 0000000000..ce65f9c38b --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/11.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) + i32.const 65536 + i32.const 85 + i32.const 0 + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "test" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/13.print b/tests/snapshots/testsuite/memory_fill.wast/13.print new file mode 100644 index 0000000000..c2277bdbf4 --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/13.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) + i32.const 131072 + i32.const 85 + i32.const 0 + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "test" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/15.print b/tests/snapshots/testsuite/memory_fill.wast/15.print new file mode 100644 index 0000000000..b12253a4b5 --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/15.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) + i32.const 1 + i32.const 170 + i32.const 65534 + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "test" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/20.print b/tests/snapshots/testsuite/memory_fill.wast/20.print new file mode 100644 index 0000000000..2dc6f6eed6 --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/20.print @@ -0,0 +1,41 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) + i32.const 18 + i32.const 85 + i32.const 10 + memory.fill + i32.const 21 + i32.const 170 + i32.const 4 + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "test" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/4.print b/tests/snapshots/testsuite/memory_fill.wast/4.print new file mode 100644 index 0000000000..23b5374177 --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/4.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) + i32.const 65280 + i32.const 85 + i32.const 257 + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "test" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/6.print b/tests/snapshots/testsuite/memory_fill.wast/6.print new file mode 100644 index 0000000000..dd6e1e837f --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/6.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) + i32.const -256 + i32.const 85 + i32.const 257 + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "test" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/8.print b/tests/snapshots/testsuite/memory_fill.wast/8.print new file mode 100644 index 0000000000..7ab47af89d --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/8.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) + i32.const 18 + i32.const 85 + i32.const 0 + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "test" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/91.print b/tests/snapshots/testsuite/memory_fill.wast/91.print new file mode 100644 index 0000000000..46ae1e79f9 --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/91.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $val i32) (param $len i32) + local.get $offs + local.get $val + local.get $len + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/94.print b/tests/snapshots/testsuite/memory_fill.wast/94.print new file mode 100644 index 0000000000..46ae1e79f9 --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/94.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $val i32) (param $len i32) + local.get $offs + local.get $val + local.get $len + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_fill.wast/97.print b/tests/snapshots/testsuite/memory_fill.wast/97.print new file mode 100644 index 0000000000..46ae1e79f9 --- /dev/null +++ b/tests/snapshots/testsuite/memory_fill.wast/97.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $val i32) (param $len i32) + local.get $offs + local.get $val + local.get $len + memory.fill + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_grow.wast/0.print b/tests/snapshots/testsuite/memory_grow.wast/0.print new file mode 100644 index 0000000000..c20c101f2e --- /dev/null +++ b/tests/snapshots/testsuite/memory_grow.wast/0.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.load + ) + (func (;1;) (type 1) + i32.const 0 + i32.const 2 + i32.store + ) + (func (;2;) (type 0) (result i32) + i32.const 65536 + i32.load + ) + (func (;3;) (type 1) + i32.const 65536 + i32.const 3 + i32.store + ) + (func (;4;) (type 2) (param $sz i32) (result i32) + local.get $sz + memory.grow + ) + (func (;5;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0) + (export "load_at_zero" (func 0)) + (export "store_at_zero" (func 1)) + (export "load_at_page_size" (func 2)) + (export "store_at_page_size" (func 3)) + (export "grow" (func 4)) + (export "size" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_grow.wast/21.print b/tests/snapshots/testsuite/memory_grow.wast/21.print new file mode 100644 index 0000000000..39585bdbd5 --- /dev/null +++ b/tests/snapshots/testsuite/memory_grow.wast/21.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (memory (;0;) 0) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_grow.wast/30.print b/tests/snapshots/testsuite/memory_grow.wast/30.print new file mode 100644 index 0000000000..1795e0039b --- /dev/null +++ b/tests/snapshots/testsuite/memory_grow.wast/30.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (memory (;0;) 0 10) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_grow.wast/39.print b/tests/snapshots/testsuite/memory_grow.wast/39.print new file mode 100644 index 0000000000..00eb748955 --- /dev/null +++ b/tests/snapshots/testsuite/memory_grow.wast/39.print @@ -0,0 +1,40 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (func (;1;) (type 1) (param i32 i32) (result i32) + (local i32) + i32.const 1 + local.set 2 + block ;; label = @1 + loop ;; label = @2 + local.get 0 + i32.load8_u + local.set 2 + local.get 2 + i32.const 0 + i32.ne + br_if 1 (;@1;) + local.get 0 + local.get 1 + i32.ge_u + br_if 1 (;@1;) + local.get 0 + i32.const 1 + i32.add + local.set 0 + local.get 0 + local.get 1 + i32.le_u + br_if 0 (;@2;) + end + end + local.get 2 + ) + (memory (;0;) 1) + (export "grow" (func 0)) + (export "check-memory-zero" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_grow.wast/51.print b/tests/snapshots/testsuite/memory_grow.wast/51.print new file mode 100644 index 0000000000..bb9880c31a --- /dev/null +++ b/tests/snapshots/testsuite/memory_grow.wast/51.print @@ -0,0 +1,306 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (type (;3;) (func (param i32 i32) (result i32))) + (func (;0;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + memory.grow + br 0 (;@1;) + end + ) + (func (;1;) (type 2) + block ;; label = @1 + i32.const 0 + memory.grow + br_if 0 (;@1;) + end + ) + (func (;2;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + memory.grow + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;3;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + memory.grow + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;4;) (type 2) + block ;; label = @1 + i32.const 0 + memory.grow + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;5;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + memory.grow + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;6;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + memory.grow + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;7;) (type 1) (result i32) + i32.const 0 + memory.grow + return + ) + (func (;8;) (type 1) (result i32) + i32.const 0 + memory.grow + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;9;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 0 + memory.grow + else + i32.const 0 + end + ) + (func (;10;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 0 + memory.grow + end + ) + (func (;11;) (type 3) (param i32 i32) (result i32) + i32.const 0 + memory.grow + local.get 0 + local.get 1 + select + ) + (func (;12;) (type 3) (param i32 i32) (result i32) + local.get 0 + i32.const 0 + memory.grow + local.get 1 + select + ) + (func (;13;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i32.const 0 + memory.grow + select + ) + (func $f (;14;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;15;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.const 2 + i32.const 3 + call $f + ) + (func (;16;) (type 1) (result i32) + i32.const 1 + i32.const 0 + memory.grow + i32.const 3 + call $f + ) + (func (;17;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + memory.grow + call $f + ) + (func (;18;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.const 2 + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;19;) (type 1) (result i32) + i32.const 1 + i32.const 0 + memory.grow + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;20;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + memory.grow + i32.const 0 + call_indirect (type $sig) + ) + (func (;21;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 0 + memory.grow + call_indirect (type $sig) + ) + (func (;22;) (type 2) + (local i32) + i32.const 0 + memory.grow + local.set 0 + ) + (func (;23;) (type 1) (result i32) + (local i32) + i32.const 0 + memory.grow + local.tee 0 + ) + (func (;24;) (type 2) + (local i32) + i32.const 0 + memory.grow + global.set $g + ) + (func (;25;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.load + ) + (func (;26;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.load8_s + ) + (func (;27;) (type 2) + i32.const 0 + memory.grow + i32.const 7 + i32.store + ) + (func (;28;) (type 2) + i32.const 2 + i32.const 0 + memory.grow + i32.store + ) + (func (;29;) (type 2) + i32.const 0 + memory.grow + i32.const 7 + i32.store8 + ) + (func (;30;) (type 2) + i32.const 2 + i32.const 0 + memory.grow + i32.store16 + ) + (func (;31;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.clz + ) + (func (;32;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.const 10 + i32.add + ) + (func (;33;) (type 1) (result i32) + i32.const 10 + i32.const 0 + memory.grow + i32.sub + ) + (func (;34;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.eqz + ) + (func (;35;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.const 10 + i32.le_s + ) + (func (;36;) (type 1) (result i32) + i32.const 10 + i32.const 0 + memory.grow + i32.ne + ) + (func (;37;) (type 1) (result i32) + i32.const 0 + memory.grow + memory.grow + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $g (;0;) (mut i32) i32.const 0) + (export "as-br-value" (func 0)) + (export "as-br_if-cond" (func 1)) + (export "as-br_if-value" (func 2)) + (export "as-br_if-value-cond" (func 3)) + (export "as-br_table-index" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-br_table-value-index" (func 6)) + (export "as-return-value" (func 7)) + (export "as-if-cond" (func 8)) + (export "as-if-then" (func 9)) + (export "as-if-else" (func 10)) + (export "as-select-first" (func 11)) + (export "as-select-second" (func 12)) + (export "as-select-cond" (func 13)) + (export "as-call-first" (func 15)) + (export "as-call-mid" (func 16)) + (export "as-call-last" (func 17)) + (export "as-call_indirect-first" (func 18)) + (export "as-call_indirect-mid" (func 19)) + (export "as-call_indirect-last" (func 20)) + (export "as-call_indirect-index" (func 21)) + (export "as-local.set-value" (func 22)) + (export "as-local.tee-value" (func 23)) + (export "as-global.set-value" (func 24)) + (export "as-load-address" (func 25)) + (export "as-loadN-address" (func 26)) + (export "as-store-address" (func 27)) + (export "as-store-value" (func 28)) + (export "as-storeN-address" (func 29)) + (export "as-storeN-value" (func 30)) + (export "as-unary-operand" (func 31)) + (export "as-binary-left" (func 32)) + (export "as-binary-right" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-left" (func 35)) + (export "as-compare-right" (func 36)) + (export "as-memory.grow-size" (func 37)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/0.print b/tests/snapshots/testsuite/memory_init.wast/0.print new file mode 100644 index 0000000000..619fbd4f6e --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/0.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + nop + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) "\02\07\01\08") + (data (;2;) (i32.const 12) "\07\05\02\03\06") + (data (;3;) "\05\09\02\07\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/130.print b/tests/snapshots/testsuite/memory_init.wast/130.print new file mode 100644 index 0000000000..dcc3e7ac15 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/130.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + data.drop 0 + data.drop 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/132.print b/tests/snapshots/testsuite/memory_init.wast/132.print new file mode 100644 index 0000000000..d841d8eddb --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/132.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + data.drop 0 + i32.const 1234 + i32.const 1 + i32.const 1 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/134.print b/tests/snapshots/testsuite/memory_init.wast/134.print new file mode 100644 index 0000000000..bcd68e7908 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/134.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 1234 + i32.const 1 + i32.const 1 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) (i32.const 0) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/138.print b/tests/snapshots/testsuite/memory_init.wast/138.print new file mode 100644 index 0000000000..d318f3a451 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/138.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 1 + i32.const 0 + i32.const 1 + memory.init 0 + i32.const 1 + i32.const 0 + i32.const 1 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/140.print b/tests/snapshots/testsuite/memory_init.wast/140.print new file mode 100644 index 0000000000..b7ac404fc5 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/140.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 1234 + i32.const 0 + i32.const 5 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/142.print b/tests/snapshots/testsuite/memory_init.wast/142.print new file mode 100644 index 0000000000..5e9bb8ed2c --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/142.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 1234 + i32.const 2 + i32.const 3 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/144.print b/tests/snapshots/testsuite/memory_init.wast/144.print new file mode 100644 index 0000000000..c87de909f0 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/144.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 65534 + i32.const 1 + i32.const 3 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/146.print b/tests/snapshots/testsuite/memory_init.wast/146.print new file mode 100644 index 0000000000..23f17ad9a1 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/146.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 1234 + i32.const 4 + i32.const 0 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/148.print b/tests/snapshots/testsuite/memory_init.wast/148.print new file mode 100644 index 0000000000..febdb7acd3 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/148.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 1234 + i32.const 1 + i32.const 0 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/150.print b/tests/snapshots/testsuite/memory_init.wast/150.print new file mode 100644 index 0000000000..bb5b22a6eb --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/150.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 65537 + i32.const 0 + i32.const 0 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/152.print b/tests/snapshots/testsuite/memory_init.wast/152.print new file mode 100644 index 0000000000..9dd62b6ca7 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/152.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 65536 + i32.const 0 + i32.const 0 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/154.print b/tests/snapshots/testsuite/memory_init.wast/154.print new file mode 100644 index 0000000000..f8b9050837 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/154.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 65536 + i32.const 1 + i32.const 0 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/156.print b/tests/snapshots/testsuite/memory_init.wast/156.print new file mode 100644 index 0000000000..92c4488e06 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/156.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 65537 + i32.const 4 + i32.const 0 + memory.init 0 + ) + (memory (;0;) 1) + (export "test" (func 0)) + (data (;0;) "7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/221.print b/tests/snapshots/testsuite/memory_init.wast/221.print new file mode 100644 index 0000000000..32190d2046 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/221.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + memory.init 0 + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) + (data (;0;) "BBBBBBBBBBBBBBBB") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/224.print b/tests/snapshots/testsuite/memory_init.wast/224.print new file mode 100644 index 0000000000..32190d2046 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/224.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + memory.init 0 + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) + (data (;0;) "BBBBBBBBBBBBBBBB") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/227.print b/tests/snapshots/testsuite/memory_init.wast/227.print new file mode 100644 index 0000000000..32190d2046 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/227.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + memory.init 0 + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) + (data (;0;) "BBBBBBBBBBBBBBBB") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/230.print b/tests/snapshots/testsuite/memory_init.wast/230.print new file mode 100644 index 0000000000..32190d2046 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/230.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + memory.init 0 + ) + (memory (;0;) 1 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) + (data (;0;) "BBBBBBBBBBBBBBBB") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/233.print b/tests/snapshots/testsuite/memory_init.wast/233.print new file mode 100644 index 0000000000..c8d009f373 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/233.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + memory.init 0 + ) + (memory (;0;) 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) + (data (;0;) "BBBBBBBBBBBBBBBB") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/236.print b/tests/snapshots/testsuite/memory_init.wast/236.print new file mode 100644 index 0000000000..c8d009f373 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/236.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (func (;0;) (type 0) (param $from i32) (param $to i32) (param $expected i32) (result i32) + loop $cont ;; label = @1 + local.get $from + local.get $to + i32.eq + if ;; label = @2 + i32.const -1 + return + end + local.get $from + i32.load8_u + local.get $expected + i32.eq + if ;; label = @2 + local.get $from + i32.const 1 + i32.add + local.set $from + br 1 (;@1;) + end + end + local.get $from + return + ) + (func (;1;) (type 1) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + memory.init 0 + ) + (memory (;0;) 1) + (export "checkRange" (func 0)) + (export "run" (func 1)) + (data (;0;) "BBBBBBBBBBBBBBBB") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/239.print b/tests/snapshots/testsuite/memory_init.wast/239.print new file mode 100644 index 0000000000..b131aef415 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/239.print @@ -0,0 +1,75 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.const 0 + i32.const 0 + memory.init 64 + ) + (memory (;0;) 1) + (data (;0;) "") + (data (;1;) "") + (data (;2;) "") + (data (;3;) "") + (data (;4;) "") + (data (;5;) "") + (data (;6;) "") + (data (;7;) "") + (data (;8;) "") + (data (;9;) "") + (data (;10;) "") + (data (;11;) "") + (data (;12;) "") + (data (;13;) "") + (data (;14;) "") + (data (;15;) "") + (data (;16;) "") + (data (;17;) "") + (data (;18;) "") + (data (;19;) "") + (data (;20;) "") + (data (;21;) "") + (data (;22;) "") + (data (;23;) "") + (data (;24;) "") + (data (;25;) "") + (data (;26;) "") + (data (;27;) "") + (data (;28;) "") + (data (;29;) "") + (data (;30;) "") + (data (;31;) "") + (data (;32;) "") + (data (;33;) "") + (data (;34;) "") + (data (;35;) "") + (data (;36;) "") + (data (;37;) "") + (data (;38;) "") + (data (;39;) "") + (data (;40;) "") + (data (;41;) "") + (data (;42;) "") + (data (;43;) "") + (data (;44;) "") + (data (;45;) "") + (data (;46;) "") + (data (;47;) "") + (data (;48;) "") + (data (;49;) "") + (data (;50;) "") + (data (;51;) "") + (data (;52;) "") + (data (;53;) "") + (data (;54;) "") + (data (;55;) "") + (data (;56;) "") + (data (;57;) "") + (data (;58;) "") + (data (;59;) "") + (data (;60;) "") + (data (;61;) "") + (data (;62;) "") + (data (;63;) "") + (data (;64;) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/32.print b/tests/snapshots/testsuite/memory_init.wast/32.print new file mode 100644 index 0000000000..a0b9d51086 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/32.print @@ -0,0 +1,22 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 7 + i32.const 0 + i32.const 4 + memory.init 1 + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) "\02\07\01\08") + (data (;2;) (i32.const 12) "\07\05\02\03\06") + (data (;3;) "\05\09\02\07\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/64.print b/tests/snapshots/testsuite/memory_init.wast/64.print new file mode 100644 index 0000000000..8511c99eb1 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/64.print @@ -0,0 +1,22 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 15 + i32.const 1 + i32.const 3 + memory.init 3 + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) "\02\07\01\08") + (data (;2;) (i32.const 12) "\07\05\02\03\06") + (data (;3;) "\05\09\02\07\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_init.wast/96.print b/tests/snapshots/testsuite/memory_init.wast/96.print new file mode 100644 index 0000000000..e5f6f0a244 --- /dev/null +++ b/tests/snapshots/testsuite/memory_init.wast/96.print @@ -0,0 +1,48 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 7 + i32.const 0 + i32.const 4 + memory.init 1 + data.drop 1 + i32.const 15 + i32.const 1 + i32.const 3 + memory.init 3 + data.drop 3 + i32.const 20 + i32.const 15 + i32.const 5 + memory.copy + i32.const 21 + i32.const 29 + i32.const 1 + memory.copy + i32.const 24 + i32.const 10 + i32.const 1 + memory.copy + i32.const 13 + i32.const 11 + i32.const 4 + memory.copy + i32.const 19 + i32.const 20 + i32.const 5 + memory.copy + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 1 1) + (export "memory0" (memory 0)) + (export "test" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 2) "\03\01\04\01") + (data (;1;) "\02\07\01\08") + (data (;2;) (i32.const 12) "\07\05\02\03\06") + (data (;3;) "\05\09\02\07\06") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_redundancy.wast/0.print b/tests/snapshots/testsuite/memory_redundancy.wast/0.print new file mode 100644 index 0000000000..df0ab18db4 --- /dev/null +++ b/tests/snapshots/testsuite/memory_redundancy.wast/0.print @@ -0,0 +1,85 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (result f32))) + (type (;3;) (func (param i32) (result i32))) + (func (;0;) (type 0) + i32.const 0 + i32.const 0 + i32.store + i32.const 4 + i32.const 0 + i32.store + i32.const 8 + i32.const 0 + i32.store + i32.const 12 + i32.const 0 + i32.store + ) + (func (;1;) (type 1) (result i32) + i32.const 8 + i32.const 0 + i32.store + i32.const 5 + f32.const -0x0p+0 (;=-0;) + f32.store + i32.const 8 + i32.load + ) + (func (;2;) (type 1) (result i32) + (local $t i32) (local $s i32) + i32.const 8 + i32.load + local.set $t + i32.const 5 + i32.const -2147483648 + i32.store + i32.const 8 + i32.load + local.set $s + local.get $t + local.get $s + i32.add + ) + (func (;3;) (type 2) (result f32) + (local $t f32) + i32.const 8 + i32.const 589505315 + i32.store + i32.const 11 + f32.load + local.set $t + i32.const 8 + i32.const 0 + i32.store + local.get $t + ) + (func $malloc (;4;) (type 3) (param $size i32) (result i32) + i32.const 16 + ) + (func (;5;) (type 1) (result i32) + (local $x i32) (local $y i32) + i32.const 4 + call $malloc + local.set $x + i32.const 4 + call $malloc + local.set $y + local.get $x + i32.const 42 + i32.store + local.get $y + i32.const 43 + i32.store + local.get $x + i32.load + ) + (memory (;0;) 1 1) + (export "zero_everything" (func 0)) + (export "test_store_to_load" (func 1)) + (export "test_redundant_load" (func 2)) + (export "test_dead_store" (func 3)) + (export "malloc" (func $malloc)) + (export "malloc_aliasing" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_size.wast/0.print b/tests/snapshots/testsuite/memory_size.wast/0.print new file mode 100644 index 0000000000..068665a77c --- /dev/null +++ b/tests/snapshots/testsuite/memory_size.wast/0.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow + drop + ) + (memory (;0;) 0) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_size.wast/16.print b/tests/snapshots/testsuite/memory_size.wast/16.print new file mode 100644 index 0000000000..a1f80fc2a2 --- /dev/null +++ b/tests/snapshots/testsuite/memory_size.wast/16.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow + drop + ) + (memory (;0;) 0 2) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_size.wast/28.print b/tests/snapshots/testsuite/memory_size.wast/28.print new file mode 100644 index 0000000000..de54b63489 --- /dev/null +++ b/tests/snapshots/testsuite/memory_size.wast/28.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow + drop + ) + (memory (;0;) 3 8) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_size.wast/8.print b/tests/snapshots/testsuite/memory_size.wast/8.print new file mode 100644 index 0000000000..bbaf0511e4 --- /dev/null +++ b/tests/snapshots/testsuite/memory_size.wast/8.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow + drop + ) + (memory (;0;) 1) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_trap.wast/0.print b/tests/snapshots/testsuite/memory_trap.wast/0.print new file mode 100644 index 0000000000..0f1e5b0994 --- /dev/null +++ b/tests/snapshots/testsuite/memory_trap.wast/0.print @@ -0,0 +1,31 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32))) + (type (;2;) (func (param i32) (result i32))) + (func $addr_limit (;0;) (type 0) (result i32) + memory.size + i32.const 65536 + i32.mul + ) + (func (;1;) (type 1) (param $i i32) (param $v i32) + call $addr_limit + local.get $i + i32.add + local.get $v + i32.store + ) + (func (;2;) (type 2) (param $i i32) (result i32) + call $addr_limit + local.get $i + i32.add + i32.load + ) + (func (;3;) (type 2) (param i32) (result i32) + local.get 0 + memory.grow + ) + (memory (;0;) 1) + (export "store" (func 1)) + (export "load" (func 2)) + (export "memory.grow" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/memory_trap.wast/14.print b/tests/snapshots/testsuite/memory_trap.wast/14.print new file mode 100644 index 0000000000..e767179ffe --- /dev/null +++ b/tests/snapshots/testsuite/memory_trap.wast/14.print @@ -0,0 +1,137 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32) (result i64))) + (type (;2;) (func (param i32) (result f32))) + (type (;3;) (func (param i32) (result f64))) + (type (;4;) (func (param i32 i32))) + (type (;5;) (func (param i32 i64))) + (type (;6;) (func (param i32 f32))) + (type (;7;) (func (param i32 f64))) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load + ) + (func (;1;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load + ) + (func (;2;) (type 2) (param $a i32) (result f32) + local.get $a + f32.load + ) + (func (;3;) (type 3) (param $a i32) (result f64) + local.get $a + f64.load + ) + (func (;4;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_s + ) + (func (;5;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (func (;6;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load16_s + ) + (func (;7;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load16_u + ) + (func (;8;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load8_s + ) + (func (;9;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load8_u + ) + (func (;10;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load16_s + ) + (func (;11;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load16_u + ) + (func (;12;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load32_s + ) + (func (;13;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load32_u + ) + (func (;14;) (type 4) (param $a i32) (param $v i32) + local.get $a + local.get $v + i32.store + ) + (func (;15;) (type 5) (param $a i32) (param $v i64) + local.get $a + local.get $v + i64.store + ) + (func (;16;) (type 6) (param $a i32) (param $v f32) + local.get $a + local.get $v + f32.store + ) + (func (;17;) (type 7) (param $a i32) (param $v f64) + local.get $a + local.get $v + f64.store + ) + (func (;18;) (type 4) (param $a i32) (param $v i32) + local.get $a + local.get $v + i32.store8 + ) + (func (;19;) (type 4) (param $a i32) (param $v i32) + local.get $a + local.get $v + i32.store16 + ) + (func (;20;) (type 5) (param $a i32) (param $v i64) + local.get $a + local.get $v + i64.store8 + ) + (func (;21;) (type 5) (param $a i32) (param $v i64) + local.get $a + local.get $v + i64.store16 + ) + (func (;22;) (type 5) (param $a i32) (param $v i64) + local.get $a + local.get $v + i64.store32 + ) + (memory (;0;) 1) + (export "i32.load" (func 0)) + (export "i64.load" (func 1)) + (export "f32.load" (func 2)) + (export "f64.load" (func 3)) + (export "i32.load8_s" (func 4)) + (export "i32.load8_u" (func 5)) + (export "i32.load16_s" (func 6)) + (export "i32.load16_u" (func 7)) + (export "i64.load8_s" (func 8)) + (export "i64.load8_u" (func 9)) + (export "i64.load16_s" (func 10)) + (export "i64.load16_u" (func 11)) + (export "i64.load32_s" (func 12)) + (export "i64.load32_u" (func 13)) + (export "i32.store" (func 14)) + (export "i64.store" (func 15)) + (export "f32.store" (func 16)) + (export "f64.store" (func 17)) + (export "i32.store8" (func 18)) + (export "i32.store16" (func 19)) + (export "i64.store8" (func 20)) + (export "i64.store16" (func 21)) + (export "i64.store32" (func 22)) + (data (;0;) (i32.const 0) "abcdefgh") + (data (;1;) (i32.const 65528) "abcdefgh") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/names.wast/0.print b/tests/snapshots/testsuite/names.wast/0.print new file mode 100644 index 0000000000..85dc3d8016 --- /dev/null +++ b/tests/snapshots/testsuite/names.wast/0.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (export "foo" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/names.wast/2.print b/tests/snapshots/testsuite/names.wast/2.print new file mode 100644 index 0000000000..f6ce6dde57 --- /dev/null +++ b/tests/snapshots/testsuite/names.wast/2.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + ) + (export "foo" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/names.wast/4.print b/tests/snapshots/testsuite/names.wast/4.print new file mode 100644 index 0000000000..9c7d4c7d69 --- /dev/null +++ b/tests/snapshots/testsuite/names.wast/4.print @@ -0,0 +1,1919 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 0) (result i32) + i32.const 10 + ) + (func (;11;) (type 0) (result i32) + i32.const 11 + ) + (func (;12;) (type 0) (result i32) + i32.const 12 + ) + (func (;13;) (type 0) (result i32) + i32.const 13 + ) + (func (;14;) (type 0) (result i32) + i32.const 14 + ) + (func (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 0) (result i32) + i32.const 16 + ) + (func (;17;) (type 0) (result i32) + i32.const 17 + ) + (func (;18;) (type 0) (result i32) + i32.const 18 + ) + (func (;19;) (type 0) (result i32) + i32.const 19 + ) + (func (;20;) (type 0) (result i32) + i32.const 20 + ) + (func (;21;) (type 0) (result i32) + i32.const 21 + ) + (func (;22;) (type 0) (result i32) + i32.const 22 + ) + (func (;23;) (type 0) (result i32) + i32.const 23 + ) + (func (;24;) (type 0) (result i32) + i32.const 24 + ) + (func (;25;) (type 0) (result i32) + i32.const 25 + ) + (func (;26;) (type 0) (result i32) + i32.const 26 + ) + (func (;27;) (type 0) (result i32) + i32.const 27 + ) + (func (;28;) (type 0) (result i32) + i32.const 28 + ) + (func (;29;) (type 0) (result i32) + i32.const 29 + ) + (func (;30;) (type 0) (result i32) + i32.const 30 + ) + (func (;31;) (type 0) (result i32) + i32.const 31 + ) + (func (;32;) (type 0) (result i32) + i32.const 32 + ) + (func (;33;) (type 0) (result i32) + i32.const 33 + ) + (func (;34;) (type 0) (result i32) + i32.const 34 + ) + (func (;35;) (type 0) (result i32) + i32.const 35 + ) + (func (;36;) (type 0) (result i32) + i32.const 36 + ) + (func (;37;) (type 0) (result i32) + i32.const 37 + ) + (func (;38;) (type 0) (result i32) + i32.const 38 + ) + (func (;39;) (type 0) (result i32) + i32.const 39 + ) + (func (;40;) (type 0) (result i32) + i32.const 40 + ) + (func (;41;) (type 0) (result i32) + i32.const 41 + ) + (func (;42;) (type 0) (result i32) + i32.const 42 + ) + (func (;43;) (type 0) (result i32) + i32.const 43 + ) + (func (;44;) (type 0) (result i32) + i32.const 44 + ) + (func (;45;) (type 0) (result i32) + i32.const 45 + ) + (func (;46;) (type 0) (result i32) + i32.const 46 + ) + (func (;47;) (type 0) (result i32) + i32.const 47 + ) + (func (;48;) (type 0) (result i32) + i32.const 48 + ) + (func (;49;) (type 0) (result i32) + i32.const 49 + ) + (func (;50;) (type 0) (result i32) + i32.const 50 + ) + (func (;51;) (type 0) (result i32) + i32.const 51 + ) + (func (;52;) (type 0) (result i32) + i32.const 52 + ) + (func (;53;) (type 0) (result i32) + i32.const 53 + ) + (func (;54;) (type 0) (result i32) + i32.const 54 + ) + (func (;55;) (type 0) (result i32) + i32.const 55 + ) + (func (;56;) (type 0) (result i32) + i32.const 56 + ) + (func (;57;) (type 0) (result i32) + i32.const 57 + ) + (func (;58;) (type 0) (result i32) + i32.const 58 + ) + (func (;59;) (type 0) (result i32) + i32.const 59 + ) + (func (;60;) (type 0) (result i32) + i32.const 60 + ) + (func (;61;) (type 0) (result i32) + i32.const 61 + ) + (func (;62;) (type 0) (result i32) + i32.const 62 + ) + (func (;63;) (type 0) (result i32) + i32.const 63 + ) + (func (;64;) (type 0) (result i32) + i32.const 64 + ) + (func (;65;) (type 0) (result i32) + i32.const 65 + ) + (func (;66;) (type 0) (result i32) + i32.const 66 + ) + (func (;67;) (type 0) (result i32) + i32.const 67 + ) + (func (;68;) (type 0) (result i32) + i32.const 68 + ) + (func (;69;) (type 0) (result i32) + i32.const 69 + ) + (func (;70;) (type 0) (result i32) + i32.const 70 + ) + (func (;71;) (type 0) (result i32) + i32.const 71 + ) + (func (;72;) (type 0) (result i32) + i32.const 72 + ) + (func (;73;) (type 0) (result i32) + i32.const 73 + ) + (func (;74;) (type 0) (result i32) + i32.const 74 + ) + (func (;75;) (type 0) (result i32) + i32.const 75 + ) + (func (;76;) (type 0) (result i32) + i32.const 76 + ) + (func (;77;) (type 0) (result i32) + i32.const 77 + ) + (func (;78;) (type 0) (result i32) + i32.const 78 + ) + (func (;79;) (type 0) (result i32) + i32.const 79 + ) + (func (;80;) (type 0) (result i32) + i32.const 80 + ) + (func (;81;) (type 0) (result i32) + i32.const 81 + ) + (func (;82;) (type 0) (result i32) + i32.const 82 + ) + (func (;83;) (type 0) (result i32) + i32.const 83 + ) + (func (;84;) (type 0) (result i32) + i32.const 84 + ) + (func (;85;) (type 0) (result i32) + i32.const 85 + ) + (func (;86;) (type 0) (result i32) + i32.const 86 + ) + (func (;87;) (type 0) (result i32) + i32.const 87 + ) + (func (;88;) (type 0) (result i32) + i32.const 88 + ) + (func (;89;) (type 0) (result i32) + i32.const 89 + ) + (func (;90;) (type 0) (result i32) + i32.const 90 + ) + (func (;91;) (type 0) (result i32) + i32.const 91 + ) + (func (;92;) (type 0) (result i32) + i32.const 92 + ) + (func (;93;) (type 0) (result i32) + i32.const 93 + ) + (func (;94;) (type 0) (result i32) + i32.const 94 + ) + (func (;95;) (type 0) (result i32) + i32.const 95 + ) + (func (;96;) (type 0) (result i32) + i32.const 96 + ) + (func (;97;) (type 0) (result i32) + i32.const 97 + ) + (func (;98;) (type 0) (result i32) + i32.const 98 + ) + (func (;99;) (type 0) (result i32) + i32.const 99 + ) + (func (;100;) (type 0) (result i32) + i32.const 100 + ) + (func (;101;) (type 0) (result i32) + i32.const 101 + ) + (func (;102;) (type 0) (result i32) + i32.const 102 + ) + (func (;103;) (type 0) (result i32) + i32.const 103 + ) + (func (;104;) (type 0) (result i32) + i32.const 104 + ) + (func (;105;) (type 0) (result i32) + i32.const 105 + ) + (func (;106;) (type 0) (result i32) + i32.const 106 + ) + (func (;107;) (type 0) (result i32) + i32.const 107 + ) + (func (;108;) (type 0) (result i32) + i32.const 108 + ) + (func (;109;) (type 0) (result i32) + i32.const 109 + ) + (func (;110;) (type 0) (result i32) + i32.const 110 + ) + (func (;111;) (type 0) (result i32) + i32.const 111 + ) + (func (;112;) (type 0) (result i32) + i32.const 112 + ) + (func (;113;) (type 0) (result i32) + i32.const 113 + ) + (func (;114;) (type 0) (result i32) + i32.const 114 + ) + (func (;115;) (type 0) (result i32) + i32.const 115 + ) + (func (;116;) (type 0) (result i32) + i32.const 116 + ) + (func (;117;) (type 0) (result i32) + i32.const 117 + ) + (func (;118;) (type 0) (result i32) + i32.const 118 + ) + (func (;119;) (type 0) (result i32) + i32.const 119 + ) + (func (;120;) (type 0) (result i32) + i32.const 120 + ) + (func (;121;) (type 0) (result i32) + i32.const 121 + ) + (func (;122;) (type 0) (result i32) + i32.const 122 + ) + (func (;123;) (type 0) (result i32) + i32.const 123 + ) + (func (;124;) (type 0) (result i32) + i32.const 124 + ) + (func (;125;) (type 0) (result i32) + i32.const 125 + ) + (func (;126;) (type 0) (result i32) + i32.const 126 + ) + (func (;127;) (type 0) (result i32) + i32.const 127 + ) + (func (;128;) (type 0) (result i32) + i32.const 128 + ) + (func (;129;) (type 0) (result i32) + i32.const 129 + ) + (func (;130;) (type 0) (result i32) + i32.const 130 + ) + (func (;131;) (type 0) (result i32) + i32.const 131 + ) + (func (;132;) (type 0) (result i32) + i32.const 132 + ) + (func (;133;) (type 0) (result i32) + i32.const 133 + ) + (func (;134;) (type 0) (result i32) + i32.const 134 + ) + (func (;135;) (type 0) (result i32) + i32.const 135 + ) + (func (;136;) (type 0) (result i32) + i32.const 136 + ) + (func (;137;) (type 0) (result i32) + i32.const 137 + ) + (func (;138;) (type 0) (result i32) + i32.const 138 + ) + (func (;139;) (type 0) (result i32) + i32.const 139 + ) + (func (;140;) (type 0) (result i32) + i32.const 140 + ) + (func (;141;) (type 0) (result i32) + i32.const 141 + ) + (func (;142;) (type 0) (result i32) + i32.const 142 + ) + (func (;143;) (type 0) (result i32) + i32.const 143 + ) + (func (;144;) (type 0) (result i32) + i32.const 144 + ) + (func (;145;) (type 0) (result i32) + i32.const 145 + ) + (func (;146;) (type 0) (result i32) + i32.const 146 + ) + (func (;147;) (type 0) (result i32) + i32.const 147 + ) + (func (;148;) (type 0) (result i32) + i32.const 148 + ) + (func (;149;) (type 0) (result i32) + i32.const 149 + ) + (func (;150;) (type 0) (result i32) + i32.const 150 + ) + (func (;151;) (type 0) (result i32) + i32.const 151 + ) + (func (;152;) (type 0) (result i32) + i32.const 152 + ) + (func (;153;) (type 0) (result i32) + i32.const 153 + ) + (func (;154;) (type 0) (result i32) + i32.const 154 + ) + (func (;155;) (type 0) (result i32) + i32.const 155 + ) + (func (;156;) (type 0) (result i32) + i32.const 156 + ) + (func (;157;) (type 0) (result i32) + i32.const 157 + ) + (func (;158;) (type 0) (result i32) + i32.const 158 + ) + (func (;159;) (type 0) (result i32) + i32.const 159 + ) + (func (;160;) (type 0) (result i32) + i32.const 160 + ) + (func (;161;) (type 0) (result i32) + i32.const 161 + ) + (func (;162;) (type 0) (result i32) + i32.const 162 + ) + (func (;163;) (type 0) (result i32) + i32.const 163 + ) + (func (;164;) (type 0) (result i32) + i32.const 164 + ) + (func (;165;) (type 0) (result i32) + i32.const 165 + ) + (func (;166;) (type 0) (result i32) + i32.const 166 + ) + (func (;167;) (type 0) (result i32) + i32.const 167 + ) + (func (;168;) (type 0) (result i32) + i32.const 168 + ) + (func (;169;) (type 0) (result i32) + i32.const 169 + ) + (func (;170;) (type 0) (result i32) + i32.const 170 + ) + (func (;171;) (type 0) (result i32) + i32.const 171 + ) + (func (;172;) (type 0) (result i32) + i32.const 172 + ) + (func (;173;) (type 0) (result i32) + i32.const 173 + ) + (func (;174;) (type 0) (result i32) + i32.const 174 + ) + (func (;175;) (type 0) (result i32) + i32.const 175 + ) + (func (;176;) (type 0) (result i32) + i32.const 176 + ) + (func (;177;) (type 0) (result i32) + i32.const 177 + ) + (func (;178;) (type 0) (result i32) + i32.const 178 + ) + (func (;179;) (type 0) (result i32) + i32.const 179 + ) + (func (;180;) (type 0) (result i32) + i32.const 180 + ) + (func (;181;) (type 0) (result i32) + i32.const 181 + ) + (func (;182;) (type 0) (result i32) + i32.const 182 + ) + (func (;183;) (type 0) (result i32) + i32.const 183 + ) + (func (;184;) (type 0) (result i32) + i32.const 184 + ) + (func (;185;) (type 0) (result i32) + i32.const 185 + ) + (func (;186;) (type 0) (result i32) + i32.const 186 + ) + (func (;187;) (type 0) (result i32) + i32.const 187 + ) + (func (;188;) (type 0) (result i32) + i32.const 188 + ) + (func (;189;) (type 0) (result i32) + i32.const 189 + ) + (func (;190;) (type 0) (result i32) + i32.const 190 + ) + (func (;191;) (type 0) (result i32) + i32.const 191 + ) + (func (;192;) (type 0) (result i32) + i32.const 192 + ) + (func (;193;) (type 0) (result i32) + i32.const 193 + ) + (func (;194;) (type 0) (result i32) + i32.const 194 + ) + (func (;195;) (type 0) (result i32) + i32.const 195 + ) + (func (;196;) (type 0) (result i32) + i32.const 196 + ) + (func (;197;) (type 0) (result i32) + i32.const 197 + ) + (func (;198;) (type 0) (result i32) + i32.const 198 + ) + (func (;199;) (type 0) (result i32) + i32.const 199 + ) + (func (;200;) (type 0) (result i32) + i32.const 200 + ) + (func (;201;) (type 0) (result i32) + i32.const 201 + ) + (func (;202;) (type 0) (result i32) + i32.const 202 + ) + (func (;203;) (type 0) (result i32) + i32.const 203 + ) + (func (;204;) (type 0) (result i32) + i32.const 204 + ) + (func (;205;) (type 0) (result i32) + i32.const 205 + ) + (func (;206;) (type 0) (result i32) + i32.const 206 + ) + (func (;207;) (type 0) (result i32) + i32.const 207 + ) + (func (;208;) (type 0) (result i32) + i32.const 208 + ) + (func (;209;) (type 0) (result i32) + i32.const 209 + ) + (func (;210;) (type 0) (result i32) + i32.const 210 + ) + (func (;211;) (type 0) (result i32) + i32.const 211 + ) + (func (;212;) (type 0) (result i32) + i32.const 212 + ) + (func (;213;) (type 0) (result i32) + i32.const 213 + ) + (func (;214;) (type 0) (result i32) + i32.const 214 + ) + (func (;215;) (type 0) (result i32) + i32.const 215 + ) + (func (;216;) (type 0) (result i32) + i32.const 216 + ) + (func (;217;) (type 0) (result i32) + i32.const 217 + ) + (func (;218;) (type 0) (result i32) + i32.const 218 + ) + (func (;219;) (type 0) (result i32) + i32.const 219 + ) + (func (;220;) (type 0) (result i32) + i32.const 220 + ) + (func (;221;) (type 0) (result i32) + i32.const 221 + ) + (func (;222;) (type 0) (result i32) + i32.const 222 + ) + (func (;223;) (type 0) (result i32) + i32.const 223 + ) + (func (;224;) (type 0) (result i32) + i32.const 224 + ) + (func (;225;) (type 0) (result i32) + i32.const 225 + ) + (func (;226;) (type 0) (result i32) + i32.const 226 + ) + (func (;227;) (type 0) (result i32) + i32.const 227 + ) + (func (;228;) (type 0) (result i32) + i32.const 228 + ) + (func (;229;) (type 0) (result i32) + i32.const 229 + ) + (func (;230;) (type 0) (result i32) + i32.const 230 + ) + (func (;231;) (type 0) (result i32) + i32.const 231 + ) + (func (;232;) (type 0) (result i32) + i32.const 232 + ) + (func (;233;) (type 0) (result i32) + i32.const 233 + ) + (func (;234;) (type 0) (result i32) + i32.const 234 + ) + (func (;235;) (type 0) (result i32) + i32.const 235 + ) + (func (;236;) (type 0) (result i32) + i32.const 236 + ) + (func (;237;) (type 0) (result i32) + i32.const 237 + ) + (func (;238;) (type 0) (result i32) + i32.const 238 + ) + (func (;239;) (type 0) (result i32) + i32.const 239 + ) + (func (;240;) (type 0) (result i32) + i32.const 240 + ) + (func (;241;) (type 0) (result i32) + i32.const 241 + ) + (func (;242;) (type 0) (result i32) + i32.const 242 + ) + (func (;243;) (type 0) (result i32) + i32.const 243 + ) + (func (;244;) (type 0) (result i32) + i32.const 244 + ) + (func (;245;) (type 0) (result i32) + i32.const 245 + ) + (func (;246;) (type 0) (result i32) + i32.const 246 + ) + (func (;247;) (type 0) (result i32) + i32.const 247 + ) + (func (;248;) (type 0) (result i32) + i32.const 248 + ) + (func (;249;) (type 0) (result i32) + i32.const 249 + ) + (func (;250;) (type 0) (result i32) + i32.const 250 + ) + (func (;251;) (type 0) (result i32) + i32.const 251 + ) + (func (;252;) (type 0) (result i32) + i32.const 252 + ) + (func (;253;) (type 0) (result i32) + i32.const 253 + ) + (func (;254;) (type 0) (result i32) + i32.const 254 + ) + (func (;255;) (type 0) (result i32) + i32.const 255 + ) + (func (;256;) (type 0) (result i32) + i32.const 256 + ) + (func (;257;) (type 0) (result i32) + i32.const 257 + ) + (func (;258;) (type 0) (result i32) + i32.const 258 + ) + (func (;259;) (type 0) (result i32) + i32.const 259 + ) + (func (;260;) (type 0) (result i32) + i32.const 260 + ) + (func (;261;) (type 0) (result i32) + i32.const 261 + ) + (func (;262;) (type 0) (result i32) + i32.const 262 + ) + (func (;263;) (type 0) (result i32) + i32.const 263 + ) + (func (;264;) (type 0) (result i32) + i32.const 264 + ) + (func (;265;) (type 0) (result i32) + i32.const 265 + ) + (func (;266;) (type 0) (result i32) + i32.const 266 + ) + (func (;267;) (type 0) (result i32) + i32.const 267 + ) + (func (;268;) (type 0) (result i32) + i32.const 268 + ) + (func (;269;) (type 0) (result i32) + i32.const 269 + ) + (func (;270;) (type 0) (result i32) + i32.const 270 + ) + (func (;271;) (type 0) (result i32) + i32.const 271 + ) + (func (;272;) (type 0) (result i32) + i32.const 272 + ) + (func (;273;) (type 0) (result i32) + i32.const 273 + ) + (func (;274;) (type 0) (result i32) + i32.const 274 + ) + (func (;275;) (type 0) (result i32) + i32.const 275 + ) + (func (;276;) (type 0) (result i32) + i32.const 276 + ) + (func (;277;) (type 0) (result i32) + i32.const 277 + ) + (func (;278;) (type 0) (result i32) + i32.const 278 + ) + (func (;279;) (type 0) (result i32) + i32.const 279 + ) + (func (;280;) (type 0) (result i32) + i32.const 280 + ) + (func (;281;) (type 0) (result i32) + i32.const 281 + ) + (func (;282;) (type 0) (result i32) + i32.const 282 + ) + (func (;283;) (type 0) (result i32) + i32.const 283 + ) + (func (;284;) (type 0) (result i32) + i32.const 284 + ) + (func (;285;) (type 0) (result i32) + i32.const 285 + ) + (func (;286;) (type 0) (result i32) + i32.const 286 + ) + (func (;287;) (type 0) (result i32) + i32.const 287 + ) + (func (;288;) (type 0) (result i32) + i32.const 288 + ) + (func (;289;) (type 0) (result i32) + i32.const 289 + ) + (func (;290;) (type 0) (result i32) + i32.const 290 + ) + (func (;291;) (type 0) (result i32) + i32.const 291 + ) + (func (;292;) (type 0) (result i32) + i32.const 292 + ) + (func (;293;) (type 0) (result i32) + i32.const 293 + ) + (func (;294;) (type 0) (result i32) + i32.const 294 + ) + (func (;295;) (type 0) (result i32) + i32.const 295 + ) + (func (;296;) (type 0) (result i32) + i32.const 296 + ) + (func (;297;) (type 0) (result i32) + i32.const 297 + ) + (func (;298;) (type 0) (result i32) + i32.const 298 + ) + (func (;299;) (type 0) (result i32) + i32.const 299 + ) + (func (;300;) (type 0) (result i32) + i32.const 300 + ) + (func (;301;) (type 0) (result i32) + i32.const 301 + ) + (func (;302;) (type 0) (result i32) + i32.const 302 + ) + (func (;303;) (type 0) (result i32) + i32.const 303 + ) + (func (;304;) (type 0) (result i32) + i32.const 304 + ) + (func (;305;) (type 0) (result i32) + i32.const 305 + ) + (func (;306;) (type 0) (result i32) + i32.const 306 + ) + (func (;307;) (type 0) (result i32) + i32.const 307 + ) + (func (;308;) (type 0) (result i32) + i32.const 308 + ) + (func (;309;) (type 0) (result i32) + i32.const 309 + ) + (func (;310;) (type 0) (result i32) + i32.const 310 + ) + (func (;311;) (type 0) (result i32) + i32.const 311 + ) + (func (;312;) (type 0) (result i32) + i32.const 312 + ) + (func (;313;) (type 0) (result i32) + i32.const 313 + ) + (func (;314;) (type 0) (result i32) + i32.const 314 + ) + (func (;315;) (type 0) (result i32) + i32.const 315 + ) + (func (;316;) (type 0) (result i32) + i32.const 316 + ) + (func (;317;) (type 0) (result i32) + i32.const 317 + ) + (func (;318;) (type 0) (result i32) + i32.const 318 + ) + (func (;319;) (type 0) (result i32) + i32.const 319 + ) + (func (;320;) (type 0) (result i32) + i32.const 320 + ) + (func (;321;) (type 0) (result i32) + i32.const 321 + ) + (func (;322;) (type 0) (result i32) + i32.const 322 + ) + (func (;323;) (type 0) (result i32) + i32.const 323 + ) + (func (;324;) (type 0) (result i32) + i32.const 324 + ) + (func (;325;) (type 0) (result i32) + i32.const 325 + ) + (func (;326;) (type 0) (result i32) + i32.const 326 + ) + (func (;327;) (type 0) (result i32) + i32.const 327 + ) + (func (;328;) (type 0) (result i32) + i32.const 328 + ) + (func (;329;) (type 0) (result i32) + i32.const 329 + ) + (func (;330;) (type 0) (result i32) + i32.const 330 + ) + (func (;331;) (type 0) (result i32) + i32.const 331 + ) + (func (;332;) (type 0) (result i32) + i32.const 332 + ) + (func (;333;) (type 0) (result i32) + i32.const 333 + ) + (func (;334;) (type 0) (result i32) + i32.const 334 + ) + (func (;335;) (type 0) (result i32) + i32.const 335 + ) + (func (;336;) (type 0) (result i32) + i32.const 336 + ) + (func (;337;) (type 0) (result i32) + i32.const 337 + ) + (func (;338;) (type 0) (result i32) + i32.const 338 + ) + (func (;339;) (type 0) (result i32) + i32.const 339 + ) + (func (;340;) (type 0) (result i32) + i32.const 340 + ) + (func (;341;) (type 0) (result i32) + i32.const 341 + ) + (func (;342;) (type 0) (result i32) + i32.const 342 + ) + (func (;343;) (type 0) (result i32) + i32.const 343 + ) + (func (;344;) (type 0) (result i32) + i32.const 344 + ) + (func (;345;) (type 0) (result i32) + i32.const 345 + ) + (func (;346;) (type 0) (result i32) + i32.const 346 + ) + (func (;347;) (type 0) (result i32) + i32.const 347 + ) + (func (;348;) (type 0) (result i32) + i32.const 348 + ) + (func (;349;) (type 0) (result i32) + i32.const 349 + ) + (func (;350;) (type 0) (result i32) + i32.const 350 + ) + (func (;351;) (type 0) (result i32) + i32.const 351 + ) + (func (;352;) (type 0) (result i32) + i32.const 352 + ) + (func (;353;) (type 0) (result i32) + i32.const 353 + ) + (func (;354;) (type 0) (result i32) + i32.const 354 + ) + (func (;355;) (type 0) (result i32) + i32.const 355 + ) + (func (;356;) (type 0) (result i32) + i32.const 356 + ) + (func (;357;) (type 0) (result i32) + i32.const 357 + ) + (func (;358;) (type 0) (result i32) + i32.const 358 + ) + (func (;359;) (type 0) (result i32) + i32.const 359 + ) + (func (;360;) (type 0) (result i32) + i32.const 360 + ) + (func (;361;) (type 0) (result i32) + i32.const 361 + ) + (func (;362;) (type 0) (result i32) + i32.const 362 + ) + (func (;363;) (type 0) (result i32) + i32.const 363 + ) + (func (;364;) (type 0) (result i32) + i32.const 364 + ) + (func (;365;) (type 0) (result i32) + i32.const 365 + ) + (func (;366;) (type 0) (result i32) + i32.const 366 + ) + (func (;367;) (type 0) (result i32) + i32.const 367 + ) + (func (;368;) (type 0) (result i32) + i32.const 368 + ) + (func (;369;) (type 0) (result i32) + i32.const 369 + ) + (func (;370;) (type 0) (result i32) + i32.const 370 + ) + (func (;371;) (type 0) (result i32) + i32.const 371 + ) + (func (;372;) (type 0) (result i32) + i32.const 372 + ) + (func (;373;) (type 0) (result i32) + i32.const 373 + ) + (func (;374;) (type 0) (result i32) + i32.const 374 + ) + (func (;375;) (type 0) (result i32) + i32.const 375 + ) + (func (;376;) (type 0) (result i32) + i32.const 376 + ) + (func (;377;) (type 0) (result i32) + i32.const 377 + ) + (func (;378;) (type 0) (result i32) + i32.const 378 + ) + (func (;379;) (type 0) (result i32) + i32.const 379 + ) + (func (;380;) (type 0) (result i32) + i32.const 380 + ) + (func (;381;) (type 0) (result i32) + i32.const 381 + ) + (func (;382;) (type 0) (result i32) + i32.const 382 + ) + (func (;383;) (type 0) (result i32) + i32.const 383 + ) + (func (;384;) (type 0) (result i32) + i32.const 384 + ) + (func (;385;) (type 0) (result i32) + i32.const 385 + ) + (func (;386;) (type 0) (result i32) + i32.const 386 + ) + (func (;387;) (type 0) (result i32) + i32.const 387 + ) + (func (;388;) (type 0) (result i32) + i32.const 388 + ) + (func (;389;) (type 0) (result i32) + i32.const 389 + ) + (func (;390;) (type 0) (result i32) + i32.const 390 + ) + (func (;391;) (type 0) (result i32) + i32.const 391 + ) + (func (;392;) (type 0) (result i32) + i32.const 392 + ) + (func (;393;) (type 0) (result i32) + i32.const 393 + ) + (func (;394;) (type 0) (result i32) + i32.const 394 + ) + (func (;395;) (type 0) (result i32) + i32.const 395 + ) + (func (;396;) (type 0) (result i32) + i32.const 396 + ) + (func (;397;) (type 0) (result i32) + i32.const 397 + ) + (func (;398;) (type 0) (result i32) + i32.const 398 + ) + (func (;399;) (type 0) (result i32) + i32.const 399 + ) + (func (;400;) (type 0) (result i32) + i32.const 400 + ) + (func (;401;) (type 0) (result i32) + i32.const 401 + ) + (func (;402;) (type 0) (result i32) + i32.const 402 + ) + (func (;403;) (type 0) (result i32) + i32.const 403 + ) + (func (;404;) (type 0) (result i32) + i32.const 404 + ) + (func (;405;) (type 0) (result i32) + i32.const 405 + ) + (func (;406;) (type 0) (result i32) + i32.const 406 + ) + (func (;407;) (type 0) (result i32) + i32.const 407 + ) + (func (;408;) (type 0) (result i32) + i32.const 408 + ) + (func (;409;) (type 0) (result i32) + i32.const 409 + ) + (func (;410;) (type 0) (result i32) + i32.const 410 + ) + (func (;411;) (type 0) (result i32) + i32.const 411 + ) + (func (;412;) (type 0) (result i32) + i32.const 412 + ) + (func (;413;) (type 0) (result i32) + i32.const 413 + ) + (func (;414;) (type 0) (result i32) + i32.const 414 + ) + (func (;415;) (type 0) (result i32) + i32.const 415 + ) + (func (;416;) (type 0) (result i32) + i32.const 416 + ) + (func (;417;) (type 0) (result i32) + i32.const 417 + ) + (func (;418;) (type 0) (result i32) + i32.const 418 + ) + (func (;419;) (type 0) (result i32) + i32.const 419 + ) + (func (;420;) (type 0) (result i32) + i32.const 420 + ) + (func (;421;) (type 0) (result i32) + i32.const 421 + ) + (func (;422;) (type 0) (result i32) + i32.const 422 + ) + (func (;423;) (type 0) (result i32) + i32.const 423 + ) + (func (;424;) (type 0) (result i32) + i32.const 424 + ) + (func (;425;) (type 0) (result i32) + i32.const 425 + ) + (func (;426;) (type 0) (result i32) + i32.const 426 + ) + (func (;427;) (type 0) (result i32) + i32.const 427 + ) + (func (;428;) (type 0) (result i32) + i32.const 428 + ) + (func (;429;) (type 0) (result i32) + i32.const 429 + ) + (func (;430;) (type 0) (result i32) + i32.const 430 + ) + (func (;431;) (type 0) (result i32) + i32.const 431 + ) + (func (;432;) (type 0) (result i32) + i32.const 432 + ) + (func (;433;) (type 0) (result i32) + i32.const 433 + ) + (func (;434;) (type 0) (result i32) + i32.const 434 + ) + (func (;435;) (type 0) (result i32) + i32.const 435 + ) + (func (;436;) (type 0) (result i32) + i32.const 436 + ) + (func (;437;) (type 0) (result i32) + i32.const 437 + ) + (func (;438;) (type 0) (result i32) + i32.const 438 + ) + (func (;439;) (type 0) (result i32) + i32.const 439 + ) + (func (;440;) (type 0) (result i32) + i32.const 440 + ) + (func (;441;) (type 0) (result i32) + i32.const 441 + ) + (func (;442;) (type 0) (result i32) + i32.const 442 + ) + (func (;443;) (type 0) (result i32) + i32.const 443 + ) + (func (;444;) (type 0) (result i32) + i32.const 444 + ) + (func (;445;) (type 0) (result i32) + i32.const 445 + ) + (func (;446;) (type 0) (result i32) + i32.const 446 + ) + (func (;447;) (type 0) (result i32) + i32.const 447 + ) + (func (;448;) (type 0) (result i32) + i32.const 448 + ) + (func (;449;) (type 0) (result i32) + i32.const 449 + ) + (func (;450;) (type 0) (result i32) + i32.const 450 + ) + (func (;451;) (type 0) (result i32) + i32.const 451 + ) + (func (;452;) (type 0) (result i32) + i32.const 452 + ) + (func (;453;) (type 0) (result i32) + i32.const 453 + ) + (func (;454;) (type 0) (result i32) + i32.const 454 + ) + (func (;455;) (type 0) (result i32) + i32.const 455 + ) + (func (;456;) (type 0) (result i32) + i32.const 456 + ) + (func (;457;) (type 0) (result i32) + i32.const 457 + ) + (func (;458;) (type 0) (result i32) + i32.const 458 + ) + (func (;459;) (type 0) (result i32) + i32.const 459 + ) + (func (;460;) (type 0) (result i32) + i32.const 460 + ) + (func (;461;) (type 0) (result i32) + i32.const 461 + ) + (func (;462;) (type 0) (result i32) + i32.const 462 + ) + (func (;463;) (type 0) (result i32) + i32.const 463 + ) + (func (;464;) (type 0) (result i32) + i32.const 464 + ) + (func (;465;) (type 0) (result i32) + i32.const 465 + ) + (func (;466;) (type 0) (result i32) + i32.const 466 + ) + (func (;467;) (type 0) (result i32) + i32.const 467 + ) + (func (;468;) (type 0) (result i32) + i32.const 468 + ) + (func (;469;) (type 0) (result i32) + i32.const 469 + ) + (func (;470;) (type 0) (result i32) + i32.const 470 + ) + (func (;471;) (type 0) (result i32) + i32.const 471 + ) + (func (;472;) (type 0) (result i32) + i32.const 472 + ) + (func (;473;) (type 0) (result i32) + i32.const 473 + ) + (func (;474;) (type 0) (result i32) + i32.const 474 + ) + (func (;475;) (type 0) (result i32) + i32.const 475 + ) + (func (;476;) (type 0) (result i32) + i32.const 476 + ) + (func (;477;) (type 0) (result i32) + i32.const 477 + ) + (func (;478;) (type 0) (result i32) + i32.const 478 + ) + (export "" (func 0)) + (export "0" (func 1)) + (export "-0" (func 2)) + (export "_" (func 3)) + (export "$" (func 4)) + (export "@" (func 5)) + (export "~!@#$%^&*()_+`-={}|[]\5c:\22;'<>?,./ " (func 6)) + (export "NaN" (func 7)) + (export "Infinity" (func 8)) + (export "if" (func 9)) + (export "malloc" (func 10)) + (export "_malloc" (func 11)) + (export "__malloc" (func 12)) + (export "a" (func 13)) + (export "A" (func 14)) + (export "\ef\bb\bf" (func 15)) + (export "\c3\85" (func 16)) + (export "A\cc\8a" (func 17)) + (export "\e2\84\ab" (func 18)) + (export "\ef\ac\83" (func 19)) + (export "f\ef\ac\81" (func 20)) + (export "ffi" (func 21)) + (export "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f" (func 22)) + (export "\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f" (func 23)) + (export " \7f" (func 24)) + (export "\c2\80\c2\81\c2\82\c2\83\c2\84\c2\85\c2\86\c2\87\c2\88\c2\89\c2\8a\c2\8b\c2\8c\c2\8d\c2\8e\c2\8f" (func 25)) + (export "\c2\90\c2\91\c2\92\c2\93\c2\94\c2\95\c2\96\c2\97\c2\98\c2\99\c2\9a\c2\9b\c2\9c\c2\9d\c2\9e\c2\9f" (func 26)) + (export "\ef\bf\b0\ef\bf\b1\ef\bf\b2\ef\bf\b3\ef\bf\b4\ef\bf\b5\ef\bf\b6\ef\bf\b7" (func 27)) + (export "\ef\bf\b8\ef\bf\b9\ef\bf\ba\ef\bf\bb\ef\bf\bc\ef\bf\bd\ef\bf\be\ef\bf\bf" (func 28)) + (export "\e2\90\80\e2\90\81\e2\90\82\e2\90\83\e2\90\84\e2\90\85\e2\90\86\e2\90\87\e2\90\88\e2\90\89\e2\90\8a\e2\90\8b\e2\90\8c\e2\90\8d\e2\90\8e\e2\90\8f" (func 29)) + (export "\e2\90\90\e2\90\91\e2\90\92\e2\90\93\e2\90\94\e2\90\95\e2\90\96\e2\90\97\e2\90\98\e2\90\99\e2\90\9a\e2\90\9b\e2\90\9c\e2\90\9d\e2\90\9e\e2\90\9f" (func 30)) + (export "\e2\90\a0\e2\90\a1" (func 31)) + (export "\ef\bf\b0\ef\bf\b1\ef\bf\b2\ef\bf\b3\ef\bf\b4\ef\bf\b5\ef\bf\b6\ef\bf\b7\ef\bf\b8\ef\bf\b9\ef\bf\ba\ef\bf\bb\ef\bf\bc\ef\bf\bd" (func 32)) + (export "\e2\80\8d" (func 33)) + (export "\e2\80\8c" (func 34)) + (export "\cd\8f" (func 35)) + (export "\e2\81\a0" (func 36)) + (export "\e2\b5\bf" (func 37)) + (export "\f0\91\81\bf" (func 38)) + (export "\e1\a0\8e" (func 39)) + (export "\ef\bf\af\e2\80\8b\c2\a0\c2\ad\e2\81\a0\e1\9a\80\e2\80\ae\e2\80\ad" (func 40)) + (export "\e2\80\8e\e2\80\8f\e2\80\91\e2\80\a8\e2\80\a9\e2\80\aa\e2\80\ab\e2\80\ac\e2\80\af\e2\81\a6\e2\81\a7\e2\81\a8\e2\81\a9" (func 41)) + (export "\e2\81\aa\e2\81\ab\e2\81\ac\e2\81\ad\e2\81\ae\e2\81\af" (func 42)) + (export "\e2\81\a1\e2\81\a2\e2\81\a3\e2\81\a4" (func 43)) + (export "\f0\90\80\80\f3\9f\bf\bf\f4\8f\bf\bf" (func 44)) + (export "Z\cc\8f\cd\86\cc\86\cd\9b\cd\8c\cc\b4\cd\98\cd\9e\cd\87\cc\ab\cc\a5\cc\aa\cd\93\cd\88\cd\94\cd\8e\cc\97\cc\9e\cc\ba\cc\af\cc\b1\cc\9e\cc\99\cc\b1\cc\9c\cc\96\cc\a0a\cd\97\cd\a8\cc\8e\cc\84\cc\86\cd\97\cc\bf\cd\a1\cd\9f\cd\80\cc\b6\cd\81\cc\a5\cc\b0\cc\b3\cc\ad\cd\99\cc\b2\cc\b1\cc\b9\cc\9d\cd\8e\cc\bcl\cd\84\cd\8a\cc\9a\cd\97\cd\a6\cd\84\cd\ab\cc\87\cd\81\cc\b6\cc\b7\cd\89\cc\a9\cc\b9\cc\ab\cc\9d\cd\96\cd\85\cc\99\cc\b2\cc\bc\cd\87\cd\9a\cd\8d\cc\ae\cd\8e\cc\a5\cd\85\cc\9eg\cd\83\cc\90\cc\85\cd\ae\cc\94\cc\90\cc\8e\cc\82\cc\8f\cc\be\cd\8a\cc\8d\cd\8b\cd\8a\cd\a7\cc\81\cc\86\cd\a6\cd\9e\cc\b6\cd\95\cd\94\cd\9a\cc\a9o\cd\8b\cc\94\cd\90\cd\aa\cd\a9\cc\a1\cd\8f\cc\a2\cc\a7\cd\81\cc\ab\cc\99\cc\a4\cc\ae\cd\96\cd\99\cd\93\cc\ba\cc\9c\cc\a9\cc\bc\cc\98\cc\a0" (func 45)) + (export "\e1\85\9f\e1\85\a0\e3\85\a4\ef\be\a0" (func 46)) + (export "\ef\b8\80" (func 47)) + (export "\ef\b8\84" (func 48)) + (export "\f3\a0\84\80" (func 49)) + (export "\f3\a0\87\af" (func 50)) + (export "\cc\88" (func 51)) + (export "\0a" (func 52)) + (export "\e2\90\a4" (func 53)) + (export "\e2\80\a8" (func 54)) + (export "\0d" (func 55)) + (export "\0d\0a" (func 56)) + (export "\0a\0d" (func 57)) + (export "\1e" (func 58)) + (export "\0b" (func 59)) + (export "\0c" (func 60)) + (export "\c2\85" (func 61)) + (export "\e2\80\a9" (func 62)) + (export "\e2\80\a6" (func 63)) + (export "\e2\8f\8e" (func 64)) + (export "\c2\8b" (func 65)) + (export "\c2\8c" (func 66)) + (export "\c2\8d" (func 67)) + (export "\e2\86\b5" (func 68)) + (export "\e2\86\a9" (func 69)) + (export "\e2\8c\a4" (func 70)) + (export "\e2\a4\b6" (func 71)) + (export "\e2\86\b2" (func 72)) + (export "\e2\ae\a8" (func 73)) + (export "\e2\ae\b0" (func 74)) + (export "\ef\bf\bd" (func 75)) + (export "\ef\b7\90" (func 76)) + (export "\ef\b7\91" (func 77)) + (export "\ef\b7\92" (func 78)) + (export "\ef\b7\93" (func 79)) + (export "\ef\b7\94" (func 80)) + (export "\ef\b7\95" (func 81)) + (export "\ef\b7\96" (func 82)) + (export "\ef\b7\97" (func 83)) + (export "\ef\b7\98" (func 84)) + (export "\ef\b7\99" (func 85)) + (export "\ef\b7\9a" (func 86)) + (export "\ef\b7\9b" (func 87)) + (export "\ef\b7\9c" (func 88)) + (export "\ef\b7\9d" (func 89)) + (export "\ef\b7\9e" (func 90)) + (export "\ef\b7\9f" (func 91)) + (export "\ef\b7\a0" (func 92)) + (export "\ef\b7\a1" (func 93)) + (export "\ef\b7\a2" (func 94)) + (export "\ef\b7\a3" (func 95)) + (export "\ef\b7\a4" (func 96)) + (export "\ef\b7\a5" (func 97)) + (export "\ef\b7\a6" (func 98)) + (export "\ef\b7\a7" (func 99)) + (export "\ef\b7\a8" (func 100)) + (export "\ef\b7\a9" (func 101)) + (export "\ef\b7\aa" (func 102)) + (export "\ef\b7\ab" (func 103)) + (export "\ef\b7\ac" (func 104)) + (export "\ef\b7\ad" (func 105)) + (export "\ef\b7\ae" (func 106)) + (export "\ef\b7\af" (func 107)) + (export "\ef\bf\be" (func 108)) + (export "\ef\bf\bf" (func 109)) + (export "\f0\9f\bf\be" (func 110)) + (export "\f0\9f\bf\bf" (func 111)) + (export "\f0\af\bf\be" (func 112)) + (export "\f0\af\bf\bf" (func 113)) + (export "\f0\bf\bf\be" (func 114)) + (export "\f0\bf\bf\bf" (func 115)) + (export "\f1\8f\bf\be" (func 116)) + (export "\f1\8f\bf\bf" (func 117)) + (export "\f1\9f\bf\be" (func 118)) + (export "\f1\9f\bf\bf" (func 119)) + (export "\f1\af\bf\be" (func 120)) + (export "\f1\af\bf\bf" (func 121)) + (export "\f1\bf\bf\be" (func 122)) + (export "\f1\bf\bf\bf" (func 123)) + (export "\f2\8f\bf\be" (func 124)) + (export "\f2\8f\bf\bf" (func 125)) + (export "\f2\9f\bf\be" (func 126)) + (export "\f2\9f\bf\bf" (func 127)) + (export "\f2\af\bf\be" (func 128)) + (export "\f2\af\bf\bf" (func 129)) + (export "\f2\bf\bf\be" (func 130)) + (export "\f2\bf\bf\bf" (func 131)) + (export "\f3\8f\bf\be" (func 132)) + (export "\f3\8f\bf\bf" (func 133)) + (export "\f3\9f\bf\be" (func 134)) + (export "\f3\9f\bf\bf" (func 135)) + (export "\f3\af\bf\be" (func 136)) + (export "\f3\af\bf\bf" (func 137)) + (export "\f3\bf\bf\be" (func 138)) + (export "\f3\bf\bf\bf" (func 139)) + (export "\f4\8f\bf\be" (func 140)) + (export "\f4\8f\bf\bf" (func 141)) + (export "\cc\88\e2\80\bd\cc\88\cc\89" (func 142)) + (export "abc" (func 143)) + (export "\e2\80\adabc" (func 144)) + (export "\e2\80\aecba" (func 145)) + (export "\e2\80\adabc\e2\80\ae" (func 146)) + (export "\e2\80\aecba\e2\80\ad" (func 147)) + (export "\f0\9d\91\a8" (func 148)) + (export "\f0\9d\90\b4" (func 149)) + (export "\f0\9d\98\88" (func 150)) + (export "\f0\9d\98\bc" (func 151)) + (export "\f0\9d\90\80" (func 152)) + (export "\f0\9d\93\90" (func 153)) + (export "\f0\9d\95\ac" (func 154)) + (export "\f0\9d\97\94" (func 155)) + (export "\f0\9d\92\9c" (func 156)) + (export "\f0\9d\94\84" (func 157)) + (export "\f0\9d\94\b8" (func 158)) + (export "\f0\9d\96\a0" (func 159)) + (export "\f0\9d\99\b0" (func 160)) + (export "\e1\b4\80" (func 161)) + (export "\e1\b4\ac" (func 162)) + (export "\e2\92\b6" (func 163)) + (export "\ef\bc\a1" (func 164)) + (export "\f0\9f\84\90" (func 165)) + (export "\f0\9f\84\b0" (func 166)) + (export "\f3\a0\81\81" (func 167)) + (export "U+0041" (func 168)) + (export "A\e2\80\8b" (func 169)) + (export "\d0\90" (func 170)) + (export "\ea\99\96" (func 171)) + (export "\e2\b7\bc" (func 172)) + (export "\e2\b7\b6" (func 173)) + (export "\e2\b1\af" (func 174)) + (export "\f0\9f\85\90" (func 175)) + (export "\f0\9f\85\b0" (func 176)) + (export "\e2\b0\ad" (func 177)) + (export "\f0\90\90\82" (func 178)) + (export "\f0\90\90\88" (func 179)) + (export "\f0\90\92\b0" (func 180)) + (export "\c3\80" (func 181)) + (export "\c3\81" (func 182)) + (export "\c3\82" (func 183)) + (export "\c3\83" (func 184)) + (export "\c3\84" (func 185)) + (export "\c4\80" (func 186)) + (export "\c4\82" (func 187)) + (export "\c4\84" (func 188)) + (export "\c7\8d" (func 189)) + (export "\c7\9e" (func 190)) + (export "\c7\a0" (func 191)) + (export "\c7\ba" (func 192)) + (export "\c8\80" (func 193)) + (export "\c8\82" (func 194)) + (export "\c8\a6" (func 195)) + (export "\c8\ba" (func 196)) + (export "\d3\90" (func 197)) + (export "\d3\92" (func 198)) + (export "\df\8a" (func 199)) + (export "\e0\a0\a1" (func 200)) + (export "\e0\a0\a2" (func 201)) + (export "\e0\a0\a3" (func 202)) + (export "\e0\a0\a4" (func 203)) + (export "\e0\a0\a5" (func 204)) + (export "\e0\a4\84" (func 205)) + (export "\e0\a4\85" (func 206)) + (export "\e0\a5\b2" (func 207)) + (export "\e0\a6\85" (func 208)) + (export "\e0\a8\85" (func 209)) + (export "\e0\aa\85" (func 210)) + (export "\e0\ac\85" (func 211)) + (export "\e0\ae\85" (func 212)) + (export "\e0\b0\85" (func 213)) + (export "\e0\b2\85" (func 214)) + (export "\e0\b4\85" (func 215)) + (export "\e0\b8\b0" (func 216)) + (export "\e0\ba\b0" (func 217)) + (export "\e0\bc\81" (func 218)) + (export "\e0\bd\a8" (func 219)) + (export "\e0\be\b8" (func 220)) + (export "\e1\80\a1" (func 221)) + (export "\e1\80\a2" (func 222)) + (export "\e1\82\9c" (func 223)) + (export "\e1\85\a1" (func 224)) + (export "\e1\8a\a0" (func 225)) + (export "\e1\8b\90" (func 226)) + (export "\e1\8e\a0" (func 227)) + (export "\e1\90\8a" (func 228)) + (export "\e1\96\b3" (func 229)) + (export "\e1\9a\a8" (func 230)) + (export "\e1\9a\aa" (func 231)) + (export "\e1\9b\86" (func 232)) + (export "\e1\9c\80" (func 233)) + (export "\e1\9c\a0" (func 234)) + (export "\e1\9d\80" (func 235)) + (export "\e1\9d\a0" (func 236)) + (export "\e1\a0\a0" (func 237)) + (export "\e1\a2\87" (func 238)) + (export "\e1\a4\a0" (func 239)) + (export "\e1\a5\a3" (func 240)) + (export "\e1\a8\95" (func 241)) + (export "\e1\a9\8b" (func 242)) + (export "\e1\a9\a1" (func 243)) + (export "\e1\ae\83" (func 244)) + (export "\e1\af\80" (func 245)) + (export "\e1\af\81" (func 246)) + (export "\e1\b0\a3" (func 247)) + (export "\e1\b8\80" (func 248)) + (export "\e1\ba\a0" (func 249)) + (export "\e1\ba\a2" (func 250)) + (export "\e1\ba\a4" (func 251)) + (export "\e1\ba\a6" (func 252)) + (export "\e1\ba\a8" (func 253)) + (export "\e1\ba\aa" (func 254)) + (export "\e1\ba\ac" (func 255)) + (export "\e1\ba\ae" (func 256)) + (export "\e1\ba\b0" (func 257)) + (export "\e1\ba\b2" (func 258)) + (export "\e1\ba\b4" (func 259)) + (export "\e1\ba\b6" (func 260)) + (export "\e3\81\82" (func 261)) + (export "\e3\82\a2" (func 262)) + (export "\e3\84\9a" (func 263)) + (export "\e3\85\8f" (func 264)) + (export "\e3\88\8e" (func 265)) + (export "\e3\88\8f" (func 266)) + (export "\e3\88\90" (func 267)) + (export "\e3\88\91" (func 268)) + (export "\e3\88\92" (func 269)) + (export "\e3\88\93" (func 270)) + (export "\e3\88\94" (func 271)) + (export "\e3\88\95" (func 272)) + (export "\e3\88\96" (func 273)) + (export "\e3\88\97" (func 274)) + (export "\e3\88\98" (func 275)) + (export "\e3\88\99" (func 276)) + (export "\e3\88\9a" (func 277)) + (export "\e3\88\9b" (func 278)) + (export "\e3\89\ae" (func 279)) + (export "\e3\89\af" (func 280)) + (export "\e3\89\b0" (func 281)) + (export "\e3\89\b1" (func 282)) + (export "\e3\89\b2" (func 283)) + (export "\e3\89\b3" (func 284)) + (export "\e3\89\b4" (func 285)) + (export "\e3\89\b5" (func 286)) + (export "\e3\89\b6" (func 287)) + (export "\e3\89\b7" (func 288)) + (export "\e3\89\b8" (func 289)) + (export "\e3\89\b9" (func 290)) + (export "\e3\89\ba" (func 291)) + (export "\e3\89\bb" (func 292)) + (export "\e3\8b\90" (func 293)) + (export "\ea\80\8a" (func 294)) + (export "\ea\93\ae" (func 295)) + (export "\ea\95\89" (func 296)) + (export "\ea\9a\a0" (func 297)) + (export "\ea\a0\80" (func 298)) + (export "\ea\a0\a3" (func 299)) + (export "\ea\a1\9d" (func 300)) + (export "\ea\a2\82" (func 301)) + (export "\ea\a3\aa" (func 302)) + (export "\ea\a4\a2" (func 303)) + (export "\ea\a5\86" (func 304)) + (export "\ea\a6\84" (func 305)) + (export "\ea\a8\80" (func 306)) + (export "\ef\bd\b1" (func 307)) + (export "\ef\bf\82" (func 308)) + (export "\f0\90\80\80" (func 309)) + (export "\f0\90\8a\80" (func 310)) + (export "\f0\90\8a\a0" (func 311)) + (export "\f0\90\8c\80" (func 312)) + (export "\f0\90\8e\a0" (func 313)) + (export "\f0\90\92\96" (func 314)) + (export "\f0\90\94\80" (func 315)) + (export "\f0\90\9d\80" (func 316)) + (export "\f0\90\a0\80" (func 317)) + (export "\f0\90\a4\a0" (func 318)) + (export "\f0\90\a6\80" (func 319)) + (export "\f0\90\a6\a0" (func 320)) + (export "\f0\90\a8\80" (func 321)) + (export "\f0\90\ac\80" (func 322)) + (export "\f0\90\b0\80" (func 323)) + (export "\f0\90\b0\81" (func 324)) + (export "\f0\90\b2\80" (func 325)) + (export "\f0\91\80\85" (func 326)) + (export "\f0\91\82\83" (func 327)) + (export "\f0\91\84\a7" (func 328)) + (export "\f0\91\85\90" (func 329)) + (export "\f0\91\86\83" (func 330)) + (export "\f0\91\88\80" (func 331)) + (export "\f0\91\8a\80" (func 332)) + (export "\f0\91\8a\b0" (func 333)) + (export "\f0\91\8c\85" (func 334)) + (export "\f0\91\8d\b0" (func 335)) + (export "\f0\91\90\80" (func 336)) + (export "\f0\91\92\81" (func 337)) + (export "\f0\91\96\80" (func 338)) + (export "\f0\91\98\80" (func 339)) + (export "\f0\91\9a\80" (func 340)) + (export "\f0\91\9c\92" (func 341)) + (export "\f0\91\9c\a0" (func 342)) + (export "\f0\91\a2\a1" (func 343)) + (export "\f0\91\ab\95" (func 344)) + (export "\f0\91\b0\80" (func 345)) + (export "\f0\91\b2\8f" (func 346)) + (export "\f0\91\b2\af" (func 347)) + (export "\f0\92\80\80" (func 348)) + (export "\f0\96\a7\95" (func 349)) + (export "\f0\96\a9\86" (func 350)) + (export "\f0\96\ab\a7" (func 351)) + (export "\f0\96\bd\94" (func 352)) + (export "\f0\9b\b1\81" (func 353)) + (export "\f0\9b\b1\a4" (func 354)) + (export "\f0\9e\a0\a3" (func 355)) + (export "\f0\9f\87\a6" (func 356)) + (export "\e2\b1\ad" (func 357)) + (export "\ce\9b" (func 358)) + (export "\e2\b1\b0" (func 359)) + (export "\c2\aa" (func 360)) + (export "\e2\88\80" (func 361)) + (export "\e2\82\b3" (func 362)) + (export "\f0\90\a4\80" (func 363)) + (export "\e2\b2\80" (func 364)) + (export "\f0\90\8c\b0" (func 365)) + (export "\ce\86" (func 366)) + (export "\ce\91" (func 367)) + (export "\e1\bc\88" (func 368)) + (export "\e1\bc\89" (func 369)) + (export "\e1\bc\8a" (func 370)) + (export "\e1\bc\8b" (func 371)) + (export "\e1\bc\8c" (func 372)) + (export "\e1\bc\8d" (func 373)) + (export "\e1\bc\8e" (func 374)) + (export "\e1\bc\8f" (func 375)) + (export "\e1\be\88" (func 376)) + (export "\e1\be\89" (func 377)) + (export "\e1\be\8a" (func 378)) + (export "\e1\be\8b" (func 379)) + (export "\e1\be\8c" (func 380)) + (export "\e1\be\8d" (func 381)) + (export "\e1\be\8e" (func 382)) + (export "\e1\be\8f" (func 383)) + (export "\e1\be\b8" (func 384)) + (export "\e1\be\b9" (func 385)) + (export "\e1\be\ba" (func 386)) + (export "\e1\be\bb" (func 387)) + (export "\e1\be\bc" (func 388)) + (export "\f0\9d\9a\a8" (func 389)) + (export "\f0\9d\9b\a2" (func 390)) + (export "\f0\9d\9c\9c" (func 391)) + (export "\f0\9d\9d\96" (func 392)) + (export "\f0\9d\9e\90" (func 393)) + (export "\e2\8d\b6" (func 394)) + (export "\e2\8d\ba" (func 395)) + (export "\e2\a9\9c" (func 396)) + (export "\e1\97\85" (func 397)) + (export "\e1\8e\aa" (func 398)) + (export ")\cb\ba\cb\bc\f0\94\97\8f\f0\9d\85\b4\f0\9d\85\b6\f0\9d\85\b8\f0\9d\85\ba\e2\81\be\e2\82\8e\e2\9d\a9\e2\9d\ab\e2\9f\af\ef\b4\bf\ef\b8\b6\ef\b9\9a\ef\bc\89\ef\bd\a0\f3\a0\80\a9\e2\9d\b3\e2\9d\b5\e2\9f\a7\e2\9f\a9\e2\9f\ab\e2\9f\ad\e2\a6\88\e2\a6\8a\e2\a6\96\e2\b8\a3\e2\b8\a5\ef\b8\98\ef\b8\b8\ef\b8\ba\ef\b8\bc\ef\b8\be\ef\b9\80\ef\b9\82\ef\b9\84\ef\b9\88\ef\b9\9c\ef\b9\9e\ef\bc\bd\ef\bd\9d\ef\bd\a3\f3\a0\81\9d\f3\a0\81\bd\c2\bb\e2\80\99\e2\80\9d\e2\80\ba\e2\9d\af" (func 399)) + (export "(\cb\b9\cb\bb\f0\94\97\8e\f0\9d\85\b3\f0\9d\85\b5\f0\9d\85\b7\f0\9d\85\b9\e2\81\bd\e2\82\8d\e2\9d\a8\e2\9d\aa\e2\9f\ae\ef\b4\be\ef\b8\b5\ef\b9\99\ef\bc\88\ef\bd\9f\f3\a0\80\a8\e2\9d\b2\e2\9d\b4\e2\9f\a6\e2\9f\a8\e2\9f\aa\e2\9f\ac\e2\a6\87\e2\a6\89\e2\a6\95\e2\b8\a2\e2\b8\a4\ef\b8\97\ef\b8\b7\ef\b8\b9\ef\b8\bb\ef\b8\bd\ef\b8\bf\ef\b9\81\ef\b9\83\ef\b9\87\ef\b9\9b\ef\b9\9d\ef\bc\bb\ef\bd\9b\ef\bd\a2\f3\a0\81\9b\f3\a0\81\bb\c2\ab\e2\80\98\e2\80\9c\e2\80\b9\e2\9d\ae" (func 400)) + (export "\f0\9d\aa\8b\f0\9d\aa\a4" (func 401)) + (export "\f0\9d\aa\8b" (func 402)) + (export "\c2\bd" (func 403)) + (export "1\e2\81\842" (func 404)) + (export "1/2" (func 405)) + (export "\e0\ad\b3" (func 406)) + (export "\e0\b5\b4" (func 407)) + (export "\e2\b3\bd" (func 408)) + (export "\ea\a0\b1" (func 409)) + (export "\f0\90\85\81" (func 410)) + (export "\f0\90\85\b5" (func 411)) + (export "\f0\90\85\b6" (func 412)) + (export "\f0\90\a6\bd" (func 413)) + (export "\f0\90\b9\bb" (func 414)) + (export "\ef\bc\82" (func 415)) + (export "\7f" (func 416)) + (export "\08" (func 417)) + (export "\e2\8c\ab" (func 418)) + (export "\e2\8c\a6" (func 419)) + (export "\e2\90\88" (func 420)) + (export "\e2\90\a1" (func 421)) + (export "\e1\b7\bb" (func 422)) + (export "\0f" (func 423)) + (export "\e2\86\90" (func 424)) + (export "\e2\8c\a7" (func 425)) + (export "\e2\8d\92" (func 426)) + (export "\e2\8d\94" (func 427)) + (export "\e2\8d\a2" (func 428)) + (export "\e2\8d\ab" (func 429)) + (export "\1a" (func 430)) + (export "\e2\90\a6" (func 431)) + (export "\e2\90\9a" (func 432)) + (export "\ef\bf\bc" (func 433)) + (export "?" (func 434)) + (export "\c2\bf" (func 435)) + (export "\e1\a5\85" (func 436)) + (export "\cd\be" (func 437)) + (export "\d5\9e" (func 438)) + (export "\d8\9f" (func 439)) + (export "\e1\8d\a7" (func 440)) + (export "\e2\81\87" (func 441)) + (export "\e2\8d\b0" (func 442)) + (export "\e2\9d\93" (func 443)) + (export "\e2\9d\94" (func 444)) + (export "\e2\b3\ba" (func 445)) + (export "\e2\b3\bb" (func 446)) + (export "\e2\b8\ae" (func 447)) + (export "\e3\89\84" (func 448)) + (export "\ea\98\8f" (func 449)) + (export "\ea\9b\b7" (func 450)) + (export "\ef\b8\96" (func 451)) + (export "\ef\b9\96" (func 452)) + (export "\ef\bc\9f" (func 453)) + (export "\f0\91\85\83" (func 454)) + (export "\f0\9e\a5\9f" (func 455)) + (export "\f3\a0\80\bf" (func 456)) + (export "\f0\96\a1\84" (func 457)) + (export "\e2\af\91" (func 458)) + (export "\c2\b6" (func 459)) + (export "\e2\81\8b" (func 460)) + (export "\dc\80" (func 461)) + (export "\e1\83\bb" (func 462)) + (export "\e1\8d\a8" (func 463)) + (export "\e3\80\b7" (func 464)) + (export "\e2\9d\a1" (func 465)) + (export "\e2\b8\8f" (func 466)) + (export "\e2\b8\90" (func 467)) + (export "\e2\b8\91" (func 468)) + (export "\e2\b8\8e" (func 469)) + (export "\14" (func 470)) + (export "\e2\98\99" (func 471)) + (export "\e2\b8\bf" (func 472)) + (export "\e3\80\87" (func 473)) + (export "\e0\b9\9b" (func 474)) + (export "\ea\99\ae" (func 475)) + (export "\cf\93" (func 476)) + (export "\cf\94" (func 477)) + (export "\e1\ba\9b" (func 478)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/names.wast/484.print b/tests/snapshots/testsuite/names.wast/484.print new file mode 100644 index 0000000000..fb58415b3d --- /dev/null +++ b/tests/snapshots/testsuite/names.wast/484.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32))) + (import "spectest" "print_i32" (func (;0;) (type 0))) + (import "spectest" "print_i32" (func (;1;) (type 0))) + (func (;2;) (type 1) (param i32 i32) + local.get 0 + call 0 + local.get 1 + call 1 + ) + (export "print32" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/nop.wast/0.print b/tests/snapshots/testsuite/nop.wast/0.print new file mode 100644 index 0000000000..c7a0287809 --- /dev/null +++ b/tests/snapshots/testsuite/nop.wast/0.print @@ -0,0 +1,699 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32 i32 i32) (result i32))) + (type (;3;) (func (result i32))) + (type (;4;) (func (param i32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i32 i32))) + (func $dummy (;0;) (type 1)) + (func $3-ary (;1;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + i32.sub + i32.add + ) + (func (;2;) (type 3) (result i32) + nop + i32.const 1 + ) + (func (;3;) (type 3) (result i32) + call $dummy + nop + i32.const 2 + ) + (func (;4;) (type 3) (result i32) + call $dummy + i32.const 3 + nop + ) + (func (;5;) (type 3) (result i32) + nop + nop + call $dummy + nop + i32.const 4 + nop + nop + ) + (func (;6;) (type 4) (param i32) + nop + local.get 0 + drop + ) + (func (;7;) (type 4) (param i32) + local.get 0 + nop + drop + ) + (func (;8;) (type 4) (param i32) + nop + nop + local.get 0 + nop + nop + drop + ) + (func (;9;) (type 5) (param i32) (result i32) + nop + local.get 0 + local.get 0 + local.get 0 + select + ) + (func (;10;) (type 5) (param i32) (result i32) + local.get 0 + nop + local.get 0 + local.get 0 + select + ) + (func (;11;) (type 5) (param i32) (result i32) + local.get 0 + local.get 0 + nop + local.get 0 + select + ) + (func (;12;) (type 5) (param i32) (result i32) + local.get 0 + local.get 0 + local.get 0 + nop + select + ) + (func (;13;) (type 5) (param i32) (result i32) + nop + local.get 0 + nop + nop + local.get 0 + nop + nop + local.get 0 + nop + nop + select + ) + (func (;14;) (type 3) (result i32) + block (result i32) ;; label = @1 + nop + i32.const 2 + end + ) + (func (;15;) (type 3) (result i32) + block (result i32) ;; label = @1 + call $dummy + nop + i32.const 2 + end + ) + (func (;16;) (type 3) (result i32) + block (result i32) ;; label = @1 + nop + call $dummy + i32.const 3 + nop + end + ) + (func (;17;) (type 3) (result i32) + block (result i32) ;; label = @1 + nop + nop + call $dummy + nop + i32.const 4 + nop + nop + end + ) + (func (;18;) (type 3) (result i32) + loop (result i32) ;; label = @1 + nop + i32.const 2 + end + ) + (func (;19;) (type 3) (result i32) + loop (result i32) ;; label = @1 + call $dummy + nop + i32.const 2 + end + ) + (func (;20;) (type 3) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 3 + nop + end + ) + (func (;21;) (type 3) (result i32) + loop (result i32) ;; label = @1 + nop + nop + call $dummy + nop + i32.const 4 + nop + nop + end + ) + (func (;22;) (type 4) (param i32) + local.get 0 + nop + if ;; label = @1 + call $dummy + end + ) + (func (;23;) (type 4) (param i32) + local.get 0 + if ;; label = @1 + nop + else + call $dummy + end + ) + (func (;24;) (type 4) (param i32) + local.get 0 + if ;; label = @1 + call $dummy + else + nop + end + ) + (func (;25;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + nop + local.get 0 + br 0 (;@1;) + end + ) + (func (;26;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + nop + br 0 (;@1;) + end + ) + (func (;27;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + nop + nop + local.get 0 + nop + nop + br 0 (;@1;) + end + ) + (func (;28;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + nop + local.get 0 + local.get 0 + br_if 0 (;@1;) + end + ) + (func (;29;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + nop + local.get 0 + br_if 0 (;@1;) + end + ) + (func (;30;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + local.get 0 + nop + br_if 0 (;@1;) + end + ) + (func (;31;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + nop + nop + local.get 0 + nop + nop + local.get 0 + nop + nop + br_if 0 (;@1;) + end + ) + (func (;32;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + nop + local.get 0 + local.get 0 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;33;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + nop + local.get 0 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;34;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + local.get 0 + nop + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;35;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + nop + nop + local.get 0 + nop + nop + local.get 0 + nop + nop + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;36;) (type 5) (param i32) (result i32) + nop + local.get 0 + return + ) + (func (;37;) (type 5) (param i32) (result i32) + local.get 0 + nop + return + ) + (func (;38;) (type 5) (param i32) (result i32) + nop + nop + local.get 0 + nop + nop + return + ) + (func (;39;) (type 2) (param i32 i32 i32) (result i32) + nop + local.get 0 + local.get 1 + local.get 2 + call $3-ary + ) + (func (;40;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + nop + local.get 1 + local.get 2 + call $3-ary + ) + (func (;41;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + nop + local.get 2 + call $3-ary + ) + (func (;42;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + nop + call $3-ary + ) + (func (;43;) (type 2) (param i32 i32 i32) (result i32) + nop + nop + local.get 0 + nop + nop + local.get 1 + nop + nop + local.get 2 + nop + nop + call $3-ary + ) + (func (;44;) (type 5) (param i32) (result i32) + nop + local.get 0 + i32.ctz + ) + (func (;45;) (type 5) (param i32) (result i32) + local.get 0 + nop + i32.ctz + ) + (func (;46;) (type 5) (param i32) (result i32) + nop + nop + local.get 0 + nop + nop + i32.ctz + ) + (func (;47;) (type 5) (param i32) (result i32) + nop + local.get 0 + local.get 0 + i32.add + ) + (func (;48;) (type 5) (param i32) (result i32) + local.get 0 + nop + local.get 0 + i32.add + ) + (func (;49;) (type 5) (param i32) (result i32) + local.get 0 + local.get 0 + nop + i32.add + ) + (func (;50;) (type 5) (param i32) (result i32) + nop + local.get 0 + nop + nop + local.get 0 + nop + nop + i32.add + ) + (func (;51;) (type 5) (param i32) (result i32) + nop + local.get 0 + i32.eqz + ) + (func (;52;) (type 5) (param i32) (result i32) + local.get 0 + nop + i32.eqz + ) + (func (;53;) (type 5) (param i32) (result i32) + nop + nop + local.get 0 + nop + nop + i32.eqz + ) + (func (;54;) (type 5) (param i32) (result i32) + nop + local.get 0 + local.get 0 + i32.ne + ) + (func (;55;) (type 5) (param i32) (result i32) + local.get 0 + nop + local.get 0 + i32.ne + ) + (func (;56;) (type 5) (param i32) (result i32) + local.get 0 + local.get 0 + nop + i32.lt_u + ) + (func (;57;) (type 5) (param i32) (result i32) + nop + local.get 0 + nop + nop + local.get 0 + nop + nop + i32.le_s + ) + (func (;58;) (type 5) (param i32) (result i32) + nop + local.get 0 + memory.grow + ) + (func (;59;) (type 5) (param i32) (result i32) + local.get 0 + nop + memory.grow + ) + (func (;60;) (type 5) (param i32) (result i32) + nop + nop + local.get 0 + nop + nop + memory.grow + ) + (func $func (;61;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;62;) (type 3) (result i32) + block (result i32) ;; label = @1 + nop + i32.const 1 + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;63;) (type 3) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + nop + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;64;) (type 3) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + nop + i32.const 0 + call_indirect (type $check) + end + ) + (func (;65;) (type 3) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 0 + nop + call_indirect (type $check) + end + ) + (func (;66;) (type 3) (result i32) + block (result i32) ;; label = @1 + nop + nop + i32.const 1 + nop + nop + i32.const 2 + nop + nop + i32.const 0 + nop + nop + call_indirect (type $check) + end + ) + (func (;67;) (type 5) (param i32) (result i32) + nop + i32.const 2 + local.set 0 + local.get 0 + ) + (func (;68;) (type 5) (param i32) (result i32) + i32.const 2 + nop + local.set 0 + local.get 0 + ) + (func (;69;) (type 5) (param i32) (result i32) + nop + nop + i32.const 2 + nop + nop + local.set 0 + local.get 0 + ) + (func (;70;) (type 5) (param i32) (result i32) + nop + i32.const 2 + local.tee 0 + ) + (func (;71;) (type 5) (param i32) (result i32) + i32.const 2 + nop + local.tee 0 + ) + (func (;72;) (type 5) (param i32) (result i32) + nop + nop + i32.const 2 + nop + nop + local.tee 0 + ) + (func (;73;) (type 3) (result i32) + nop + i32.const 2 + global.set $a + global.get $a + ) + (func (;74;) (type 3) (result i32) + i32.const 2 + nop + global.set $a + global.get $a + ) + (func (;75;) (type 3) (result i32) + nop + nop + i32.const 2 + nop + nop + global.set $a + global.get $a + ) + (func (;76;) (type 5) (param i32) (result i32) + nop + local.get 0 + i32.load + ) + (func (;77;) (type 5) (param i32) (result i32) + local.get 0 + nop + i32.load + ) + (func (;78;) (type 5) (param i32) (result i32) + nop + nop + local.get 0 + nop + nop + i32.load + ) + (func (;79;) (type 6) (param i32 i32) + nop + local.get 0 + local.get 1 + i32.store + ) + (func (;80;) (type 6) (param i32 i32) + local.get 0 + nop + local.get 1 + i32.store + ) + (func (;81;) (type 6) (param i32 i32) + local.get 0 + local.get 1 + nop + i32.store + ) + (func (;82;) (type 6) (param i32 i32) + nop + nop + local.get 0 + nop + nop + local.get 1 + nop + nop + i32.store + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 0) + (export "as-func-first" (func 2)) + (export "as-func-mid" (func 3)) + (export "as-func-last" (func 4)) + (export "as-func-everywhere" (func 5)) + (export "as-drop-first" (func 6)) + (export "as-drop-last" (func 7)) + (export "as-drop-everywhere" (func 8)) + (export "as-select-first" (func 9)) + (export "as-select-mid1" (func 10)) + (export "as-select-mid2" (func 11)) + (export "as-select-last" (func 12)) + (export "as-select-everywhere" (func 13)) + (export "as-block-first" (func 14)) + (export "as-block-mid" (func 15)) + (export "as-block-last" (func 16)) + (export "as-block-everywhere" (func 17)) + (export "as-loop-first" (func 18)) + (export "as-loop-mid" (func 19)) + (export "as-loop-last" (func 20)) + (export "as-loop-everywhere" (func 21)) + (export "as-if-condition" (func 22)) + (export "as-if-then" (func 23)) + (export "as-if-else" (func 24)) + (export "as-br-first" (func 25)) + (export "as-br-last" (func 26)) + (export "as-br-everywhere" (func 27)) + (export "as-br_if-first" (func 28)) + (export "as-br_if-mid" (func 29)) + (export "as-br_if-last" (func 30)) + (export "as-br_if-everywhere" (func 31)) + (export "as-br_table-first" (func 32)) + (export "as-br_table-mid" (func 33)) + (export "as-br_table-last" (func 34)) + (export "as-br_table-everywhere" (func 35)) + (export "as-return-first" (func 36)) + (export "as-return-last" (func 37)) + (export "as-return-everywhere" (func 38)) + (export "as-call-first" (func 39)) + (export "as-call-mid1" (func 40)) + (export "as-call-mid2" (func 41)) + (export "as-call-last" (func 42)) + (export "as-call-everywhere" (func 43)) + (export "as-unary-first" (func 44)) + (export "as-unary-last" (func 45)) + (export "as-unary-everywhere" (func 46)) + (export "as-binary-first" (func 47)) + (export "as-binary-mid" (func 48)) + (export "as-binary-last" (func 49)) + (export "as-binary-everywhere" (func 50)) + (export "as-test-first" (func 51)) + (export "as-test-last" (func 52)) + (export "as-test-everywhere" (func 53)) + (export "as-compare-first" (func 54)) + (export "as-compare-mid" (func 55)) + (export "as-compare-last" (func 56)) + (export "as-compare-everywhere" (func 57)) + (export "as-memory.grow-first" (func 58)) + (export "as-memory.grow-last" (func 59)) + (export "as-memory.grow-everywhere" (func 60)) + (export "as-call_indirect-first" (func 62)) + (export "as-call_indirect-mid1" (func 63)) + (export "as-call_indirect-mid2" (func 64)) + (export "as-call_indirect-last" (func 65)) + (export "as-call_indirect-everywhere" (func 66)) + (export "as-local.set-first" (func 67)) + (export "as-local.set-last" (func 68)) + (export "as-local.set-everywhere" (func 69)) + (export "as-local.tee-first" (func 70)) + (export "as-local.tee-last" (func 71)) + (export "as-local.tee-everywhere" (func 72)) + (export "as-global.set-first" (func 73)) + (export "as-global.set-last" (func 74)) + (export "as-global.set-everywhere" (func 75)) + (export "as-load-first" (func 76)) + (export "as-load-last" (func 77)) + (export "as-load-everywhere" (func 78)) + (export "as-store-first" (func 79)) + (export "as-store-mid" (func 80)) + (export "as-store-last" (func 81)) + (export "as-store-everywhere" (func 82)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/annotations/annotations.wast/0.print b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/annotations/annotations.wast/10.print b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/10.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/10.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/annotations/annotations.wast/11.print b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/11.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/11.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/annotations/annotations.wast/14.print b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/14.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/14.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/annotations/annotations.wast/33.print b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/33.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/33.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/annotations/annotations.wast/65.print b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/65.print new file mode 100644 index 0000000000..2984e3d240 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/65.print @@ -0,0 +1,11 @@ +(module $m + (type (;0;) (func (param i32 f32))) + (import "spectest" "global_i32" (global $g (;0;) i32)) + (import "spectest" "table" (table $t (;0;) 10 20 funcref)) + (import "spectest" "memory" (memory $m (;0;) 1 2)) + (import "spectest" "print_i32_f32" (func $f (;0;) (type 0))) + (export "g" (global $g)) + (export "t" (table $t)) + (export "m" (memory $m)) + (export "f" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/annotations/annotations.wast/66.print b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/66.print new file mode 100644 index 0000000000..54b66b0a3e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/66.print @@ -0,0 +1,11 @@ +(module $m1 + (type (;0;) (func (param i32 f32))) + (import "spectest" "global_i32" (global $g (;0;) i32)) + (import "spectest" "table" (table $t (;0;) 10 20 funcref)) + (import "spectest" "memory" (memory $m (;0;) 1 2)) + (import "spectest" "print_i32_f32" (func $f (;0;) (type 0))) + (export "g" (global $g)) + (export "t" (table $t)) + (export "m" (memory $m)) + (export "f" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/annotations/annotations.wast/67.print b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/67.print new file mode 100644 index 0000000000..8122b59a84 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/annotations/annotations.wast/67.print @@ -0,0 +1,23 @@ +(module $m2 + (type $T (;0;) (func (param i32 i64 i32) (result i32))) + (type (;1;) (func)) + (func $f (;0;) (type $T) (param i32 i64) (param $x i32) (result i32) + (local i32 i32) (local $y i32) + block (result i32) ;; label = @1 + local.get $x + local.get 0 + i32.add + end + ) + (func $s (;1;) (type 1)) + (table $t (;0;) 10 20 funcref) + (memory $m (;0;) 1 2) + (global $g (;0;) i32 i32.const 42) + (export "g" (global $g)) + (export "t" (table $t)) + (export "m" (memory $m)) + (export "f" (func $f)) + (start $s) + (elem (;0;) (i32.const 0) func $f $f $f) + (data (;0;) (i32.const 0) "blaC") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/0.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/1.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/103.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/103.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/103.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/108.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/108.print new file mode 100644 index 0000000000..17f0618fdf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/108.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 1 + if ;; label = @2 + i32.const 1 + br_table 2 (;@0;) + end + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/110.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/110.print new file mode 100644 index 0000000000..a2354a64c3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/110.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (start 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/2.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/2.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/2.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/3.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/3.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/3.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/55.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/55.print new file mode 100644 index 0000000000..3171d8f4fb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/55.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local f32 f32) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/60.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/60.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/60.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/61.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/61.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/61.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/68.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/68.print new file mode 100644 index 0000000000..a72fa86b64 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/68.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/69.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/69.print new file mode 100644 index 0000000000..8a3ff91247 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/69.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.null func)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/70.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/70.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/70.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/73.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/73.print new file mode 100644 index 0000000000..c47d05badc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/73.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/82.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/82.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/82.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/87.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/87.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/87.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/93.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/93.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/93.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/96.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/96.print new file mode 100644 index 0000000000..1270a74e97 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/96.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/99.print b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/99.print new file mode 100644 index 0000000000..a0fe812a51 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/binary.wast/99.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/0.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/0.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/0.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/1.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/1.print new file mode 100644 index 0000000000..e7a58f9dc9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/1.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) + (export "b" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/10.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/10.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/10.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/11.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/11.print new file mode 100644 index 0000000000..c34519993c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/11.print @@ -0,0 +1,10 @@ +(module $Func + (type (;0;) (func (param i32) (result i32))) + (func $f (;0;) (type 0) (param $n i32) (result i32) + local.get $n + i32.const 1 + i32.add + return + ) + (export "e" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/14.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/14.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/14.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/15.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/15.print new file mode 100644 index 0000000000..5d29297e1f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/15.print @@ -0,0 +1 @@ +(module $Other1) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/17.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/17.print new file mode 100644 index 0000000000..9b016a3b70 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/17.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 42 + ) + (export "a" (func 0)) + (export "b" (func 0)) + (export "c" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/2.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/2.print new file mode 100644 index 0000000000..92bc234966 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/2.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) + (export "a" (func 0)) + (export "b" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/3.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/3.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/3.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/30.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/30.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/30.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/31.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/31.print new file mode 100644 index 0000000000..cb29da92eb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/31.print @@ -0,0 +1,5 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) + (export "b" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/32.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/32.print new file mode 100644 index 0000000000..ce572cc593 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/32.print @@ -0,0 +1,6 @@ +(module + (global (;0;) i32 i32.const 0) + (global (;1;) i32 i32.const 0) + (export "a" (global 0)) + (export "b" (global 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/33.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/33.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/33.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/34.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/34.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/34.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/35.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/35.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/35.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/36.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/36.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/36.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/37.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/37.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/37.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/38.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/38.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/38.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/39.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/39.print new file mode 100644 index 0000000000..ce0c9c5233 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/39.print @@ -0,0 +1,4 @@ +(module $Global + (global $g (;0;) i32 i32.const 42) + (export "e" (global $g)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/4.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/4.print new file mode 100644 index 0000000000..1e92fbc9f7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/4.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) + (export "b" (func 0)) + (export "c" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/42.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/42.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/42.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/43.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/43.print new file mode 100644 index 0000000000..95a91d8cad --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/43.print @@ -0,0 +1 @@ +(module $Other2) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/5.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/5.print new file mode 100644 index 0000000000..786bbc30b4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/5.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param i32)) + (export "a" (func 0)) + (export "b" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/53.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/53.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/53.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/54.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/54.print new file mode 100644 index 0000000000..eadf450224 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/54.print @@ -0,0 +1,5 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) + (export "b" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/55.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/55.print new file mode 100644 index 0000000000..d0cac41d19 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/55.print @@ -0,0 +1,6 @@ +(module + (table (;0;) 0 funcref) + (table (;1;) 0 funcref) + (export "a" (table 0)) + (export "b" (table 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/56.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/56.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/56.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/57.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/57.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/57.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/58.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/58.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/58.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/59.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/59.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/59.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/6.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/6.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/6.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/60.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/60.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/60.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/61.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/61.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/61.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/62.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/62.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/62.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/63.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/63.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/63.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/64.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/64.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/64.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/65.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/65.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/65.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/66.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/66.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/66.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/67.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/67.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/67.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/7.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/7.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/7.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/76.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/76.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/76.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/77.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/77.print new file mode 100644 index 0000000000..277573bf82 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/77.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) + (export "b" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/78.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/78.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/78.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/79.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/79.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/79.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/8.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/8.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/8.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/80.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/80.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/80.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/81.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/81.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/81.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/82.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/82.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/82.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/83.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/83.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/83.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/84.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/84.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/84.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/85.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/85.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/85.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/86.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/86.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/86.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/87.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/87.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/87.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/88.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/88.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/88.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/89.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/89.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/89.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/9.print b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/9.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/exports.wast/9.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/0.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/0.print new file mode 100644 index 0000000000..b149a05a8a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/0.print @@ -0,0 +1,49 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (result i32))) + (type (;4;) (func (result f32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i64) (result i64))) + (func (;0;) (type 0)) + (func (;1;) (type 1) (param i32)) + (func (;2;) (type 2) (param f32)) + (func (;3;) (type 3) (result i32) + i32.const 22 + ) + (func (;4;) (type 4) (result f32) + f32.const 0x1.6p+3 (;=11;) + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;6;) (type 6) (param i64) (result i64) + local.get 0 + ) + (table (;0;) 10 funcref) + (table (;1;) 10 20 funcref) + (memory (;0;) 2) + (tag (;0;) (type 0)) + (tag (;1;) (type 1) (param i32)) + (tag (;2;) (type 2) (param f32)) + (global (;0;) i32 i32.const 55) + (global (;1;) f32 f32.const 0x1.6p+5 (;=44;)) + (global (;2;) (mut i64) i64.const 66) + (export "func" (func 0)) + (export "func-i32" (func 1)) + (export "func-f32" (func 2)) + (export "func->i32" (func 3)) + (export "func->f32" (func 4)) + (export "func-i32->i32" (func 5)) + (export "func-i64->i64" (func 6)) + (export "global-i32" (global 0)) + (export "global-f32" (global 1)) + (export "global-mut-i64" (global 2)) + (export "table-10-inf" (table 0)) + (export "table-10-20" (table 1)) + (export "memory-2-inf" (memory 0)) + (export "tag" (tag 0)) + (export "tag-i32" (tag 1)) + (export "tag-f32" (tag 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/10.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/10.print new file mode 100644 index 0000000000..22a02a9053 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/10.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (import "test" "func" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/100.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/100.print new file mode 100644 index 0000000000..64a52acf28 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/100.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/101.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/101.print new file mode 100644 index 0000000000..218d7d9bdc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/101.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/102.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/102.print new file mode 100644 index 0000000000..2a0fa834a7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/102.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/103.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/103.print new file mode 100644 index 0000000000..03446a5f52 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/103.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/104.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/104.print new file mode 100644 index 0000000000..d1cff0037a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/104.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/105.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/105.print new file mode 100644 index 0000000000..65ae983998 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/105.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 0 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/106.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/106.print new file mode 100644 index 0000000000..9c95837f51 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/106.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/107.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/107.print new file mode 100644 index 0000000000..45fc077841 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/107.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/11.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/11.print new file mode 100644 index 0000000000..782997f244 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/11.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "test" "func-i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/12.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/12.print new file mode 100644 index 0000000000..ace1d7c959 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/12.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param f32))) + (import "test" "func-f32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/120.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/120.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/120.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/125.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/125.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/125.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/13.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/13.print new file mode 100644 index 0000000000..0744a46fba --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/13.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (result i32))) + (import "test" "func->i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/133.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/133.print new file mode 100644 index 0000000000..1aad2d0f8d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/133.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/134.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/134.print new file mode 100644 index 0000000000..546d8eaedc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/134.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/135.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/135.print new file mode 100644 index 0000000000..e40926e430 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/135.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/136.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/136.print new file mode 100644 index 0000000000..3c97146026 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/136.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/137.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/137.print new file mode 100644 index 0000000000..83efcab834 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/137.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/138.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/138.print new file mode 100644 index 0000000000..404698c724 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/138.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/139.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/139.print new file mode 100644 index 0000000000..39db875587 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/139.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/14.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/14.print new file mode 100644 index 0000000000..3b07b2a04c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/14.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (result f32))) + (import "test" "func->f32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/140.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/140.print new file mode 100644 index 0000000000..897e9b716b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/140.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/141.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/141.print new file mode 100644 index 0000000000..c0d28c6be7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/141.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/15.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/15.print new file mode 100644 index 0000000000..e6ddafe344 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/15.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "test" "func-i32->i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/156.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/156.print new file mode 100644 index 0000000000..73ee1fb50c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/156.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 0 3)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/16.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/16.print new file mode 100644 index 0000000000..c5ca6af197 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/16.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (import "test" "func-i64->i64" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/162.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/162.print new file mode 100644 index 0000000000..7efe25f1d8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/162.print @@ -0,0 +1,10 @@ +(module $Mgm + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + memory.grow + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/165.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/165.print new file mode 100644 index 0000000000..477ca763be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/165.print @@ -0,0 +1,10 @@ +(module $Mgim1 + (type (;0;) (func (result i32))) + (import "grown-memory" "memory" (memory (;0;) 2)) + (func (;0;) (type 0) (result i32) + i32.const 1 + memory.grow + ) + (export "memory" (memory 0)) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/168.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/168.print new file mode 100644 index 0000000000..80793cacec --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/168.print @@ -0,0 +1,8 @@ +(module $Mgim2 + (type (;0;) (func (result i32))) + (import "grown-imported-memory" "memory" (memory (;0;) 3)) + (func (;0;) (type 0) (result i32) + memory.size + ) + (export "size" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/186.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/186.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/186.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/2.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/2.print new file mode 100644 index 0000000000..f9c3f2a3f4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/2.print @@ -0,0 +1,85 @@ +(module + (type $func_i32 (;0;) (func (param i32))) + (type $func_i64 (;1;) (func (param i64))) + (type $func_f32 (;2;) (func (param f32))) + (type $func_f64 (;3;) (func (param f64))) + (type $forward (;4;) (func (param i32))) + (type (;5;) (func (param i32 f32))) + (type (;6;) (func (param f64 f64))) + (type (;7;) (func (param i64) (result i64))) + (import "spectest" "print_i32" (func (;0;) (type $func_i32))) + (import "spectest" "print_i64" (func (;1;) (type $func_i64))) + (import "spectest" "print_i32" (func $print_i32 (;2;) (type $func_i32))) + (import "spectest" "print_i64" (func $print_i64 (;3;) (type $func_i64))) + (import "spectest" "print_f32" (func $print_f32 (;4;) (type $func_f32))) + (import "spectest" "print_f64" (func $print_f64 (;5;) (type $func_f64))) + (import "spectest" "print_i32_f32" (func $print_i32_f32 (;6;) (type 5))) + (import "spectest" "print_f64_f64" (func $print_f64_f64 (;7;) (type 6))) + (import "spectest" "print_i32" (func $print_i32-2 (;8;) (type $func_i32))) + (import "spectest" "print_f64" (func $print_f64-2 (;9;) (type $func_f64))) + (import "test" "func-i64->i64" (func $i64->i64 (;10;) (type 7))) + (import "test" "tag-i32" (tag (;0;) (type $func_i32) (param i32))) + (import "test" "tag-f32" (tag (;1;) (type $func_f32) (param f32))) + (import "spectest" "print_i32" (func (;11;) (type $func_i32))) + (import "spectest" "print_i32" (func $p (;12;) (type $func_i32))) + (import "spectest" "print_i32" (func (;13;) (type $func_i32))) + (import "spectest" "print_i32" (func (;14;) (type $func_i32))) + (import "spectest" "print_i32" (func (;15;) (type $func_i32))) + (import "spectest" "print_i32" (func (;16;) (type $forward))) + (import "spectest" "print_i32" (func (;17;) (type $forward))) + (func (;18;) (type $func_i32) (param $i i32) + (local $x f32) + local.get $i + f32.convert_i32_s + local.set $x + local.get $i + call 0 + local.get $i + i32.const 1 + i32.add + f32.const 0x1.5p+5 (;=42;) + call $print_i32_f32 + local.get $i + call $print_i32 + local.get $i + call $print_i32-2 + local.get $x + call $print_f32 + local.get $i + i32.const 0 + call_indirect (type $func_i32) + ) + (func (;19;) (type $func_i64) (param $i i64) + (local $x f64) + local.get $i + call $i64->i64 + f64.convert_i64_s + local.set $x + local.get $i + call 1 + local.get $x + f64.const 0x1p+0 (;=1;) + f64.add + f64.const 0x1.a8p+5 (;=53;) + call $print_f64_f64 + local.get $i + call $print_i64 + local.get $x + call $print_f64 + local.get $x + call $print_f64-2 + local.get $x + i32.const 1 + call_indirect (type $func_f64) + ) + (table (;0;) 2 2 funcref) + (export "p1" (func 11)) + (export "p2" (func $p)) + (export "p3" (func 13)) + (export "p4" (func 13)) + (export "p5" (func 14)) + (export "p6" (func 15)) + (export "print32" (func 18)) + (export "print64" (func 19)) + (elem (;0;) (i32.const 0) func $print_i32 $print_f64) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/47.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/47.print new file mode 100644 index 0000000000..0693cbec34 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/47.print @@ -0,0 +1,26 @@ +(module + (type (;0;) (func (result i32))) + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "global_i32" (global (;1;) i32)) + (import "spectest" "global_i32" (global $x (;2;) i32)) + (import "spectest" "global_i32" (global $y (;3;) i32)) + (import "spectest" "global_i64" (global (;4;) i64)) + (import "spectest" "global_f32" (global (;5;) f32)) + (import "spectest" "global_f64" (global (;6;) f64)) + (func (;0;) (type 0) (result i32) + global.get 0 + ) + (func (;1;) (type 0) (result i32) + global.get 1 + ) + (func (;2;) (type 0) (result i32) + global.get $x + ) + (func (;3;) (type 0) (result i32) + global.get $y + ) + (export "get-0" (func 0)) + (export "get-1" (func 1)) + (export "get-x" (func 2)) + (export "get-y" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/52.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/52.print new file mode 100644 index 0000000000..1b1739a096 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/52.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-i32" (global (;0;) i32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/53.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/53.print new file mode 100644 index 0000000000..eae7b7643b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/53.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-f32" (global (;0;) f32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/54.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/54.print new file mode 100644 index 0000000000..8cff34a430 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/54.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-mut-i64" (global (;0;) (mut i64))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/6.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/6.print new file mode 100644 index 0000000000..63910ab9f5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/6.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func $imported_print (;0;) (type 0))) + (func (;1;) (type 0) (param $i i32) + local.get $i + call $imported_print + ) + (export "print_i32" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/75.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/75.print new file mode 100644 index 0000000000..d06f6c7555 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/75.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "spectest" "table" (table $tab (;0;) 10 20 funcref)) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func $f (;1;) (type 0) (result i32) + i32.const 11 + ) + (func $g (;2;) (type 0) (result i32) + i32.const 22 + ) + (export "call" (func 0)) + (elem (;0;) (i32.const 1) func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/8.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/8.print new file mode 100644 index 0000000000..a93289d203 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/8.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (import "spectest" "print_i32" (func $imported_print (;0;) (type 0))) + (func (;1;) (type 1) (param $i i32) (param $j i32) (result i32) + local.get $i + local.get $j + i32.add + ) + (export "print_i32" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/81.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/81.print new file mode 100644 index 0000000000..d06f6c7555 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/81.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "spectest" "table" (table $tab (;0;) 10 20 funcref)) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func $f (;1;) (type 0) (result i32) + i32.const 11 + ) + (func $g (;2;) (type 0) (result i32) + i32.const 22 + ) + (export "call" (func 0)) + (elem (;0;) (i32.const 1) func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/87.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/87.print new file mode 100644 index 0000000000..9dfcbda865 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/87.print @@ -0,0 +1,6 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (import "spectest" "table" (table (;1;) 0 funcref)) + (table (;2;) 10 funcref) + (table (;3;) 10 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/88.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/88.print new file mode 100644 index 0000000000..72f38c2e80 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/88.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/89.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/89.print new file mode 100644 index 0000000000..475c251b6e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/89.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/90.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/90.print new file mode 100644 index 0000000000..c8997038cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/90.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/91.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/91.print new file mode 100644 index 0000000000..f1e8559446 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/91.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/92.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/92.print new file mode 100644 index 0000000000..4eca2099fe --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/92.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/93.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/93.print new file mode 100644 index 0000000000..18937c5d00 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/93.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/94.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/94.print new file mode 100644 index 0000000000..affb91adc7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/94.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/95.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/95.print new file mode 100644 index 0000000000..b27d0a1814 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/95.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/96.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/96.print new file mode 100644 index 0000000000..d40ae2d3a4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/96.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/97.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/97.print new file mode 100644 index 0000000000..eea2b23b56 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/97.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/98.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/98.print new file mode 100644 index 0000000000..339f1e02ed --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/98.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/99.print b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/99.print new file mode 100644 index 0000000000..5c845b5cc2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/imports.wast/99.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/rethrow.wast/0.print b/tests/snapshots/testsuite/proposals/exception-handling/rethrow.wast/0.print new file mode 100644 index 0000000000..389c4a9b54 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/rethrow.wast/0.print @@ -0,0 +1,98 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + try ;; label = @1 + throw 0 + catch 0 + rethrow 0 (;@1;) + end + ) + (func (;1;) (type 1) (param i32) (result i32) + try (result i32) ;; label = @1 + throw 0 + catch 0 + local.get 0 + i32.eqz + if ;; label = @2 + rethrow 1 (;@1;) + end + i32.const 23 + end + ) + (func (;2;) (type 0) + try ;; label = @1 + throw 0 + catch_all + rethrow 0 (;@1;) + end + ) + (func (;3;) (type 1) (param i32) (result i32) + try (result i32) ;; label = @1 + throw 0 + catch_all + local.get 0 + i32.eqz + if ;; label = @2 + rethrow 1 (;@1;) + end + i32.const 23 + end + ) + (func (;4;) (type 1) (param i32) (result i32) + try (result i32) ;; label = @1 + throw 1 + catch 1 + try (result i32) ;; label = @2 + throw 0 + catch 0 + local.get 0 + i32.const 0 + i32.eq + if ;; label = @3 + rethrow 1 (;@2;) + end + local.get 0 + i32.const 1 + i32.eq + if ;; label = @3 + rethrow 2 (;@1;) + end + i32.const 23 + end + end + ) + (func (;5;) (type 1) (param i32) (result i32) + try (result i32) ;; label = @1 + throw 0 + catch 0 + try (result i32) ;; label = @2 + local.get 0 + i32.eqz + if ;; label = @3 + rethrow 2 (;@1;) + end + i32.const 42 + catch 0 + i32.const 23 + end + end + ) + (func (;6;) (type 0) + try ;; label = @1 + throw 0 + catch 0 + i32.const 1 + rethrow 0 (;@1;) + end + ) + (tag (;0;) (type 0)) + (tag (;1;) (type 0)) + (export "catch-rethrow-0" (func 0)) + (export "catch-rethrow-1" (func 1)) + (export "catchall-rethrow-0" (func 2)) + (export "catchall-rethrow-1" (func 3)) + (export "rethrow-nested" (func 4)) + (export "rethrow-recatch" (func 5)) + (export "rethrow-stack-polymorphism" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/tag.wast/0.print b/tests/snapshots/testsuite/proposals/exception-handling/tag.wast/0.print new file mode 100644 index 0000000000..36049d8d37 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/tag.wast/0.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i32 f32))) + (tag (;0;) (type 0)) + (tag (;1;) (type 1) (param i32)) + (tag (;2;) (type 1) (param i32)) + (tag (;3;) (type 2) (param i32 f32)) + (export "t2" (tag 2)) + (export "t3" (tag 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/exception-handling/tag.wast/2.print b/tests/snapshots/testsuite/proposals/exception-handling/tag.wast/2.print new file mode 100644 index 0000000000..d9f5a1d55a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/exception-handling/tag.wast/2.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 f32))) + (import "test" "t2" (tag (;0;) (type 0) (param i32))) + (import "test" "t3" (tag (;1;) (type 1) (param i32 f32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/0.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/0.print new file mode 100644 index 0000000000..76dcc35a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/0.print @@ -0,0 +1,27 @@ +(module + (memory $m (;0;) 1) + (data (;0;) (i32.const 0) "") + (data (;1;) (i32.const 1) "abcd") + (data (;2;) (i32.const 0) "") + (data (;3;) (i32.const 0) "abc") + (data (;4;) (i32.const 0) "") + (data (;5;) (i32.const 1) "abcd") + (data (;6;) (i32.const 0) "") + (data (;7;) (i32.const 0) "abc") + (data (;8;) (i32.const 0) "") + (data (;9;) (i32.const 1) "abcd") + (data (;10;) (i32.const 0) "") + (data (;11;) (i32.const 0) "abc") + (data $d1 (;12;) (i32.const 0) "") + (data $d2 (;13;) (i32.const 1) "abcd") + (data $d3 (;14;) (i32.const 0) "") + (data $d4 (;15;) (i32.const 0) "abc") + (data $d5 (;16;) (i32.const 0) "") + (data $d6 (;17;) (i32.const 1) "abcd") + (data $d7 (;18;) (i32.const 0) "") + (data $d8 (;19;) (i32.const 0) "abc") + (data $d9 (;20;) (i32.const 0) "") + (data $d10 (;21;) (i32.const 1) "abcd") + (data $d11 (;22;) (i32.const 0) "") + (data $d12 (;23;) (i32.const 0) "abc") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/1.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/1.print new file mode 100644 index 0000000000..cc1e75fe22 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/1.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/11.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/11.print new file mode 100644 index 0000000000..0474fc6565 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/11.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 65535) "b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/12.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/12.print new file mode 100644 index 0000000000..c7cfbb07bb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/12.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 65535) "b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/13.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/13.print new file mode 100644 index 0000000000..0d6dc72126 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/13.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 2) + (data (;0;) (i32.const 131071) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/14.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/14.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/14.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/15.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/15.print new file mode 100644 index 0000000000..bb79a2b2e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/15.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/16.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/16.print new file mode 100644 index 0000000000..70d5011af0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/16.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/17.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/17.print new file mode 100644 index 0000000000..2f4c3a8d18 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/17.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 65536) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/18.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/18.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/18.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/19.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/19.print new file mode 100644 index 0000000000..bb79a2b2e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/19.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/2.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/2.print new file mode 100644 index 0000000000..481aec56e8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/2.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/20.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/20.print new file mode 100644 index 0000000000..70d5011af0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/20.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/21.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/21.print new file mode 100644 index 0000000000..4e08a2a6d1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/21.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/22.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/22.print new file mode 100644 index 0000000000..376eeb676a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/22.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/23.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/23.print new file mode 100644 index 0000000000..18183a143f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/23.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/24.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/24.print new file mode 100644 index 0000000000..86be16f707 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/24.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/25.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/25.print new file mode 100644 index 0000000000..6cb38d0981 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/25.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 1) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/26.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/26.print new file mode 100644 index 0000000000..42df962f09 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/26.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (i32.const 1) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/27.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/27.print new file mode 100644 index 0000000000..37bc8a8757 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/27.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (offset i32.const 0 i32.const 42 i32.add) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/28.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/28.print new file mode 100644 index 0000000000..85a5ce11ab --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/28.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (offset i32.const 42 i32.const 0 i32.sub) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/29.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/29.print new file mode 100644 index 0000000000..4ab595057d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/29.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (offset i32.const 1 i32.const 2 i32.mul) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/3.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/3.print new file mode 100644 index 0000000000..fbef21b722 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/3.print @@ -0,0 +1,8 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 3) "b") + (data (;2;) (i32.const 100) "cde") + (data (;3;) (i32.const 5) "x") + (data (;4;) (i32.const 3) "c") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/30.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/30.print new file mode 100644 index 0000000000..6f559e8567 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/30.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (offset i32.const 2 global.get 0 i32.const 1 i32.sub i32.const 2 i32.add i32.mul) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/4.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/4.print new file mode 100644 index 0000000000..bb6a67d9e3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/4.print @@ -0,0 +1,9 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 1) "b") + (data (;2;) (i32.const 2) "cde") + (data (;3;) (i32.const 3) "f") + (data (;4;) (i32.const 2) "g") + (data (;5;) (i32.const 1) "h") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/5.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/5.print new file mode 100644 index 0000000000..ee7a8e6fe9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/5.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/6.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/6.print new file mode 100644 index 0000000000..55a464f093 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/6.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/7.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/7.print new file mode 100644 index 0000000000..cc48f688bf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/7.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/data.wast/8.print b/tests/snapshots/testsuite/proposals/extended-const/data.wast/8.print new file mode 100644 index 0000000000..9baa7ce142 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/data.wast/8.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/0.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/0.print new file mode 100644 index 0000000000..f5b37aa021 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/0.print @@ -0,0 +1,67 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func $g (;1;) (type 0)) + (table $t (;0;) 10 funcref) + (elem (;0;) funcref) + (elem (;1;) funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem (;2;) func) + (elem (;3;) func $f $f $g $g) + (elem $p1 (;4;) funcref) + (elem $p2 (;5;) funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $p3 (;6;) func) + (elem $p4 (;7;) func $f $f $g $g) + (elem (;8;) (i32.const 0) funcref) + (elem (;9;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;10;) (i32.const 0) func) + (elem (;11;) (i32.const 0) func $f $g) + (elem (;12;) (i32.const 0) funcref) + (elem (;13;) (i32.const 0) func $f $g) + (elem (;14;) (i32.const 0) func) + (elem (;15;) (i32.const 0) func $f $f) + (elem (;16;) (i32.const 0) func) + (elem (;17;) (i32.const 0) func $f $f) + (elem (;18;) (i32.const 0) func) + (elem (;19;) (i32.const 0) func $f $f) + (elem (;20;) (i32.const 0) func) + (elem (;21;) (i32.const 0) func $f $f) + (elem (;22;) (i32.const 0) func) + (elem (;23;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;24;) (i32.const 0) func $f $f) + (elem (;25;) (i32.const 0) func $f $f) + (elem (;26;) (i32.const 0) func) + (elem (;27;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;28;) (i32.const 0) func $f $f) + (elem (;29;) (i32.const 0) func $f $f) + (elem (;30;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a1 (;31;) (i32.const 0) funcref) + (elem $a2 (;32;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a3 (;33;) (i32.const 0) func) + (elem $a4 (;34;) (i32.const 0) func $f $g) + (elem $a9 (;35;) (i32.const 0) funcref) + (elem $a10 (;36;) (i32.const 0) func $f $g) + (elem $a11 (;37;) (i32.const 0) func) + (elem $a12 (;38;) (i32.const 0) func $f $f) + (elem $a13 (;39;) (i32.const 0) func) + (elem $a14 (;40;) (i32.const 0) func $f $f) + (elem $a15 (;41;) (i32.const 0) func) + (elem $a16 (;42;) (i32.const 0) func $f $f) + (elem $a17 (;43;) (i32.const 0) func) + (elem $a18 (;44;) (i32.const 0) func $f $f) + (elem $a19 (;45;) (i32.const 0) func) + (elem $a20 (;46;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a21 (;47;) (i32.const 0) func $f $f) + (elem $a22 (;48;) (i32.const 0) func $f $f) + (elem $a23 (;49;) (i32.const 0) func) + (elem $a24 (;50;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a25 (;51;) (i32.const 0) func $f $f) + (elem $a26 (;52;) (i32.const 0) func $f $f) + (elem (;53;) declare funcref) + (elem (;54;) declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem (;55;) declare func) + (elem (;56;) declare func $f $f $g $g) + (elem $d1 (;57;) declare funcref) + (elem $d2 (;58;) declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $d3 (;59;) declare func) + (elem $d4 (;60;) declare func $f $f $g $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/1.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/1.print new file mode 100644 index 0000000000..609acc4a8d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/1.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func $g (;1;) (type 0)) + (table $t (;0;) 3 3 funcref) + (elem (;0;) (i32.const 0) funcref (ref.func $f) (ref.null func) (ref.func $g)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/11.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/11.print new file mode 100644 index 0000000000..c20a98422b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/11.print @@ -0,0 +1,22 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 11 funcref) + (export "call-7" (func 2)) + (export "call-9" (func 3)) + (elem (;0;) (i32.const 6) funcref (ref.null func) (ref.func $const-i32-a)) + (elem (;1;) (i32.const 9) funcref (ref.func $const-i32-b) (ref.null func)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/16.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/16.print new file mode 100644 index 0000000000..59834e5a95 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/16.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/17.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/17.print new file mode 100644 index 0000000000..6e685d7bc7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/17.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/18.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/18.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/18.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/19.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/19.print new file mode 100644 index 0000000000..b890117b79 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/19.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/2.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/2.print new file mode 100644 index 0000000000..2da39bb2cc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/2.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/20.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/20.print new file mode 100644 index 0000000000..6dd5628226 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/20.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/21.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/21.print new file mode 100644 index 0000000000..9cdf4a4535 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/21.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 20 funcref) + (elem (;0;) (i32.const 20) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/22.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/22.print new file mode 100644 index 0000000000..fdbf02b70d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/22.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/23.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/23.print new file mode 100644 index 0000000000..9a7e48cac6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/23.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 100 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/24.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/24.print new file mode 100644 index 0000000000..8e7e87eeea --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/24.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 1) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/25.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/25.print new file mode 100644 index 0000000000..8e00e00fe9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/25.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 30 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 1) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/3.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/3.print new file mode 100644 index 0000000000..9fbc90ac8a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/3.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/38.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/38.print new file mode 100644 index 0000000000..f553de715e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/38.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func (;1;) (type 0) + i32.const 0 + i32.const 0 + i32.const 1 + table.init $e + ) + (table (;0;) 10 funcref) + (export "init" (func 1)) + (elem $e (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/4.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/4.print new file mode 100644 index 0000000000..fdf2793aac --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/4.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 0) func $f) + (elem (;1;) (i32.const 3) func $f) + (elem (;2;) (i32.const 7) func $f) + (elem (;3;) (i32.const 5) func $f) + (elem (;4;) (i32.const 3) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/40.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/40.print new file mode 100644 index 0000000000..0a8dfffa28 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/40.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func (;1;) (type 0) + i32.const 0 + i32.const 0 + i32.const 1 + table.init $e + ) + (table (;0;) 10 funcref) + (export "init" (func 1)) + (elem $e (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/5.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/5.print new file mode 100644 index 0000000000..2c9c937ee7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/5.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) + (elem (;1;) (i32.const 3) func $f) + (elem (;2;) (i32.const 7) func $f) + (elem (;3;) (i32.const 3) func $f) + (elem (;4;) (i32.const 5) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/6.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/6.print new file mode 100644 index 0000000000..ba9ed82c15 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/6.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (import "spectest" "global_i32" (global (;0;) i32)) + (func $f (;0;) (type 0)) + (table (;0;) 1000 funcref) + (elem (;0;) (global.get 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/63.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/63.print new file mode 100644 index 0000000000..6ad9b0b3b3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/63.print @@ -0,0 +1,17 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call-overwritten" (func 2)) + (elem (;0;) (i32.const 9) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/65.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/65.print new file mode 100644 index 0000000000..9e872c44e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/65.print @@ -0,0 +1,17 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (export "call-overwritten-element" (func 2)) + (elem (;0;) (i32.const 9) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/67.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/67.print new file mode 100644 index 0000000000..a7fafae05a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/67.print @@ -0,0 +1,28 @@ +(module $module1 + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 8 + call_indirect (type $out-i32) + ) + (func (;4;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "shared-table" (table 0)) + (export "call-7" (func 2)) + (export "call-8" (func 3)) + (export "call-9" (func 4)) + (elem (;0;) (i32.const 8) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/7.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/7.print new file mode 100644 index 0000000000..83d7347f17 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/7.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (import "spectest" "global_i32" (global $g (;0;) i32)) + (func $f (;0;) (type 0)) + (table (;0;) 1000 funcref) + (elem (;0;) (global.get $g) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/72.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/72.print new file mode 100644 index 0000000000..27cf2472b6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/72.print @@ -0,0 +1,12 @@ +(module $module2 + (type $out-i32 (;0;) (func (result i32))) + (import "module1" "shared-table" (table (;0;) 10 funcref)) + (func $const-i32-c (;0;) (type $out-i32) (result i32) + i32.const 67 + ) + (func $const-i32-d (;1;) (type $out-i32) (result i32) + i32.const 68 + ) + (elem (;0;) (i32.const 7) func $const-i32-c) + (elem (;1;) (i32.const 8) func $const-i32-d) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/76.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/76.print new file mode 100644 index 0000000000..e0ef8f741b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/76.print @@ -0,0 +1,12 @@ +(module $module3 + (type $out-i32 (;0;) (func (result i32))) + (import "module1" "shared-table" (table (;0;) 10 funcref)) + (func $const-i32-e (;0;) (type $out-i32) (result i32) + i32.const 69 + ) + (func $const-i32-f (;1;) (type $out-i32) (result i32) + i32.const 70 + ) + (elem (;0;) (i32.const 8) func $const-i32-e) + (elem (;1;) (i32.const 9) func $const-i32-f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/8.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/8.print new file mode 100644 index 0000000000..6bb8d5e65f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/8.print @@ -0,0 +1,22 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call-7" (func 2)) + (export "call-9" (func 3)) + (elem (;0;) (i32.const 7) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/84.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/84.print new file mode 100644 index 0000000000..b1267707e4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/84.print @@ -0,0 +1,17 @@ +(module $m + (type (;0;) (func (param i32) (result externref))) + (type (;1;) (func (param i32 externref))) + (func (;0;) (type 0) (param $i i32) (result externref) + local.get $i + table.get $t + ) + (func (;1;) (type 1) (param $i i32) (param $x externref) + local.get $i + local.get $x + table.set $t + ) + (table $t (;0;) 2 externref) + (export "table" (table $t)) + (export "get" (func 0)) + (export "set" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/92.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/92.print new file mode 100644 index 0000000000..c6a336d99d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/92.print @@ -0,0 +1,4 @@ +(module + (import "exporter" "table" (table $t (;0;) 2 externref)) + (elem (;0;) (i32.const 0) externref (ref.null extern)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/95.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/95.print new file mode 100644 index 0000000000..d2623e77ab --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/95.print @@ -0,0 +1,8 @@ +(module $module4 + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 42 + ) + (global (;0;) funcref ref.func 0) + (export "f" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/elem.wast/97.print b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/97.print new file mode 100644 index 0000000000..bd279c1b29 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/elem.wast/97.print @@ -0,0 +1,11 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (import "module4" "f" (global (;0;) funcref)) + (func (;0;) (type $out-i32) (result i32) + i32.const 0 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call_imported_elem" (func 0)) + (elem (;0;) (i32.const 0) funcref (global.get 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/global.wast/0.print b/tests/snapshots/testsuite/proposals/extended-const/global.wast/0.print new file mode 100644 index 0000000000..3ba1aef1f7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/global.wast/0.print @@ -0,0 +1,348 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (result i64))) + (type (;3;) (func (result externref))) + (type (;4;) (func (param i32))) + (type (;5;) (func (param i64))) + (type (;6;) (func (param externref))) + (type (;7;) (func (result f32))) + (type (;8;) (func (result f64))) + (type (;9;) (func (param f32))) + (type (;10;) (func (param f64))) + (type (;11;) (func)) + (type (;12;) (func (param i32) (result i32))) + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "global_i64" (global (;1;) i64)) + (func (;0;) (type 1) (result i32) + global.get $a + ) + (func (;1;) (type 2) (result i64) + global.get $b + ) + (func (;2;) (type 3) (result externref) + global.get $r + ) + (func (;3;) (type 3) (result externref) + global.get $mr + ) + (func (;4;) (type 1) (result i32) + global.get $x + ) + (func (;5;) (type 2) (result i64) + global.get $y + ) + (func (;6;) (type 1) (result i32) + global.get $z1 + ) + (func (;7;) (type 2) (result i64) + global.get $z2 + ) + (func (;8;) (type 1) (result i32) + global.get $z3 + ) + (func (;9;) (type 2) (result i64) + global.get $z4 + ) + (func (;10;) (type 1) (result i32) + global.get $z5 + ) + (func (;11;) (type 2) (result i64) + global.get $z6 + ) + (func (;12;) (type 4) (param i32) + local.get 0 + global.set $x + ) + (func (;13;) (type 5) (param i64) + local.get 0 + global.set $y + ) + (func (;14;) (type 6) (param externref) + local.get 0 + global.set $mr + ) + (func (;15;) (type 7) (result f32) + global.get 3 + ) + (func (;16;) (type 8) (result f64) + global.get 4 + ) + (func (;17;) (type 7) (result f32) + global.get 7 + ) + (func (;18;) (type 8) (result f64) + global.get 8 + ) + (func (;19;) (type 9) (param f32) + local.get 0 + global.set 7 + ) + (func (;20;) (type 10) (param f64) + local.get 0 + global.set 8 + ) + (func $dummy (;21;) (type 11)) + (func (;22;) (type 1) (result i32) + global.get $x + i32.const 2 + i32.const 3 + select + ) + (func (;23;) (type 1) (result i32) + i32.const 2 + global.get $x + i32.const 3 + select + ) + (func (;24;) (type 1) (result i32) + i32.const 2 + i32.const 3 + global.get $x + select + ) + (func (;25;) (type 1) (result i32) + loop (result i32) ;; label = @1 + global.get $x + call $dummy + call $dummy + end + ) + (func (;26;) (type 1) (result i32) + loop (result i32) ;; label = @1 + call $dummy + global.get $x + call $dummy + end + ) + (func (;27;) (type 1) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + global.get $x + end + ) + (func (;28;) (type 1) (result i32) + global.get $x + if (result i32) ;; label = @1 + call $dummy + i32.const 2 + else + call $dummy + i32.const 3 + end + ) + (func (;29;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + global.get $x + else + i32.const 2 + end + ) + (func (;30;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 2 + else + global.get $x + end + ) + (func (;31;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;32;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;33;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;34;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;35;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;36;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;37;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + i32.const 0 + call_indirect (type $check) + end + ) + (func (;38;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + global.get $x + call_indirect (type $check) + end + ) + (func (;39;) (type 11) + global.get $x + i32.const 1 + i32.store + ) + (func (;40;) (type 11) + i32.const 0 + global.get $x + i32.store + ) + (func (;41;) (type 1) (result i32) + global.get $x + i32.load + ) + (func (;42;) (type 1) (result i32) + global.get $x + memory.grow + ) + (func $f (;43;) (type 12) (param i32) (result i32) + local.get 0 + ) + (func (;44;) (type 1) (result i32) + global.get $x + call $f + ) + (func (;45;) (type 1) (result i32) + global.get $x + return + ) + (func (;46;) (type 11) + global.get $x + drop + ) + (func (;47;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + br 0 (;@1;) + end + ) + (func (;48;) (type 12) (param i32) (result i32) + global.get $x + local.set 0 + local.get 0 + ) + (func (;49;) (type 12) (param i32) (result i32) + global.get $x + local.tee 0 + ) + (func (;50;) (type 1) (result i32) + global.get $x + global.set $x + global.get $x + ) + (func (;51;) (type 1) (result i32) + global.get $x + i32.eqz + ) + (func (;52;) (type 1) (result i32) + global.get $x + global.get $x + i32.mul + ) + (func (;53;) (type 1) (result i32) + global.get 0 + i32.const 1 + i32.gt_u + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;2;) i32 i32.const -2) + (global (;3;) f32 f32.const -0x1.8p+1 (;=-3;)) + (global (;4;) f64 f64.const -0x1p+2 (;=-4;)) + (global $b (;5;) i64 i64.const -5) + (global $x (;6;) (mut i32) i32.const -12) + (global (;7;) (mut f32) f32.const -0x1.ap+3 (;=-13;)) + (global (;8;) (mut f64) f64.const -0x1.cp+3 (;=-14;)) + (global $y (;9;) (mut i64) i64.const -15) + (global $z1 (;10;) i32 global.get 0) + (global $z2 (;11;) i64 global.get 1) + (global $z3 (;12;) i32 i32.const 20 i32.const 2 i32.mul i32.const 2 i32.sub i32.const 4 i32.add) + (global $z4 (;13;) i64 i64.const 20 i64.const 2 i64.mul i64.const 2 i64.sub i64.const 5 i64.add) + (global $z5 (;14;) i32 global.get 0 i32.const 42 i32.add) + (global $z6 (;15;) i64 global.get 1 i64.const 42 i64.add) + (global $r (;16;) externref ref.null extern) + (global $mr (;17;) (mut externref) ref.null extern) + (global (;18;) funcref ref.null func) + (export "get-a" (func 0)) + (export "get-b" (func 1)) + (export "get-r" (func 2)) + (export "get-mr" (func 3)) + (export "get-x" (func 4)) + (export "get-y" (func 5)) + (export "get-z1" (func 6)) + (export "get-z2" (func 7)) + (export "get-z3" (func 8)) + (export "get-z4" (func 9)) + (export "get-z5" (func 10)) + (export "get-z6" (func 11)) + (export "set-x" (func 12)) + (export "set-y" (func 13)) + (export "set-mr" (func 14)) + (export "get-3" (func 15)) + (export "get-4" (func 16)) + (export "get-7" (func 17)) + (export "get-8" (func 18)) + (export "set-7" (func 19)) + (export "set-8" (func 20)) + (export "as-select-first" (func 22)) + (export "as-select-mid" (func 23)) + (export "as-select-last" (func 24)) + (export "as-loop-first" (func 25)) + (export "as-loop-mid" (func 26)) + (export "as-loop-last" (func 27)) + (export "as-if-condition" (func 28)) + (export "as-if-then" (func 29)) + (export "as-if-else" (func 30)) + (export "as-br_if-first" (func 31)) + (export "as-br_if-last" (func 32)) + (export "as-br_table-first" (func 33)) + (export "as-br_table-last" (func 34)) + (export "as-call_indirect-first" (func 36)) + (export "as-call_indirect-mid" (func 37)) + (export "as-call_indirect-last" (func 38)) + (export "as-store-first" (func 39)) + (export "as-store-last" (func 40)) + (export "as-load-operand" (func 41)) + (export "as-memory.grow-value" (func 42)) + (export "as-call-value" (func 44)) + (export "as-return-value" (func 45)) + (export "as-drop-operand" (func 46)) + (export "as-br-value" (func 47)) + (export "as-local.set-value" (func 48)) + (export "as-local.tee-value" (func 49)) + (export "as-global.set-value" (func 50)) + (export "as-unary-operand" (func 51)) + (export "as-binary-operand" (func 52)) + (export "as-compare-operand" (func 53)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/global.wast/65.print b/tests/snapshots/testsuite/proposals/extended-const/global.wast/65.print new file mode 100644 index 0000000000..bb29c81054 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/global.wast/65.print @@ -0,0 +1,4 @@ +(module + (global (;0;) (mut f32) f32.const 0x0p+0 (;=0;)) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/global.wast/66.print b/tests/snapshots/testsuite/proposals/extended-const/global.wast/66.print new file mode 100644 index 0000000000..bb29c81054 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/global.wast/66.print @@ -0,0 +1,4 @@ +(module + (global (;0;) (mut f32) f32.const 0x0p+0 (;=0;)) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/global.wast/85.print b/tests/snapshots/testsuite/proposals/extended-const/global.wast/85.print new file mode 100644 index 0000000000..ca7594713b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/global.wast/85.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/extended-const/global.wast/88.print b/tests/snapshots/testsuite/proposals/extended-const/global.wast/88.print new file mode 100644 index 0000000000..e6b79c4e23 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/extended-const/global.wast/88.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/1.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/103.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/103.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/103.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/108.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/108.print new file mode 100644 index 0000000000..17f0618fdf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/108.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 1 + if ;; label = @2 + i32.const 1 + br_table 2 (;@0;) + end + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/110.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/110.print new file mode 100644 index 0000000000..a2354a64c3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/110.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (start 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/2.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/2.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/2.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/3.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/3.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/3.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/55.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/55.print new file mode 100644 index 0000000000..3171d8f4fb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/55.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local f32 f32) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/60.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/60.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/60.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/61.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/61.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/61.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/68.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/68.print new file mode 100644 index 0000000000..a72fa86b64 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/68.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/69.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/69.print new file mode 100644 index 0000000000..8a3ff91247 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/69.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.null func)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/70.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/70.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/70.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/73.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/73.print new file mode 100644 index 0000000000..c47d05badc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/73.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/82.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/82.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/82.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/87.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/87.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/87.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/93.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/93.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/93.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/96.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/96.print new file mode 100644 index 0000000000..1270a74e97 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/96.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/binary.wast/99.print b/tests/snapshots/testsuite/proposals/function-references/binary.wast/99.print new file mode 100644 index 0000000000..a0fe812a51 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/binary.wast/99.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/0.print new file mode 100644 index 0000000000..f8045bc658 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/0.print @@ -0,0 +1,52 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + block $l (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + i32.const -1 + return + end + call_ref $t + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + block $l (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + i32.const -1 + return + end + call_ref $t + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + block $l (result (ref 0)) ;; label = @1 + unreachable + br_on_non_null 0 (;@1;) + i32.const -1 + return + end + call_ref $t + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/5.print b/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/5.print new file mode 100644 index 0000000000..e8ef804e8e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/5.print @@ -0,0 +1,30 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref null 0)))) + (type (;2;) (func (param funcref))) + (type (;3;) (func (param externref))) + (func (;0;) (type 1) (param $r (ref null 0)) + block (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) + (func (;1;) (type 2) (param $r funcref) + block (result (ref func)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) + (func (;2;) (type 3) (param $r externref) + block (result (ref extern)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/6.print b/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/6.print new file mode 100644 index 0000000000..e370706479 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/br_on_non_null.wast/6.print @@ -0,0 +1,32 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 (ref null 0)) (result i32))) + (type (;2;) (func (result i32 (ref 0)))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $a (;1;) (type 1) (param $n i32) (param $r (ref null 0)) (result i32) + block $l (type 2) (result i32 (ref 0)) ;; label = @1 + local.get $n + local.get $r + br_on_non_null 0 (;@1;) + return + end + call_ref $t + ) + (func (;2;) (type $t) (param $n i32) (result i32) + local.get $n + ref.null 0 + call $a + ) + (func (;3;) (type $t) (param $n i32) (result i32) + local.get $n + ref.func $f + call $a + ) + (export "args-null" (func 2)) + (export "args-f" (func 3)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/0.print new file mode 100644 index 0000000000..fdfd989b2e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/0.print @@ -0,0 +1,52 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + block $l ;; label = @1 + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + block $l ;; label = @1 + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + block $l ;; label = @1 + unreachable + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/5.print b/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/5.print new file mode 100644 index 0000000000..4dc0b2d305 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/5.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref null 0)))) + (type (;2;) (func (param funcref))) + (type (;3;) (func (param externref))) + (func (;0;) (type 1) (param $r (ref null 0)) + local.get $r + br_on_null 0 (;@0;) + drop + ) + (func (;1;) (type 2) (param $r funcref) + local.get $r + br_on_null 0 (;@0;) + drop + ) + (func (;2;) (type 3) (param $r externref) + local.get $r + br_on_null 0 (;@0;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/6.print b/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/6.print new file mode 100644 index 0000000000..8be1657f4f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/br_on_null.wast/6.print @@ -0,0 +1,31 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 (ref null 0)) (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $a (;1;) (type 1) (param $n i32) (param $r (ref null 0)) (result i32) + block $l (result i32) ;; label = @1 + local.get $n + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + ) + (func (;2;) (type $t) (param $n i32) (result i32) + local.get $n + ref.null 0 + call $a + ) + (func (;3;) (type $t) (param $n i32) (result i32) + local.get $n + ref.func $f + call $a + ) + (export "args-null" (func 2)) + (export "args-f" (func 3)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/br_table.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/br_table.wast/0.print new file mode 100644 index 0000000000..6c2628a1dc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/br_table.wast/0.print @@ -0,0 +1,928 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type $t (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (type (;4;) (func (result f32))) + (type (;5;) (func (result f64))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (param i32 i32) (result i32))) + (type (;8;) (func (param i32 externref) (result externref))) + (type (;9;) (func (param i32) (result funcref))) + (func $dummy (;0;) (type $t)) + (func (;1;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.ctz + drop + end + ) + (func (;2;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i64.ctz + drop + end + ) + (func (;3;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f32.neg + drop + end + ) + (func (;4;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.neg + drop + end + ) + (func (;5;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.ctz + end + ) + (func (;6;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 2 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i64.ctz + end + ) + (func (;7;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.8p+1 (;=3;) + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f32.neg + end + ) + (func (;8;) (type 5) (result f64) + block (result f64) ;; label = @1 + f64.const 0x1p+2 (;=4;) + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.neg + end + ) + (func (;9;) (type 6) (param i32) (result i32) + block ;; label = @1 + local.get 0 + br_table 0 (;@1;) + i32.const 21 + return + end + i32.const 22 + ) + (func (;10;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 33 + local.get 0 + br_table 0 (;@1;) + i32.const 31 + end + ) + (func (;11;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) + i32.const 21 + return + end + i32.const 20 + return + end + i32.const 22 + ) + (func (;12;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 33 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) + i32.const 31 + return + end + drop + i32.const 32 + end + ) + (func (;13;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + local.get 0 + br_table 3 (;@2;) 2 (;@3;) 1 (;@4;) 0 (;@5;) 4 (;@1;) + i32.const 99 + return + end + i32.const 100 + return + end + i32.const 101 + return + end + i32.const 102 + return + end + i32.const 103 + return + end + i32.const 104 + ) + (func (;14;) (type 6) (param i32) (result i32) + (local i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + block (result i32) ;; label = @3 + block (result i32) ;; label = @4 + block (result i32) ;; label = @5 + i32.const 200 + local.get 0 + br_table 3 (;@2;) 2 (;@3;) 1 (;@4;) 0 (;@5;) 4 (;@1;) + local.get 1 + i32.const 99 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 10 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 11 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 12 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 13 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 14 + i32.add + ) + (func (;15;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) + i32.const -1 + return + end + i32.const 0 + return + end + i32.const 1 + return + ) + (func (;16;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + call $dummy + end + ) + (func (;17;) (type $t) + block ;; label = @1 + call $dummy + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + call $dummy + end + ) + (func (;18;) (type $t) + block ;; label = @1 + nop + call $dummy + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;19;) (type 2) (result i32) + block (result i32) ;; label = @1 + nop + call $dummy + i32.const 2 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;20;) (type 2) (result i32) + loop (result i32) ;; label = @1 + i32.const 3 + i32.const 0 + br_table 1 (;@0;) 1 (;@0;) + i32.const 1 + end + ) + (func (;21;) (type 2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 4 + i32.const -1 + br_table 1 (;@0;) 1 (;@0;) 1 (;@0;) + i32.const 2 + end + ) + (func (;22;) (type 2) (result i32) + loop (result i32) ;; label = @1 + nop + call $dummy + i32.const 5 + i32.const 1 + br_table 1 (;@0;) 1 (;@0;) 1 (;@0;) + end + ) + (func (;23;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 9 + i32.const 0 + br_table 0 (;@1;) + br 0 (;@1;) + end + ) + (func (;24;) (type $t) + block ;; label = @1 + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + br_if 0 (;@1;) + end + ) + (func (;25;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 8 + i32.const 0 + br_table 0 (;@1;) + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;26;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 9 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;27;) (type $t) + block ;; label = @1 + i32.const 1 + br_table 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;28;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 0 + br_table 0 (;@1;) + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;29;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 11 + i32.const 1 + br_table 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;30;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 7 + i32.const 0 + br_table 0 (;@1;) + return + end + ) + (func (;31;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + br_table 0 (;@1;) + if (result i32) ;; label = @2 + i32.const 0 + else + i32.const 1 + end + end + ) + (func (;32;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + i32.const 3 + i32.const 0 + br_table 1 (;@1;) + else + local.get 1 + end + end + ) + (func (;33;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + local.get 1 + else + i32.const 4 + i32.const 0 + br_table 1 (;@1;) 0 (;@2;) + end + end + ) + (func (;34;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + i32.const 5 + i32.const 0 + br_table 0 (;@1;) + local.get 0 + local.get 1 + select + end + ) + (func (;35;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + i32.const 6 + i32.const 1 + br_table 0 (;@1;) + local.get 1 + select + end + ) + (func (;36;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 7 + i32.const 1 + br_table 0 (;@1;) + select + end + ) + (func $f (;37;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;38;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 12 + i32.const 1 + br_table 0 (;@1;) + i32.const 2 + i32.const 3 + call $f + end + ) + (func (;39;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 13 + i32.const 1 + br_table 0 (;@1;) + i32.const 3 + call $f + end + ) + (func (;40;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 14 + i32.const 1 + br_table 0 (;@1;) + call $f + end + ) + (func (;41;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 20 + i32.const 1 + br_table 0 (;@1;) + i32.const 1 + i32.const 2 + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;42;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 21 + i32.const 1 + br_table 0 (;@1;) + i32.const 2 + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;43;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 22 + i32.const 1 + br_table 0 (;@1;) + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;44;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 2 + i32.const 23 + i32.const 1 + br_table 0 (;@1;) + call_indirect (type $sig) + end + ) + (func (;45;) (type 2) (result i32) + (local f32) + block (result i32) ;; label = @1 + i32.const 17 + i32.const 1 + br_table 0 (;@1;) + local.set 0 + i32.const -1 + end + ) + (func (;46;) (type 2) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_table 0 (;@1;) + local.set 0 + i32.const -1 + end + ) + (func (;47;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_table 0 (;@1;) + global.set $a + i32.const -1 + end + ) + (func (;48;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.b33334p+0 (;=1.7;) + i32.const 1 + br_table 0 (;@1;) + f32.load + end + ) + (func (;49;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 30 + i32.const 1 + br_table 0 (;@1;) + i64.load8_s + end + ) + (func (;50;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 30 + i32.const 1 + br_table 0 (;@1;) + f64.const 0x1.cp+2 (;=7;) + f64.store + i32.const -1 + end + ) + (func (;51;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 31 + i32.const 1 + br_table 0 (;@1;) + i64.store + i32.const -1 + end + ) + (func (;52;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 32 + i32.const 0 + br_table 0 (;@1;) + i32.const 7 + i32.store8 + i32.const -1 + end + ) + (func (;53;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 33 + i32.const 0 + br_table 0 (;@1;) + i64.store16 + i32.const -1 + end + ) + (func (;54;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.b33334p+1 (;=3.4;) + i32.const 0 + br_table 0 (;@1;) + f32.neg + end + ) + (func (;55;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.const 10 + i32.add + end + ) + (func (;56;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 10 + i64.const 45 + i32.const 0 + br_table 0 (;@1;) + i64.sub + end + ) + (func (;57;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 44 + i32.const 0 + br_table 0 (;@1;) + i32.eqz + end + ) + (func (;58;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 43 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.const 0x1.4p+3 (;=10;) + f64.le + end + ) + (func (;59;) (type 2) (result i32) + block (result i32) ;; label = @1 + f32.const 0x1.4p+3 (;=10;) + i32.const 42 + i32.const 0 + br_table 0 (;@1;) + f32.ne + end + ) + (func (;60;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 41 + i32.const 0 + br_table 0 (;@1;) + i32.wrap_i64 + end + ) + (func (;61;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 40 + i32.const 0 + br_table 0 (;@1;) + memory.grow + end + ) + (func (;62;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const -1 + drop + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + i32.const 16 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.add + end + i32.add + end + i32.add + end + ) + (func (;63;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 2 (;@1;) 1 (;@2;) 0 (;@3;) + br 0 (;@3;) + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;64;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 1 + br_if 0 (;@3;) + drop + i32.const 32 + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;65;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + i32.const 4 + i32.const 8 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) + br_if 0 (;@2;) + drop + i32.const 16 + end + i32.add + end + ) + (func (;66;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 1 + br_table 0 (;@3;) + i32.const 32 + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;67;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + i32.const 4 + i32.const 8 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) + br_table 0 (;@2;) + i32.const 16 + end + i32.add + end + ) + (func (;68;) (type 6) (param i32) (result i32) + loop (result i32) ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 0 (;@2;) + end + i32.const 0 + end + local.set 0 + loop (result i32) ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 1 (;@1;) + end + i32.const 3 + end + ) + (func (;69;) (type 8) (param i32 externref) (result externref) + block $l1 (result externref) ;; label = @1 + block $l2 (result externref) ;; label = @2 + local.get 1 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;70;) (type $t) + block (result f64) ;; label = @1 + block (result f32) ;; label = @2 + unreachable + i32.const 1 + br_table 0 (;@2;) 1 (;@1;) 1 (;@1;) + end + drop + f64.const 0x0p+0 (;=0;) + end + drop + ) + (func $tf (;71;) (type $t)) + (func (;72;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + i32.const 0 + table.get $t + local.get 0 + br_table 1 (;@1;) 1 (;@1;) 0 (;@2;) + end + end + ) + (func (;73;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + i32.const 0 + table.get $t + local.get 0 + br_table 0 (;@2;) 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;74;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + i32.const 0 + table.get $t + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) + end + end + ) + (func (;75;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + i32.const 0 + table.get $t + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;76;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + ref.null 1 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;77;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + block $l3 (result (ref 1)) ;; label = @3 + ref.func $tf + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + end + end + end + ) + (table (;0;) 1 1 funcref) + (table $t (;1;) 1 1 (ref null 1)) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "type-i32" (func 1)) + (export "type-i64" (func 2)) + (export "type-f32" (func 3)) + (export "type-f64" (func 4)) + (export "type-i32-value" (func 5)) + (export "type-i64-value" (func 6)) + (export "type-f32-value" (func 7)) + (export "type-f64-value" (func 8)) + (export "empty" (func 9)) + (export "empty-value" (func 10)) + (export "singleton" (func 11)) + (export "singleton-value" (func 12)) + (export "multiple" (func 13)) + (export "multiple-value" (func 14)) + (export "large" (func 15)) + (export "as-block-first" (func 16)) + (export "as-block-mid" (func 17)) + (export "as-block-last" (func 18)) + (export "as-block-value" (func 19)) + (export "as-loop-first" (func 20)) + (export "as-loop-mid" (func 21)) + (export "as-loop-last" (func 22)) + (export "as-br-value" (func 23)) + (export "as-br_if-cond" (func 24)) + (export "as-br_if-value" (func 25)) + (export "as-br_if-value-cond" (func 26)) + (export "as-br_table-index" (func 27)) + (export "as-br_table-value" (func 28)) + (export "as-br_table-value-index" (func 29)) + (export "as-return-value" (func 30)) + (export "as-if-cond" (func 31)) + (export "as-if-then" (func 32)) + (export "as-if-else" (func 33)) + (export "as-select-first" (func 34)) + (export "as-select-second" (func 35)) + (export "as-select-cond" (func 36)) + (export "as-call-first" (func 38)) + (export "as-call-mid" (func 39)) + (export "as-call-last" (func 40)) + (export "as-call_indirect-first" (func 41)) + (export "as-call_indirect-mid" (func 42)) + (export "as-call_indirect-last" (func 43)) + (export "as-call_indirect-func" (func 44)) + (export "as-local.set-value" (func 45)) + (export "as-local.tee-value" (func 46)) + (export "as-global.set-value" (func 47)) + (export "as-load-address" (func 48)) + (export "as-loadN-address" (func 49)) + (export "as-store-address" (func 50)) + (export "as-store-value" (func 51)) + (export "as-storeN-address" (func 52)) + (export "as-storeN-value" (func 53)) + (export "as-unary-operand" (func 54)) + (export "as-binary-left" (func 55)) + (export "as-binary-right" (func 56)) + (export "as-test-operand" (func 57)) + (export "as-compare-left" (func 58)) + (export "as-compare-right" (func 59)) + (export "as-convert-operand" (func 60)) + (export "as-memory.grow-size" (func 61)) + (export "nested-block-value" (func 62)) + (export "nested-br-value" (func 63)) + (export "nested-br_if-value" (func 64)) + (export "nested-br_if-value-cond" (func 65)) + (export "nested-br_table-value" (func 66)) + (export "nested-br_table-value-index" (func 67)) + (export "nested-br_table-loop-block" (func 68)) + (export "meet-externref" (func 69)) + (export "meet-bottom" (func 70)) + (export "meet-funcref-1" (func 72)) + (export "meet-funcref-2" (func 73)) + (export "meet-funcref-3" (func 74)) + (export "meet-funcref-4" (func 75)) + (export "meet-nullref" (func 76)) + (export "meet-multi-ref" (func 77)) + (elem (;0;) (i32.const 0) func $f) + (elem (;1;) (table $t) (i32.const 0) (ref null 1) (ref.func $tf)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/0.print new file mode 100644 index 0000000000..b5339eab8e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/0.print @@ -0,0 +1,133 @@ +(module + (type $ii (;0;) (func (param i32) (result i32))) + (type $ll (;1;) (func (param i64) (result i64))) + (type $lll (;2;) (func (param i64 i64) (result i64))) + (type (;3;) (func (param (ref 0) i32) (result i32))) + (type (;4;) (func (result i32))) + (func $apply (;0;) (type 3) (param $f (ref 0)) (param $x i32) (result i32) + local.get $x + local.get $f + call_ref $ii + ) + (func $f (;1;) (type $ii) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $g (;2;) (type $ii) (param i32) (result i32) + i32.const 0 + local.get 0 + i32.sub + ) + (func (;3;) (type $ii) (param $x i32) (result i32) + (local $rf (ref null 0)) (local $rg (ref null 0)) + ref.func $f + local.set $rf + ref.func $g + local.set $rg + local.get $x + local.get $rf + call_ref $ii + local.get $rg + call_ref $ii + ) + (func (;4;) (type 4) (result i32) + i32.const 1 + ref.null 0 + call_ref $ii + ) + (func $fac (;5;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + local.get 0 + i64.const 1 + i64.sub + global.get $fac + call_ref $ll + i64.mul + end + ) + (func $fac-acc (;6;) (type $lll) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + global.get $fac-acc + call_ref $lll + end + ) + (func $fib (;7;) (type $ll) (param i64) (result i64) + local.get 0 + i64.const 1 + i64.le_u + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + i64.const 2 + i64.sub + global.get $fib + call_ref $ll + local.get 0 + i64.const 1 + i64.sub + global.get $fib + call_ref $ll + i64.add + end + ) + (func $even (;8;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 44 + else + local.get 0 + i64.const 1 + i64.sub + global.get $odd + call_ref $ll + end + ) + (func $odd (;9;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 99 + else + local.get 0 + i64.const 1 + i64.sub + global.get $even + call_ref $ll + end + ) + (global $fac (;0;) (ref 1) ref.func $fac) + (global $fac-acc (;1;) (ref 2) ref.func $fac-acc) + (global $fib (;2;) (ref 1) ref.func $fib) + (global $even (;3;) (ref 1) ref.func $even) + (global $odd (;4;) (ref 1) ref.func $odd) + (export "run" (func 3)) + (export "null" (func 4)) + (export "fac" (func $fac)) + (export "fac-acc" (func $fac-acc)) + (export "fib" (func $fib)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) declare func $f $g) + (elem (;1;) declare func $fac) + (elem (;2;) declare func $fac-acc) + (elem (;3;) declare func $fib) + (elem (;4;) declare func $even $odd) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/25.print b/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/25.print new file mode 100644 index 0000000000..9b733d4659 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/25.print @@ -0,0 +1,9 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (result i32))) + (func (;0;) (type 1) (result i32) + unreachable + call_ref $t + ) + (export "unreachable" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/27.print b/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/27.print new file mode 100644 index 0000000000..3f690c6fbc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/27.print @@ -0,0 +1,14 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + ref.func $f + call_ref $t + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/29.print b/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/29.print new file mode 100644 index 0000000000..89b7ecc289 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/call_ref.wast/29.print @@ -0,0 +1,17 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + i32.const 0 + ref.func $f + call_ref $t + drop + i32.const 0 + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/custom.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/custom.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/custom.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/custom.wast/1.print b/tests/snapshots/testsuite/proposals/function-references/custom.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/custom.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/custom.wast/2.print b/tests/snapshots/testsuite/proposals/function-references/custom.wast/2.print new file mode 100644 index 0000000000..d94d24a9d0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/custom.wast/2.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32 i32) (result i32))) + (func (;0;) (type 0) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add + ) + (export "addTwo" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/0.print new file mode 100644 index 0000000000..76dcc35a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/0.print @@ -0,0 +1,27 @@ +(module + (memory $m (;0;) 1) + (data (;0;) (i32.const 0) "") + (data (;1;) (i32.const 1) "abcd") + (data (;2;) (i32.const 0) "") + (data (;3;) (i32.const 0) "abc") + (data (;4;) (i32.const 0) "") + (data (;5;) (i32.const 1) "abcd") + (data (;6;) (i32.const 0) "") + (data (;7;) (i32.const 0) "abc") + (data (;8;) (i32.const 0) "") + (data (;9;) (i32.const 1) "abcd") + (data (;10;) (i32.const 0) "") + (data (;11;) (i32.const 0) "abc") + (data $d1 (;12;) (i32.const 0) "") + (data $d2 (;13;) (i32.const 1) "abcd") + (data $d3 (;14;) (i32.const 0) "") + (data $d4 (;15;) (i32.const 0) "abc") + (data $d5 (;16;) (i32.const 0) "") + (data $d6 (;17;) (i32.const 1) "abcd") + (data $d7 (;18;) (i32.const 0) "") + (data $d8 (;19;) (i32.const 0) "abc") + (data $d9 (;20;) (i32.const 0) "") + (data $d10 (;21;) (i32.const 1) "abcd") + (data $d11 (;22;) (i32.const 0) "") + (data $d12 (;23;) (i32.const 0) "abc") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/1.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/1.print new file mode 100644 index 0000000000..cc1e75fe22 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/1.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/10.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/10.print new file mode 100644 index 0000000000..c7cfbb07bb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/10.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 65535) "b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/11.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/11.print new file mode 100644 index 0000000000..0d6dc72126 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/11.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 2) + (data (;0;) (i32.const 131071) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/12.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/12.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/12.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/13.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/13.print new file mode 100644 index 0000000000..bb79a2b2e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/13.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/14.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/14.print new file mode 100644 index 0000000000..70d5011af0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/14.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/15.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/15.print new file mode 100644 index 0000000000..2f4c3a8d18 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/15.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 65536) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/16.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/16.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/16.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/17.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/17.print new file mode 100644 index 0000000000..bb79a2b2e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/17.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/18.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/18.print new file mode 100644 index 0000000000..70d5011af0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/18.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/19.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/19.print new file mode 100644 index 0000000000..4e08a2a6d1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/19.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/2.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/2.print new file mode 100644 index 0000000000..481aec56e8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/2.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/20.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/20.print new file mode 100644 index 0000000000..376eeb676a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/20.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/21.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/21.print new file mode 100644 index 0000000000..18183a143f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/21.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/22.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/22.print new file mode 100644 index 0000000000..86be16f707 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/22.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/23.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/23.print new file mode 100644 index 0000000000..6cb38d0981 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/23.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 1) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/24.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/24.print new file mode 100644 index 0000000000..42df962f09 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/24.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (i32.const 1) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/3.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/3.print new file mode 100644 index 0000000000..fbef21b722 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/3.print @@ -0,0 +1,8 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 3) "b") + (data (;2;) (i32.const 100) "cde") + (data (;3;) (i32.const 5) "x") + (data (;4;) (i32.const 3) "c") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/4.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/4.print new file mode 100644 index 0000000000..bb6a67d9e3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/4.print @@ -0,0 +1,9 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 1) "b") + (data (;2;) (i32.const 2) "cde") + (data (;3;) (i32.const 3) "f") + (data (;4;) (i32.const 2) "g") + (data (;5;) (i32.const 1) "h") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/5.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/5.print new file mode 100644 index 0000000000..ee7a8e6fe9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/5.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/6.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/6.print new file mode 100644 index 0000000000..55a464f093 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/6.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/7.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/7.print new file mode 100644 index 0000000000..cc48f688bf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/7.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/8.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/8.print new file mode 100644 index 0000000000..9baa7ce142 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/8.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/data.wast/9.print b/tests/snapshots/testsuite/proposals/function-references/data.wast/9.print new file mode 100644 index 0000000000..0474fc6565 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/data.wast/9.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 65535) "b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/0.print new file mode 100644 index 0000000000..f5b37aa021 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/0.print @@ -0,0 +1,67 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func $g (;1;) (type 0)) + (table $t (;0;) 10 funcref) + (elem (;0;) funcref) + (elem (;1;) funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem (;2;) func) + (elem (;3;) func $f $f $g $g) + (elem $p1 (;4;) funcref) + (elem $p2 (;5;) funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $p3 (;6;) func) + (elem $p4 (;7;) func $f $f $g $g) + (elem (;8;) (i32.const 0) funcref) + (elem (;9;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;10;) (i32.const 0) func) + (elem (;11;) (i32.const 0) func $f $g) + (elem (;12;) (i32.const 0) funcref) + (elem (;13;) (i32.const 0) func $f $g) + (elem (;14;) (i32.const 0) func) + (elem (;15;) (i32.const 0) func $f $f) + (elem (;16;) (i32.const 0) func) + (elem (;17;) (i32.const 0) func $f $f) + (elem (;18;) (i32.const 0) func) + (elem (;19;) (i32.const 0) func $f $f) + (elem (;20;) (i32.const 0) func) + (elem (;21;) (i32.const 0) func $f $f) + (elem (;22;) (i32.const 0) func) + (elem (;23;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;24;) (i32.const 0) func $f $f) + (elem (;25;) (i32.const 0) func $f $f) + (elem (;26;) (i32.const 0) func) + (elem (;27;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (;28;) (i32.const 0) func $f $f) + (elem (;29;) (i32.const 0) func $f $f) + (elem (;30;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a1 (;31;) (i32.const 0) funcref) + (elem $a2 (;32;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a3 (;33;) (i32.const 0) func) + (elem $a4 (;34;) (i32.const 0) func $f $g) + (elem $a9 (;35;) (i32.const 0) funcref) + (elem $a10 (;36;) (i32.const 0) func $f $g) + (elem $a11 (;37;) (i32.const 0) func) + (elem $a12 (;38;) (i32.const 0) func $f $f) + (elem $a13 (;39;) (i32.const 0) func) + (elem $a14 (;40;) (i32.const 0) func $f $f) + (elem $a15 (;41;) (i32.const 0) func) + (elem $a16 (;42;) (i32.const 0) func $f $f) + (elem $a17 (;43;) (i32.const 0) func) + (elem $a18 (;44;) (i32.const 0) func $f $f) + (elem $a19 (;45;) (i32.const 0) func) + (elem $a20 (;46;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a21 (;47;) (i32.const 0) func $f $f) + (elem $a22 (;48;) (i32.const 0) func $f $f) + (elem $a23 (;49;) (i32.const 0) func) + (elem $a24 (;50;) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem $a25 (;51;) (i32.const 0) func $f $f) + (elem $a26 (;52;) (i32.const 0) func $f $f) + (elem (;53;) declare funcref) + (elem (;54;) declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem (;55;) declare func) + (elem (;56;) declare func $f $f $g $g) + (elem $d1 (;57;) declare funcref) + (elem $d2 (;58;) declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $d3 (;59;) declare func) + (elem $d4 (;60;) declare func $f $f $g $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/1.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/1.print new file mode 100644 index 0000000000..609acc4a8d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/1.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func $g (;1;) (type 0)) + (table $t (;0;) 3 3 funcref) + (elem (;0;) (i32.const 0) funcref (ref.func $f) (ref.null func) (ref.func $g)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/12.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/12.print new file mode 100644 index 0000000000..c20a98422b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/12.print @@ -0,0 +1,22 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 11 funcref) + (export "call-7" (func 2)) + (export "call-9" (func 3)) + (elem (;0;) (i32.const 6) funcref (ref.null func) (ref.func $const-i32-a)) + (elem (;1;) (i32.const 9) funcref (ref.func $const-i32-b) (ref.null func)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/15.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/15.print new file mode 100644 index 0000000000..59834e5a95 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/15.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/16.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/16.print new file mode 100644 index 0000000000..6e685d7bc7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/16.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/17.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/17.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/17.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/18.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/18.print new file mode 100644 index 0000000000..b890117b79 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/18.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/19.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/19.print new file mode 100644 index 0000000000..6dd5628226 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/19.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/2.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/2.print new file mode 100644 index 0000000000..75850d882c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/2.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func $g (;1;) (type 0)) + (table $t (;0;) 10 (ref func) ref.func $f) + (elem (;0;) (i32.const 3) func $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/20.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/20.print new file mode 100644 index 0000000000..9cdf4a4535 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/20.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 20 funcref) + (elem (;0;) (i32.const 20) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/21.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/21.print new file mode 100644 index 0000000000..fdbf02b70d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/21.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/22.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/22.print new file mode 100644 index 0000000000..9a7e48cac6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/22.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 100 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/23.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/23.print new file mode 100644 index 0000000000..8e7e87eeea --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/23.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 1) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/24.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/24.print new file mode 100644 index 0000000000..8e00e00fe9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/24.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 0 30 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 1) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/3.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/3.print new file mode 100644 index 0000000000..2da39bb2cc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/3.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/37.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/37.print new file mode 100644 index 0000000000..f553de715e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/37.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func (;1;) (type 0) + i32.const 0 + i32.const 0 + i32.const 1 + table.init $e + ) + (table (;0;) 10 funcref) + (export "init" (func 1)) + (elem $e (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/39.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/39.print new file mode 100644 index 0000000000..0a8dfffa28 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/39.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (func (;1;) (type 0) + i32.const 0 + i32.const 0 + i32.const 1 + table.init $e + ) + (table (;0;) 10 funcref) + (export "init" (func 1)) + (elem $e (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/4.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/4.print new file mode 100644 index 0000000000..9fbc90ac8a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/4.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/5.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/5.print new file mode 100644 index 0000000000..fdf2793aac --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/5.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 10 funcref) + (elem (;0;) (i32.const 0) func $f) + (elem (;1;) (i32.const 3) func $f) + (elem (;2;) (i32.const 7) func $f) + (elem (;3;) (i32.const 5) func $f) + (elem (;4;) (i32.const 3) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/6.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/6.print new file mode 100644 index 0000000000..2c9c937ee7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/6.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) + (elem (;1;) (i32.const 3) func $f) + (elem (;2;) (i32.const 7) func $f) + (elem (;3;) (i32.const 3) func $f) + (elem (;4;) (i32.const 5) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/62.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/62.print new file mode 100644 index 0000000000..6ad9b0b3b3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/62.print @@ -0,0 +1,17 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call-overwritten" (func 2)) + (elem (;0;) (i32.const 9) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/64.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/64.print new file mode 100644 index 0000000000..9e872c44e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/64.print @@ -0,0 +1,17 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (import "spectest" "table" (table (;0;) 10 funcref)) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (export "call-overwritten-element" (func 2)) + (elem (;0;) (i32.const 9) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/66.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/66.print new file mode 100644 index 0000000000..a7fafae05a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/66.print @@ -0,0 +1,28 @@ +(module $module1 + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 8 + call_indirect (type $out-i32) + ) + (func (;4;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "shared-table" (table 0)) + (export "call-7" (func 2)) + (export "call-8" (func 3)) + (export "call-9" (func 4)) + (elem (;0;) (i32.const 8) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/7.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/7.print new file mode 100644 index 0000000000..ba9ed82c15 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/7.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (import "spectest" "global_i32" (global (;0;) i32)) + (func $f (;0;) (type 0)) + (table (;0;) 1000 funcref) + (elem (;0;) (global.get 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/71.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/71.print new file mode 100644 index 0000000000..27cf2472b6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/71.print @@ -0,0 +1,12 @@ +(module $module2 + (type $out-i32 (;0;) (func (result i32))) + (import "module1" "shared-table" (table (;0;) 10 funcref)) + (func $const-i32-c (;0;) (type $out-i32) (result i32) + i32.const 67 + ) + (func $const-i32-d (;1;) (type $out-i32) (result i32) + i32.const 68 + ) + (elem (;0;) (i32.const 7) func $const-i32-c) + (elem (;1;) (i32.const 8) func $const-i32-d) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/75.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/75.print new file mode 100644 index 0000000000..e0ef8f741b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/75.print @@ -0,0 +1,12 @@ +(module $module3 + (type $out-i32 (;0;) (func (result i32))) + (import "module1" "shared-table" (table (;0;) 10 funcref)) + (func $const-i32-e (;0;) (type $out-i32) (result i32) + i32.const 69 + ) + (func $const-i32-f (;1;) (type $out-i32) (result i32) + i32.const 70 + ) + (elem (;0;) (i32.const 8) func $const-i32-e) + (elem (;1;) (i32.const 9) func $const-i32-f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/8.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/8.print new file mode 100644 index 0000000000..83d7347f17 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/8.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (import "spectest" "global_i32" (global $g (;0;) i32)) + (func $f (;0;) (type 0)) + (table (;0;) 1000 funcref) + (elem (;0;) (global.get $g) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/83.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/83.print new file mode 100644 index 0000000000..b1267707e4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/83.print @@ -0,0 +1,17 @@ +(module $m + (type (;0;) (func (param i32) (result externref))) + (type (;1;) (func (param i32 externref))) + (func (;0;) (type 0) (param $i i32) (result externref) + local.get $i + table.get $t + ) + (func (;1;) (type 1) (param $i i32) (param $x externref) + local.get $i + local.get $x + table.set $t + ) + (table $t (;0;) 2 externref) + (export "table" (table $t)) + (export "get" (func 0)) + (export "set" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/9.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/9.print new file mode 100644 index 0000000000..6bb8d5e65f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/9.print @@ -0,0 +1,22 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (func $const-i32-a (;0;) (type $out-i32) (result i32) + i32.const 65 + ) + (func $const-i32-b (;1;) (type $out-i32) (result i32) + i32.const 66 + ) + (func (;2;) (type $out-i32) (result i32) + i32.const 7 + call_indirect (type $out-i32) + ) + (func (;3;) (type $out-i32) (result i32) + i32.const 9 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call-7" (func 2)) + (export "call-9" (func 3)) + (elem (;0;) (i32.const 7) func $const-i32-a) + (elem (;1;) (i32.const 9) func $const-i32-b) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/91.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/91.print new file mode 100644 index 0000000000..c6a336d99d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/91.print @@ -0,0 +1,4 @@ +(module + (import "exporter" "table" (table $t (;0;) 2 externref)) + (elem (;0;) (i32.const 0) externref (ref.null extern)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/94.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/94.print new file mode 100644 index 0000000000..d2623e77ab --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/94.print @@ -0,0 +1,8 @@ +(module $module4 + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 42 + ) + (global (;0;) funcref ref.func 0) + (export "f" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/elem.wast/96.print b/tests/snapshots/testsuite/proposals/function-references/elem.wast/96.print new file mode 100644 index 0000000000..bd279c1b29 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/elem.wast/96.print @@ -0,0 +1,11 @@ +(module + (type $out-i32 (;0;) (func (result i32))) + (import "module4" "f" (global (;0;) funcref)) + (func (;0;) (type $out-i32) (result i32) + i32.const 0 + call_indirect (type $out-i32) + ) + (table (;0;) 10 funcref) + (export "call_imported_elem" (func 0)) + (elem (;0;) (i32.const 0) funcref (global.get 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/func.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/func.wast/0.print new file mode 100644 index 0000000000..e05dc5fd34 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/func.wast/0.print @@ -0,0 +1,505 @@ +(module + (type $sig (;0;) (func)) + (type $sig-1 (;1;) (func)) + (type $sig-2 (;2;) (func (result i32))) + (type $sig-3 (;3;) (func (param i32))) + (type $sig-4 (;4;) (func (param i32 f64 i32) (result i32))) + (type $forward (;5;) (func)) + (type (;6;) (func (param i32 f64 i64))) + (type (;7;) (func (param i32 f64))) + (type (;8;) (func (param i32 f32 i64 i32 f64))) + (type (;9;) (func (result i32 f64 f32))) + (type (;10;) (func (result i32 f64))) + (type (;11;) (func (result i32 f32 i64 i32 f64))) + (type (;12;) (func (param i32 f32 i64 i32) (result i32 i64 i32))) + (type (;13;) (func (result i64))) + (type (;14;) (func (result f32))) + (type (;15;) (func (result f64))) + (type (;16;) (func (param i32 i32) (result i32))) + (type (;17;) (func (param i64 i64) (result i64))) + (type (;18;) (func (param f32 f32) (result f32))) + (type (;19;) (func (param f64 f64) (result f64))) + (type (;20;) (func (param f32 i32 i64 i32 f64 i32) (result f64))) + (type (;21;) (func (result i32 i32 i32))) + (type (;22;) (func (result i32 i64))) + (type (;23;) (func (param i32) (result i32))) + (type (;24;) (func (param i32) (result i32 i64))) + (type (;25;) (func (param i32) (result f32 i64))) + (type (;26;) (func (param i32) (result i32 i32))) + (type (;27;) (func (result i32 i32))) + (type (;28;) (func (param i32 i64 f32 f32 i32 f64 f32 i32 i32 i32 f32 f64 f64 f64 i32 i32 f32) (result f64 f32 i32 i32 i32 i64 f32 i32 i32 f32 f64 f64 i32 f32 i32 f64))) + (func $dummy (;0;) (type $sig)) + (func (;1;) (type $sig)) + (func (;2;) (type $sig)) + (func $f (;3;) (type $sig)) + (func $h (;4;) (type $sig)) + (func (;5;) (type $sig)) + (func (;6;) (type $sig)) + (func (;7;) (type $sig) + (local i32) + ) + (func (;8;) (type $sig) + (local $x i32) + ) + (func (;9;) (type $sig) + (local i32 f64 i64) + ) + (func (;10;) (type $sig) + (local i32 f64) + ) + (func (;11;) (type $sig) + (local i32 f32) (local $x i64) (local i32 f64) + ) + (func (;12;) (type $sig)) + (func (;13;) (type $sig)) + (func (;14;) (type $sig-3) (param i32)) + (func (;15;) (type $sig-3) (param $x i32)) + (func (;16;) (type 6) (param i32 f64 i64)) + (func (;17;) (type 7) (param i32 f64)) + (func (;18;) (type 8) (param i32 f32) (param $x i64) (param i32 f64)) + (func (;19;) (type $sig)) + (func (;20;) (type $sig)) + (func (;21;) (type $sig-2) (result i32) + unreachable + ) + (func (;22;) (type 9) (result i32 f64 f32) + unreachable + ) + (func (;23;) (type 10) (result i32 f64) + unreachable + ) + (func (;24;) (type 11) (result i32 f32 i64 i32 f64) + unreachable + ) + (func (;25;) (type $sig-1)) + (func (;26;) (type $sig-2) (result i32) + i32.const 0 + ) + (func (;27;) (type $sig-3) (param i32)) + (func (;28;) (type $sig-4) (param i32 f64 i32) (result i32) + i32.const 0 + ) + (func (;29;) (type $sig-2) (result i32) + i32.const 0 + ) + (func (;30;) (type $sig-3) (param i32)) + (func (;31;) (type $sig-4) (param i32 f64 i32) (result i32) + i32.const 0 + ) + (func (;32;) (type $sig)) + (func (;33;) (type $forward)) + (func $complex (;34;) (type 12) (param i32 f32) (param $x i64) (param i32) (result i32 i64 i32) + (local f32) (local $y i32) (local i64 i32 f64 i32) + unreachable + unreachable + ) + (func $complex-sig (;35;) (type $sig) + (local f32) (local $y i32) (local i64 i32 f64 i32) + unreachable + unreachable + ) + (func (;36;) (type $sig-2) (result i32) + (local i32 i32) + local.get 0 + ) + (func (;37;) (type 13) (result i64) + (local i64 i64) + local.get 0 + ) + (func (;38;) (type 14) (result f32) + (local f32 f32) + local.get 0 + ) + (func (;39;) (type 15) (result f64) + (local f64 f64) + local.get 0 + ) + (func (;40;) (type $sig-2) (result i32) + (local i32 i32) + local.get 1 + ) + (func (;41;) (type 13) (result i64) + (local i64 i64) + local.get 1 + ) + (func (;42;) (type 14) (result f32) + (local f32 f32) + local.get 1 + ) + (func (;43;) (type 15) (result f64) + (local f64 f64) + local.get 1 + ) + (func (;44;) (type 15) (result f64) + (local f32) (local $x i32) (local i64 i32 f64 i32) + local.get 0 + f32.neg + drop + local.get $x + i32.eqz + drop + local.get 2 + i64.eqz + drop + local.get 3 + i32.eqz + drop + local.get 4 + f64.neg + drop + local.get 5 + i32.eqz + drop + local.get 4 + ) + (func (;45;) (type 16) (param i32 i32) (result i32) + local.get 0 + ) + (func (;46;) (type 17) (param i64 i64) (result i64) + local.get 0 + ) + (func (;47;) (type 18) (param f32 f32) (result f32) + local.get 0 + ) + (func (;48;) (type 19) (param f64 f64) (result f64) + local.get 0 + ) + (func (;49;) (type 16) (param i32 i32) (result i32) + local.get 1 + ) + (func (;50;) (type 17) (param i64 i64) (result i64) + local.get 1 + ) + (func (;51;) (type 18) (param f32 f32) (result f32) + local.get 1 + ) + (func (;52;) (type 19) (param f64 f64) (result f64) + local.get 1 + ) + (func (;53;) (type 20) (param f32 i32) (param $x i64) (param i32 f64 i32) (result f64) + local.get 0 + f32.neg + drop + local.get 1 + i32.eqz + drop + local.get $x + i64.eqz + drop + local.get 3 + i32.eqz + drop + local.get 4 + f64.neg + drop + local.get 5 + i32.eqz + drop + local.get 4 + ) + (func (;54;) (type $sig)) + (func (;55;) (type $sig) + call $dummy + ) + (func (;56;) (type $sig-2) (result i32) + i32.const 77 + ) + (func (;57;) (type 13) (result i64) + i64.const 7777 + ) + (func (;58;) (type 14) (result f32) + f32.const 0x1.36ccccp+6 (;=77.7;) + ) + (func (;59;) (type 15) (result f64) + f64.const 0x1.37147ae147ae1p+6 (;=77.77;) + ) + (func (;60;) (type 10) (result i32 f64) + i32.const 77 + f64.const 0x1.cp+2 (;=7;) + ) + (func (;61;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + ) + (func (;62;) (type $sig) + block ;; label = @1 + call $dummy + call $dummy + end + ) + (func (;63;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + ) + (func (;64;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + ) + (func (;65;) (type $sig) + return + ) + (func (;66;) (type $sig-2) (result i32) + i32.const 78 + return + ) + (func (;67;) (type 13) (result i64) + i64.const 7878 + return + ) + (func (;68;) (type 14) (result f32) + f32.const 0x1.3accccp+6 (;=78.7;) + return + ) + (func (;69;) (type 15) (result f64) + f64.const 0x1.3b1eb851eb852p+6 (;=78.78;) + return + ) + (func (;70;) (type 10) (result i32 f64) + i32.const 78 + f64.const 0x1.3b1eb851eb852p+6 (;=78.78;) + return + ) + (func (;71;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + return + ) + (func (;72;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + return + ) + (func (;73;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + return + ) + (func (;74;) (type $sig) + br 0 (;@0;) + ) + (func (;75;) (type $sig-2) (result i32) + i32.const 79 + br 0 (;@0;) + ) + (func (;76;) (type 13) (result i64) + i64.const 7979 + br 0 (;@0;) + ) + (func (;77;) (type 14) (result f32) + f32.const 0x1.3f999ap+6 (;=79.9;) + br 0 (;@0;) + ) + (func (;78;) (type 15) (result f64) + f64.const 0x1.3f28f5c28f5c3p+6 (;=79.79;) + br 0 (;@0;) + ) + (func (;79;) (type 10) (result i32 f64) + i32.const 79 + f64.const 0x1.3f28f5c28f5c3p+6 (;=79.79;) + br 0 (;@0;) + ) + (func (;80;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + br 0 (;@0;) + ) + (func (;81;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + br 0 (;@0;) + ) + (func (;82;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + br 0 (;@0;) + ) + (func (;83;) (type $sig-3) (param i32) + local.get 0 + br_if 0 (;@0;) + ) + (func (;84;) (type 23) (param i32) (result i32) + i32.const 50 + local.get 0 + br_if 0 (;@0;) + drop + i32.const 51 + ) + (func (;85;) (type 24) (param i32) (result i32 i64) + i32.const 50 + i64.const 51 + local.get 0 + br_if 0 (;@0;) + drop + drop + i32.const 51 + i64.const 52 + ) + (func (;86;) (type $sig-3) (param i32) + local.get 0 + br_table 0 (;@0;) 0 (;@0;) 0 (;@0;) + ) + (func (;87;) (type 23) (param i32) (result i32) + i32.const 50 + local.get 0 + br_table 0 (;@0;) 0 (;@0;) + i32.const 51 + ) + (func (;88;) (type 25) (param i32) (result f32 i64) + f32.const 0x1.9p+5 (;=50;) + i64.const 51 + local.get 0 + br_table 0 (;@0;) 0 (;@0;) + f32.const 0x1.98p+5 (;=51;) + i64.const 52 + ) + (func (;89;) (type $sig-3) (param i32) + block ;; label = @1 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + end + ) + (func (;90;) (type 23) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 50 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + i32.const 51 + end + i32.const 2 + i32.add + ) + (func (;91;) (type 26) (param i32) (result i32 i32) + block (type 27) (result i32 i32) ;; label = @1 + i32.const 50 + i32.const 51 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + i32.const 51 + i32.const -3 + end + i32.add + i32.const 52 + ) + (func (;92;) (type 28) (param i32 i64 f32 f32 i32 f64 f32 i32 i32 i32 f32 f64 f64 f64 i32 i32 f32) (result f64 f32 i32 i32 i32 i64 f32 i32 i32 f32 f64 f64 i32 f32 i32 f64) + local.get 5 + local.get 2 + local.get 0 + local.get 8 + local.get 7 + local.get 1 + local.get 3 + local.get 9 + local.get 4 + local.get 6 + local.get 13 + local.get 11 + local.get 15 + local.get 16 + local.get 14 + local.get 12 + ) + (func (;93;) (type $sig-2) (result i32) + (local i32) + local.get 0 + ) + (func (;94;) (type 13) (result i64) + (local i64) + local.get 0 + ) + (func (;95;) (type 14) (result f32) + (local f32) + local.get 0 + ) + (func (;96;) (type 15) (result f64) + (local f64) + local.get 0 + ) + (export "f" (func 2)) + (export "g" (func $h)) + (export "type-use-1" (func 25)) + (export "type-use-2" (func 26)) + (export "type-use-3" (func 27)) + (export "type-use-4" (func 28)) + (export "type-use-5" (func 29)) + (export "type-use-6" (func 30)) + (export "type-use-7" (func 31)) + (export "local-first-i32" (func 36)) + (export "local-first-i64" (func 37)) + (export "local-first-f32" (func 38)) + (export "local-first-f64" (func 39)) + (export "local-second-i32" (func 40)) + (export "local-second-i64" (func 41)) + (export "local-second-f32" (func 42)) + (export "local-second-f64" (func 43)) + (export "local-mixed" (func 44)) + (export "param-first-i32" (func 45)) + (export "param-first-i64" (func 46)) + (export "param-first-f32" (func 47)) + (export "param-first-f64" (func 48)) + (export "param-second-i32" (func 49)) + (export "param-second-i64" (func 50)) + (export "param-second-f32" (func 51)) + (export "param-second-f64" (func 52)) + (export "param-mixed" (func 53)) + (export "empty" (func 54)) + (export "value-void" (func 55)) + (export "value-i32" (func 56)) + (export "value-i64" (func 57)) + (export "value-f32" (func 58)) + (export "value-f64" (func 59)) + (export "value-i32-f64" (func 60)) + (export "value-i32-i32-i32" (func 61)) + (export "value-block-void" (func 62)) + (export "value-block-i32" (func 63)) + (export "value-block-i32-i64" (func 64)) + (export "return-empty" (func 65)) + (export "return-i32" (func 66)) + (export "return-i64" (func 67)) + (export "return-f32" (func 68)) + (export "return-f64" (func 69)) + (export "return-i32-f64" (func 70)) + (export "return-i32-i32-i32" (func 71)) + (export "return-block-i32" (func 72)) + (export "return-block-i32-i64" (func 73)) + (export "break-empty" (func 74)) + (export "break-i32" (func 75)) + (export "break-i64" (func 76)) + (export "break-f32" (func 77)) + (export "break-f64" (func 78)) + (export "break-i32-f64" (func 79)) + (export "break-i32-i32-i32" (func 80)) + (export "break-block-i32" (func 81)) + (export "break-block-i32-i64" (func 82)) + (export "break-br_if-empty" (func 83)) + (export "break-br_if-num" (func 84)) + (export "break-br_if-num-num" (func 85)) + (export "break-br_table-empty" (func 86)) + (export "break-br_table-num" (func 87)) + (export "break-br_table-num-num" (func 88)) + (export "break-br_table-nested-empty" (func 89)) + (export "break-br_table-nested-num" (func 90)) + (export "break-br_table-nested-num-num" (func 91)) + (export "large-sig" (func 92)) + (export "init-local-i32" (func 93)) + (export "init-local-i64" (func 94)) + (export "init-local-f32" (func 95)) + (export "init-local-f64" (func 96)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/func.wast/90.print b/tests/snapshots/testsuite/proposals/function-references/func.wast/90.print new file mode 100644 index 0000000000..73664e0df9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/func.wast/90.print @@ -0,0 +1,19 @@ +(module + (type $t (;0;) (func (param i32))) + (type (;1;) (func (result f64))) + (type (;2;) (func)) + (func $f (;0;) (type 1) (result f64) + f64.const 0x0p+0 (;=0;) + ) + (func $g (;1;) (type $t) (param i32)) + (func $i32->void (;2;) (type $t) (param i32)) + (func $void->f64 (;3;) (type 1) (result f64) + f64.const 0x0p+0 (;=0;) + ) + (func $check (;4;) (type 2) + i32.const 0 + call $i32->void + call $void->f64 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/func.wast/93.print b/tests/snapshots/testsuite/proposals/function-references/func.wast/93.print new file mode 100644 index 0000000000..7748f47f12 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/func.wast/93.print @@ -0,0 +1,25 @@ +(module + (type $proc (;0;) (func (result i32))) + (type $sig (;1;) (func (param i32) (result i32))) + (func (;0;) (type $sig) (param $var i32) (result i32) + (local i32) + local.get 1 + ) + (func $g (;1;) (type $sig) (param $var i32) (result i32) + (local i32) + local.get 1 + ) + (func (;2;) (type $sig) (param i32) (result i32) + local.get 0 + call $g + ) + (func (;3;) (type $proc) (result i32) + (local $var i32) + i32.const 42 + local.set $var + local.get $var + ) + (export "f" (func 0)) + (export "g" (func 2)) + (export "p" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/func.wast/97.print b/tests/snapshots/testsuite/proposals/function-references/func.wast/97.print new file mode 100644 index 0000000000..78856df296 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/func.wast/97.print @@ -0,0 +1,83 @@ +(module + (type $sig (;0;) (func)) + (type $empty-sig-duplicate (;1;) (func)) + (type $complex-sig-duplicate (;2;) (func (param i64 i64 f64 i64 f64 i64 f32 i32))) + (type (;3;) (func (param f64 i64 f64 i64 f64 i64 f32 i32))) + (func $empty-sig-1 (;0;) (type $sig)) + (func $complex-sig-1 (;1;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $empty-sig-2 (;2;) (type $sig)) + (func $complex-sig-2 (;3;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-3 (;4;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-4 (;5;) (type $complex-sig-duplicate) (param i64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-5 (;6;) (type $complex-sig-duplicate) (param i64 i64 f64 i64 f64 i64 f32 i32)) + (func (;7;) (type $sig) + i32.const 1 + call_indirect (type $sig) + i32.const 4 + call_indirect (type $sig) + ) + (func (;8;) (type $sig) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 0 + call_indirect (type 3) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 2 + call_indirect (type 3) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 3 + call_indirect (type 3) + ) + (func (;9;) (type $sig) + i32.const 1 + call_indirect (type $empty-sig-duplicate) + ) + (func (;10;) (type $sig) + i64.const 0 + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 5 + call_indirect (type $complex-sig-duplicate) + i64.const 0 + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 6 + call_indirect (type $complex-sig-duplicate) + ) + (table (;0;) 7 7 funcref) + (export "signature-explicit-reused" (func 7)) + (export "signature-implicit-reused" (func 8)) + (export "signature-explicit-duplicate" (func 9)) + (export "signature-implicit-duplicate" (func 10)) + (elem (;0;) (i32.const 0) func $complex-sig-3 $empty-sig-2 $complex-sig-1 $complex-sig-3 $empty-sig-1 $complex-sig-4 $complex-sig-5) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/global.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/global.wast/0.print new file mode 100644 index 0000000000..bea06e9abd --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/global.wast/0.print @@ -0,0 +1,328 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (result i64))) + (type (;3;) (func (result externref))) + (type (;4;) (func (param i32))) + (type (;5;) (func (param i64))) + (type (;6;) (func (param externref))) + (type (;7;) (func (result f32))) + (type (;8;) (func (result f64))) + (type (;9;) (func (param f32))) + (type (;10;) (func (param f64))) + (type (;11;) (func)) + (type (;12;) (func (param i32) (result i32))) + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "global_i64" (global (;1;) i64)) + (func (;0;) (type 1) (result i32) + global.get $a + ) + (func (;1;) (type 2) (result i64) + global.get $b + ) + (func (;2;) (type 3) (result externref) + global.get $r + ) + (func (;3;) (type 3) (result externref) + global.get $mr + ) + (func (;4;) (type 1) (result i32) + global.get $x + ) + (func (;5;) (type 2) (result i64) + global.get $y + ) + (func (;6;) (type 1) (result i32) + global.get $z1 + ) + (func (;7;) (type 2) (result i64) + global.get $z2 + ) + (func (;8;) (type 4) (param i32) + local.get 0 + global.set $x + ) + (func (;9;) (type 5) (param i64) + local.get 0 + global.set $y + ) + (func (;10;) (type 6) (param externref) + local.get 0 + global.set $mr + ) + (func (;11;) (type 7) (result f32) + global.get 3 + ) + (func (;12;) (type 8) (result f64) + global.get 4 + ) + (func (;13;) (type 7) (result f32) + global.get 7 + ) + (func (;14;) (type 8) (result f64) + global.get 8 + ) + (func (;15;) (type 9) (param f32) + local.get 0 + global.set 7 + ) + (func (;16;) (type 10) (param f64) + local.get 0 + global.set 8 + ) + (func $dummy (;17;) (type 11)) + (func (;18;) (type 1) (result i32) + global.get $x + i32.const 2 + i32.const 3 + select + ) + (func (;19;) (type 1) (result i32) + i32.const 2 + global.get $x + i32.const 3 + select + ) + (func (;20;) (type 1) (result i32) + i32.const 2 + i32.const 3 + global.get $x + select + ) + (func (;21;) (type 1) (result i32) + loop (result i32) ;; label = @1 + global.get $x + call $dummy + call $dummy + end + ) + (func (;22;) (type 1) (result i32) + loop (result i32) ;; label = @1 + call $dummy + global.get $x + call $dummy + end + ) + (func (;23;) (type 1) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + global.get $x + end + ) + (func (;24;) (type 1) (result i32) + global.get $x + if (result i32) ;; label = @1 + call $dummy + i32.const 2 + else + call $dummy + i32.const 3 + end + ) + (func (;25;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + global.get $x + else + i32.const 2 + end + ) + (func (;26;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 2 + else + global.get $x + end + ) + (func (;27;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;28;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;29;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;30;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;31;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;32;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;33;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + global.get $x + i32.const 0 + call_indirect (type $check) + end + ) + (func (;34;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + global.get $x + call_indirect (type $check) + end + ) + (func (;35;) (type 11) + global.get $x + i32.const 1 + i32.store + ) + (func (;36;) (type 11) + i32.const 0 + global.get $x + i32.store + ) + (func (;37;) (type 1) (result i32) + global.get $x + i32.load + ) + (func (;38;) (type 1) (result i32) + global.get $x + memory.grow + ) + (func $f (;39;) (type 12) (param i32) (result i32) + local.get 0 + ) + (func (;40;) (type 1) (result i32) + global.get $x + call $f + ) + (func (;41;) (type 1) (result i32) + global.get $x + return + ) + (func (;42;) (type 11) + global.get $x + drop + ) + (func (;43;) (type 1) (result i32) + block (result i32) ;; label = @1 + global.get $x + br 0 (;@1;) + end + ) + (func (;44;) (type 12) (param i32) (result i32) + global.get $x + local.set 0 + local.get 0 + ) + (func (;45;) (type 12) (param i32) (result i32) + global.get $x + local.tee 0 + ) + (func (;46;) (type 1) (result i32) + global.get $x + global.set $x + global.get $x + ) + (func (;47;) (type 1) (result i32) + global.get $x + i32.eqz + ) + (func (;48;) (type 1) (result i32) + global.get $x + global.get $x + i32.mul + ) + (func (;49;) (type 1) (result i32) + global.get 0 + i32.const 1 + i32.gt_u + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;2;) i32 i32.const -2) + (global (;3;) f32 f32.const -0x1.8p+1 (;=-3;)) + (global (;4;) f64 f64.const -0x1p+2 (;=-4;)) + (global $b (;5;) i64 i64.const -5) + (global $x (;6;) (mut i32) i32.const -12) + (global (;7;) (mut f32) f32.const -0x1.ap+3 (;=-13;)) + (global (;8;) (mut f64) f64.const -0x1.cp+3 (;=-14;)) + (global $y (;9;) (mut i64) i64.const -15) + (global $z1 (;10;) i32 global.get 0) + (global $z2 (;11;) i64 global.get 1) + (global $r (;12;) externref ref.null extern) + (global $mr (;13;) (mut externref) ref.null extern) + (global (;14;) funcref ref.null func) + (export "get-a" (func 0)) + (export "get-b" (func 1)) + (export "get-r" (func 2)) + (export "get-mr" (func 3)) + (export "get-x" (func 4)) + (export "get-y" (func 5)) + (export "get-z1" (func 6)) + (export "get-z2" (func 7)) + (export "set-x" (func 8)) + (export "set-y" (func 9)) + (export "set-mr" (func 10)) + (export "get-3" (func 11)) + (export "get-4" (func 12)) + (export "get-7" (func 13)) + (export "get-8" (func 14)) + (export "set-7" (func 15)) + (export "set-8" (func 16)) + (export "as-select-first" (func 18)) + (export "as-select-mid" (func 19)) + (export "as-select-last" (func 20)) + (export "as-loop-first" (func 21)) + (export "as-loop-mid" (func 22)) + (export "as-loop-last" (func 23)) + (export "as-if-condition" (func 24)) + (export "as-if-then" (func 25)) + (export "as-if-else" (func 26)) + (export "as-br_if-first" (func 27)) + (export "as-br_if-last" (func 28)) + (export "as-br_table-first" (func 29)) + (export "as-br_table-last" (func 30)) + (export "as-call_indirect-first" (func 32)) + (export "as-call_indirect-mid" (func 33)) + (export "as-call_indirect-last" (func 34)) + (export "as-store-first" (func 35)) + (export "as-store-last" (func 36)) + (export "as-load-operand" (func 37)) + (export "as-memory.grow-value" (func 38)) + (export "as-call-value" (func 40)) + (export "as-return-value" (func 41)) + (export "as-drop-operand" (func 42)) + (export "as-br-value" (func 43)) + (export "as-local.set-value" (func 44)) + (export "as-local.tee-value" (func 45)) + (export "as-global.set-value" (func 46)) + (export "as-unary-operand" (func 47)) + (export "as-binary-operand" (func 48)) + (export "as-compare-operand" (func 49)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/global.wast/61.print b/tests/snapshots/testsuite/proposals/function-references/global.wast/61.print new file mode 100644 index 0000000000..bb29c81054 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/global.wast/61.print @@ -0,0 +1,4 @@ +(module + (global (;0;) (mut f32) f32.const 0x0p+0 (;=0;)) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/global.wast/62.print b/tests/snapshots/testsuite/proposals/function-references/global.wast/62.print new file mode 100644 index 0000000000..bb29c81054 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/global.wast/62.print @@ -0,0 +1,4 @@ +(module + (global (;0;) (mut f32) f32.const 0x0p+0 (;=0;)) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/global.wast/79.print b/tests/snapshots/testsuite/proposals/function-references/global.wast/79.print new file mode 100644 index 0000000000..ca7594713b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/global.wast/79.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/global.wast/82.print b/tests/snapshots/testsuite/proposals/function-references/global.wast/82.print new file mode 100644 index 0000000000..e6b79c4e23 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/global.wast/82.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/if.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/if.wast/0.print new file mode 100644 index 0000000000..148a4b8282 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/if.wast/0.print @@ -0,0 +1,918 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type $block-sig-1 (;1;) (func)) + (type $block-sig-2 (;2;) (func (result i32))) + (type $block-sig-3 (;3;) (func (param i32))) + (type $block-sig-4 (;4;) (func (param i32 f64 i32) (result i32 f64 i32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i32) (result i32 i32))) + (type (;7;) (func (result i32 i64 i32))) + (type (;8;) (func (result i32 i32))) + (type (;9;) (func (result f32 f32))) + (type (;10;) (func (param i32) (result i32 i32 i64))) + (type (;11;) (func (result i32 i32 i64))) + (type (;12;) (func (param i32 i32) (result i32 i32))) + (type (;13;) (func (param i64 i64 i32) (result i64 i32))) + (type (;14;) (func (param i64 i64) (result i64))) + (type (;15;) (func (param i64) (result i64))) + (func $dummy (;0;) (type $block-sig-1)) + (func (;1;) (type $block-sig-3) (param i32) + local.get 0 + if ;; label = @1 + end + local.get 0 + if ;; label = @1 + else + end + local.get 0 + if $l ;; label = @1 + end + local.get 0 + if $l ;; label = @1 + else + end + ) + (func (;2;) (type 5) (param i32) (result i32) + local.get 0 + if ;; label = @1 + nop + end + local.get 0 + if ;; label = @1 + nop + else + nop + end + local.get 0 + if (result i32) ;; label = @1 + i32.const 7 + else + i32.const 8 + end + ) + (func (;3;) (type 6) (param i32) (result i32 i32) + local.get 0 + if ;; label = @1 + call $dummy + call $dummy + call $dummy + end + local.get 0 + if ;; label = @1 + else + call $dummy + call $dummy + call $dummy + end + local.get 0 + if (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 8 + call $dummy + else + call $dummy + call $dummy + i32.const 9 + call $dummy + end + local.get 0 + if (type 7) (result i32 i64 i32) ;; label = @1 + call $dummy + call $dummy + i32.const 1 + call $dummy + call $dummy + call $dummy + i64.const 2 + call $dummy + call $dummy + call $dummy + i32.const 3 + call $dummy + else + call $dummy + call $dummy + i32.const -1 + call $dummy + call $dummy + call $dummy + i64.const -2 + call $dummy + call $dummy + call $dummy + i32.const -3 + call $dummy + end + drop + drop + ) + (func (;4;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 1 + if ;; label = @2 + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if ;; label = @2 + else + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if (result i32) ;; label = @2 + call $dummy + i32.const 9 + else + call $dummy + i32.const 10 + end + else + local.get 1 + if ;; label = @2 + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if ;; label = @2 + else + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if (result i32) ;; label = @2 + call $dummy + i32.const 10 + else + call $dummy + i32.const 11 + end + end + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.const 3 + select + ) + (func (;6;) (type 5) (param i32) (result i32) + i32.const 2 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 3 + select + ) + (func (;7;) (type 5) (param i32) (result i32) + i32.const 2 + i32.const 3 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + select + ) + (func (;8;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call $dummy + call $dummy + end + ) + (func (;9;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call $dummy + end + ) + (func (;10;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + end + ) + (func (;11;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + if (result i32) ;; label = @1 + call $dummy + i32.const 2 + else + call $dummy + i32.const 3 + end + ) + (func (;12;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;13;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;14;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;15;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;16;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;17;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;18;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 0 + call_indirect (type $check) + end + ) + (func (;19;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call_indirect (type $check) + end + ) + (func (;20;) (type $block-sig-3) (param i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.store + ) + (func (;21;) (type $block-sig-3) (param i32) + i32.const 2 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.store + ) + (func (;22;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + memory.grow + ) + (func $f (;23;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;24;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + call $f + ) + (func (;25;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + return + ) + (func (;26;) (type $block-sig-3) (param i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + drop + ) + (func (;27;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + i32.const 1 + else + i32.const 0 + end + br 0 (;@1;) + end + ) + (func (;28;) (type 5) (param i32) (result i32) + (local i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + local.set 0 + local.get 0 + ) + (func (;29;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + local.tee 0 + ) + (func (;30;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + global.set $a + global.get $a + ) + (func (;31;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 11 + else + i32.const 10 + end + i32.load + ) + (func (;32;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 13 + else + call $dummy + i32.const -13 + end + i32.ctz + ) + (func (;33;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 3 + else + call $dummy + i32.const -3 + end + local.get 1 + if (result i32) ;; label = @1 + call $dummy + i32.const 4 + else + call $dummy + i32.const -5 + end + i32.mul + ) + (func (;34;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 13 + else + call $dummy + i32.const 0 + end + i32.eqz + ) + (func (;35;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + else + call $dummy + f32.const -0x1.8p+1 (;=-3;) + end + local.get 1 + if (result f32) ;; label = @1 + call $dummy + f32.const 0x1p+2 (;=4;) + else + call $dummy + f32.const -0x1p+2 (;=-4;) + end + f32.gt + ) + (func (;36;) (type 5) (param i32) (result i32) + local.get 0 + if (type 8) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + else + call $dummy + i32.const 3 + call $dummy + i32.const -4 + end + i32.mul + ) + (func (;37;) (type 5) (param i32) (result i32) + local.get 0 + if (type 9) (result f32 f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + call $dummy + f32.const 0x1.8p+1 (;=3;) + else + call $dummy + f32.const -0x1p+1 (;=-2;) + call $dummy + f32.const -0x1.8p+1 (;=-3;) + end + f32.gt + ) + (func (;38;) (type 5) (param i32) (result i32) + local.get 0 + if (type 8) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + else + call $dummy + i32.const -3 + call $dummy + i32.const -4 + end + i32.const 5 + i32.add + i32.mul + ) + (func (;39;) (type $block-sig-2) (result i32) + i32.const 1 + if ;; label = @1 + br 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + br 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + br 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 1 + br_if 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 1 + br_if 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + i32.const 1 + br_if 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + i32.const 0 + br_table 0 (;@1;) + unreachable + end + i32.const 19 + ) + (func (;40;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 18 + br 0 (;@1;) + i32.const 19 + else + i32.const 21 + br 0 (;@1;) + i32.const 20 + end + ) + (func (;41;) (type 10) (param i32) (result i32 i32 i64) + local.get 0 + if (type 11) (result i32 i32 i64) ;; label = @1 + i32.const 18 + i32.const -18 + i64.const 18 + br 0 (;@1;) + i32.const 19 + i32.const -19 + i64.const 19 + else + i32.const -18 + i32.const 18 + i64.const -18 + br 0 (;@1;) + i32.const -19 + i32.const 19 + i64.const -19 + end + ) + (func (;42;) (type 5) (param i32) (result i32) + i32.const 1 + local.get 0 + if (type 5) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + else + i32.const -2 + i32.add + end + ) + (func (;43;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + else + i32.sub + end + ) + (func (;44;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type 12) (param i32 i32) (result i32 i32) ;; label = @1 + end + i32.add + ) + (func (;45;) (type 5) (param i32) (result i32) + i32.const 1 + local.get 0 + if (type 5) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + br 0 (;@1;) + else + i32.const -2 + i32.add + br 0 (;@1;) + end + ) + (func (;46;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + br 0 (;@1;) + else + i32.sub + br 0 (;@1;) + end + ) + (func (;47;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type 12) (param i32 i32) (result i32 i32) ;; label = @1 + br 0 (;@1;) + end + i32.add + ) + (func (;48;) (type 5) (param i32) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + local.set 1 + local.get 0 + end + if ;; label = @1 + local.get 1 + i32.const 3 + i32.mul + local.set 1 + local.get 1 + i32.const 5 + i32.sub + local.set 1 + local.get 1 + i32.const 7 + i32.mul + local.set 1 + br 0 (;@1;) + local.get 1 + i32.const 100 + i32.mul + local.set 1 + else + local.get 1 + i32.const 5 + i32.mul + local.set 1 + local.get 1 + i32.const 7 + i32.sub + local.set 1 + local.get 1 + i32.const 3 + i32.mul + local.set 1 + br 0 (;@1;) + local.get 1 + i32.const 1000 + i32.mul + local.set 1 + end + local.get 1 + ) + (func $add64_u_with_carry (;49;) (type 13) (param $i i64) (param $j i64) (param $c i32) (result i64 i32) + (local $k i64) + local.get $i + local.get $j + i64.add + local.get $c + i64.extend_i32_u + i64.add + local.set $k + local.get $k + local.get $k + local.get $i + i64.lt_u + return + ) + (func $add64_u_saturated (;50;) (type 14) (param i64 i64) (result i64) + local.get 0 + local.get 1 + i32.const 0 + call $add64_u_with_carry + if (type 15) (param i64) (result i64) ;; label = @1 + drop + i64.const -1 + end + ) + (func (;51;) (type $block-sig-1) + i32.const 1 + if (type $block-sig-1) ;; label = @1 + end + i32.const 1 + if (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + else + i32.const 2 + end + i32.const 1 + if (type $block-sig-3) (param i32) ;; label = @1 + drop + else + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 1 + if (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + i32.const 1 + if (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + else + i32.const 2 + end + i32.const 1 + if (type $block-sig-3) (param i32) ;; label = @1 + drop + else + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 1 + if (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "empty" (func 1)) + (export "singular" (func 2)) + (export "multi" (func 3)) + (export "nested" (func 4)) + (export "as-select-first" (func 5)) + (export "as-select-mid" (func 6)) + (export "as-select-last" (func 7)) + (export "as-loop-first" (func 8)) + (export "as-loop-mid" (func 9)) + (export "as-loop-last" (func 10)) + (export "as-if-condition" (func 11)) + (export "as-br_if-first" (func 12)) + (export "as-br_if-last" (func 13)) + (export "as-br_table-first" (func 14)) + (export "as-br_table-last" (func 15)) + (export "as-call_indirect-first" (func 17)) + (export "as-call_indirect-mid" (func 18)) + (export "as-call_indirect-last" (func 19)) + (export "as-store-first" (func 20)) + (export "as-store-last" (func 21)) + (export "as-memory.grow-value" (func 22)) + (export "as-call-value" (func 24)) + (export "as-return-value" (func 25)) + (export "as-drop-operand" (func 26)) + (export "as-br-value" (func 27)) + (export "as-local.set-value" (func 28)) + (export "as-local.tee-value" (func 29)) + (export "as-global.set-value" (func 30)) + (export "as-load-operand" (func 31)) + (export "as-unary-operand" (func 32)) + (export "as-binary-operand" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-operand" (func 35)) + (export "as-binary-operands" (func 36)) + (export "as-compare-operands" (func 37)) + (export "as-mixed-operands" (func 38)) + (export "break-bare" (func 39)) + (export "break-value" (func 40)) + (export "break-multi-value" (func 41)) + (export "param" (func 42)) + (export "params" (func 43)) + (export "params-id" (func 44)) + (export "param-break" (func 45)) + (export "params-break" (func 46)) + (export "params-id-break" (func 47)) + (export "effects" (func 48)) + (export "add64_u_with_carry" (func $add64_u_with_carry)) + (export "add64_u_saturated" (func $add64_u_saturated)) + (export "type-use" (func 51)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/0.print new file mode 100644 index 0000000000..a9214ac0e3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/0.print @@ -0,0 +1,10 @@ +(module $Mf + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + call $g + ) + (func $g (;1;) (type 0) (result i32) + i32.const 2 + ) + (export "call" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/11.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/11.print new file mode 100644 index 0000000000..12315604a6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/11.print @@ -0,0 +1,21 @@ +(module $Mg + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + global.get $glob + ) + (func (;1;) (type 0) (result i32) + global.get $mut_glob + ) + (func (;2;) (type 1) (param i32) + local.get 0 + global.set $mut_glob + ) + (global $glob (;0;) i32 i32.const 42) + (global $mut_glob (;1;) (mut i32) i32.const 142) + (export "glob" (global $glob)) + (export "get" (func 0)) + (export "mut_glob" (global $mut_glob)) + (export "get_mut" (func 1)) + (export "set_mut" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/111.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/111.print new file mode 100644 index 0000000000..c3d1cec142 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/111.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "Mt" "tab" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/112.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/112.print new file mode 100644 index 0000000000..f11c4feb9d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/112.print @@ -0,0 +1,4 @@ +(module $G1 + (global (;0;) i32 i32.const 5) + (export "g" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/114.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/114.print new file mode 100644 index 0000000000..5950d0a90b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/114.print @@ -0,0 +1,5 @@ +(module $G2 + (import "G1" "g" (global (;0;) i32)) + (global (;1;) i32 global.get 0) + (export "g" (global 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/124.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/124.print new file mode 100644 index 0000000000..41ada7402e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/124.print @@ -0,0 +1,9 @@ +(module $Mtable_ex + (type $t (;0;) (func)) + (table (;0;) 1 funcref) + (table (;1;) 1 (ref null 0)) + (table (;2;) 1 externref) + (export "t-funcnull" (table 0)) + (export "t-refnull" (table 1)) + (export "t-extern" (table 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/126.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/126.print new file mode 100644 index 0000000000..32615439e4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/126.print @@ -0,0 +1,6 @@ +(module + (type $t (;0;) (func)) + (import "Mtable_ex" "t-funcnull" (table (;0;) 1 funcref)) + (import "Mtable_ex" "t-refnull" (table (;1;) 1 (ref null 0))) + (import "Mtable_ex" "t-extern" (table (;2;) 1 externref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/13.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/13.print new file mode 100644 index 0000000000..45ee840475 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/13.print @@ -0,0 +1,20 @@ +(module $Ng + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (import "Mg" "glob" (global $x (;0;) i32)) + (import "Mg" "mut_glob" (global $mut_glob (;1;) (mut i32))) + (import "Mg" "get" (func $f (;0;) (type 0))) + (import "Mg" "get_mut" (func $get_mut (;1;) (type 0))) + (import "Mg" "set_mut" (func $set_mut (;2;) (type 1))) + (func (;3;) (type 0) (result i32) + global.get $glob + ) + (global $glob (;2;) i32 i32.const 43) + (export "Mg.glob" (global $x)) + (export "Mg.get" (func $f)) + (export "glob" (global $glob)) + (export "get" (func 3)) + (export "Mg.mut_glob" (global $mut_glob)) + (export "Mg.get_mut" (func $get_mut)) + (export "Mg.set_mut" (func $set_mut)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/133.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/133.print new file mode 100644 index 0000000000..4bc82eb617 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/133.print @@ -0,0 +1,11 @@ +(module $Mm + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (memory (;0;) 1 5) + (export "mem" (memory 0)) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/135.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/135.print new file mode 100644 index 0000000000..b2d41df30d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/135.print @@ -0,0 +1,12 @@ +(module $Nm + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "load" (func $loadM (;0;) (type 0))) + (func (;1;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (memory (;0;) 1) + (export "Mm.load" (func $loadM)) + (export "load" (func 1)) + (data (;0;) (i32.const 10) "\f0\f1\f2\f3\f4\f5") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/139.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/139.print new file mode 100644 index 0000000000..31afc29676 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/139.print @@ -0,0 +1,10 @@ +(module $Om + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "mem" (memory (;0;) 1)) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (export "load" (func 0)) + (data (;0;) (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/144.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/144.print new file mode 100644 index 0000000000..56c92a9af5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/144.print @@ -0,0 +1,4 @@ +(module + (import "Mm" "mem" (memory (;0;) 0)) + (data (;0;) (i32.const 65535) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/146.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/146.print new file mode 100644 index 0000000000..17368b7ad7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/146.print @@ -0,0 +1,9 @@ +(module $Pm + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "mem" (memory (;0;) 1 8)) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + memory.grow + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/162.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/162.print new file mode 100644 index 0000000000..24a36bdfab --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/162.print @@ -0,0 +1,17 @@ +(module $Ms + (type $t (;0;) (func (result i32))) + (func (;0;) (type $t) (result i32) + i32.const 0 + i32.load8_u + ) + (func (;1;) (type $t) (result i32) + i32.const 0 + call_indirect (type $t) + ) + (table (;0;) 1 funcref) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "table" (table 0)) + (export "get memory[0]" (func 0)) + (export "get table[0]" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/2.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/2.print new file mode 100644 index 0000000000..20a34e4785 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/2.print @@ -0,0 +1,16 @@ +(module $Nf + (type (;0;) (func (result i32))) + (import "Mf" "call" (func $f (;0;) (type 0))) + (func (;1;) (type 0) (result i32) + call $f + ) + (func (;2;) (type 0) (result i32) + call $g + ) + (func $g (;3;) (type 0) (result i32) + i32.const 3 + ) + (export "Mf.call" (func $f)) + (export "call Mf.call" (func 1)) + (export "call" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/31.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/31.print new file mode 100644 index 0000000000..fe9f49e7d0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/31.print @@ -0,0 +1,25 @@ +(module $Mref_ex + (type $t (;0;) (func)) + (func $f (;0;) (type $t)) + (global (;0;) funcref ref.null func) + (global (;1;) (ref func) ref.func $f) + (global (;2;) (ref null 0) ref.null 0) + (global (;3;) (ref 0) ref.func $f) + (global (;4;) externref ref.null extern) + (global (;5;) (mut funcref) ref.null func) + (global (;6;) (mut (ref func)) ref.func $f) + (global (;7;) (mut (ref null 0)) ref.null 0) + (global (;8;) (mut (ref 0)) ref.func $f) + (global (;9;) (mut externref) ref.null extern) + (export "g-const-funcnull" (global 0)) + (export "g-const-func" (global 1)) + (export "g-const-refnull" (global 2)) + (export "g-const-ref" (global 3)) + (export "g-const-extern" (global 4)) + (export "g-var-funcnull" (global 5)) + (export "g-var-func" (global 6)) + (export "g-var-refnull" (global 7)) + (export "g-var-ref" (global 8)) + (export "g-var-extern" (global 9)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/33.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/33.print new file mode 100644 index 0000000000..f71d4c6a39 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/33.print @@ -0,0 +1,18 @@ +(module $Mref_im + (type $t (;0;) (func)) + (import "Mref_ex" "g-const-funcnull" (global (;0;) funcref)) + (import "Mref_ex" "g-const-func" (global (;1;) funcref)) + (import "Mref_ex" "g-const-refnull" (global (;2;) funcref)) + (import "Mref_ex" "g-const-ref" (global (;3;) funcref)) + (import "Mref_ex" "g-const-func" (global (;4;) (ref func))) + (import "Mref_ex" "g-const-ref" (global (;5;) (ref func))) + (import "Mref_ex" "g-const-refnull" (global (;6;) (ref null 0))) + (import "Mref_ex" "g-const-ref" (global (;7;) (ref null 0))) + (import "Mref_ex" "g-const-ref" (global (;8;) (ref 0))) + (import "Mref_ex" "g-const-extern" (global (;9;) externref)) + (import "Mref_ex" "g-var-funcnull" (global (;10;) (mut funcref))) + (import "Mref_ex" "g-var-func" (global (;11;) (mut (ref func)))) + (import "Mref_ex" "g-var-refnull" (global (;12;) (mut (ref null 0)))) + (import "Mref_ex" "g-var-ref" (global (;13;) (mut (ref 0)))) + (import "Mref_ex" "g-var-extern" (global (;14;) (mut externref))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/69.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/69.print new file mode 100644 index 0000000000..045b7e0e24 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/69.print @@ -0,0 +1,20 @@ +(module $Mt + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (func $g (;0;) (type 0) (result i32) + i32.const 4 + ) + (func (;1;) (type 0) (result i32) + i32.const -4 + ) + (func (;2;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table (;0;) 10 funcref) + (export "tab" (table 0)) + (export "h" (func 1)) + (export "call" (func 2)) + (elem (;0;) (i32.const 2) func $g $g $g $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/7.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/7.print new file mode 100644 index 0000000000..ba4140f49a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/7.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func $f (;0;) (type 0))) + (export "print" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/71.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/71.print new file mode 100644 index 0000000000..7021967aba --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/71.print @@ -0,0 +1,23 @@ +(module $Nt + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32) (result i32))) + (import "Mt" "call" (func $f (;0;) (type 2))) + (import "Mt" "h" (func $h (;1;) (type 1))) + (func $g (;2;) (type 1) (result i32) + i32.const 5 + ) + (func (;3;) (type 2) (param i32) (result i32) + local.get 0 + call $f + ) + (func (;4;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 1) + ) + (table (;0;) 5 5 funcref) + (export "Mt.call" (func $f)) + (export "call Mt.call" (func 3)) + (export "call" (func 4)) + (elem (;0;) (i32.const 0) func $g $g $g $h $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/linking.wast/90.print b/tests/snapshots/testsuite/proposals/function-references/linking.wast/90.print new file mode 100644 index 0000000000..a9da3390ae --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/linking.wast/90.print @@ -0,0 +1,15 @@ +(module $Ot + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "Mt" "h" (func $h (;0;) (type 0))) + (import "Mt" "tab" (table (;0;) 5 funcref)) + (func $i (;1;) (type 0) (result i32) + i32.const 6 + ) + (func (;2;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (export "call" (func 2)) + (elem (;0;) (i32.const 1) func $i $h) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/local_get.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/local_get.wast/0.print new file mode 100644 index 0000000000..8016de3d6b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/local_get.wast/0.print @@ -0,0 +1,189 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (type (;4;) (func (param i32) (result i32))) + (type (;5;) (func (param i64) (result i64))) + (type (;6;) (func (param f32) (result f32))) + (type (;7;) (func (param f64) (result f64))) + (type (;8;) (func (param i64 f32 f64 i32 i32))) + (type (;9;) (func (param i64 f32 f64 i32 i32) (result f64))) + (func (;0;) (type 0) (result i32) + (local i32) + local.get 0 + ) + (func (;1;) (type 1) (result i64) + (local i64) + local.get 0 + ) + (func (;2;) (type 2) (result f32) + (local f32) + local.get 0 + ) + (func (;3;) (type 3) (result f64) + (local f64) + local.get 0 + ) + (func (;4;) (type 4) (param i32) (result i32) + local.get 0 + ) + (func (;5;) (type 5) (param i64) (result i64) + local.get 0 + ) + (func (;6;) (type 6) (param f32) (result f32) + local.get 0 + ) + (func (;7;) (type 7) (param f64) (result f64) + local.get 0 + ) + (func (;8;) (type 8) (param i64 f32 f64 i32 i32) + (local f32 i64 i64 f64) + local.get 0 + i64.eqz + drop + local.get 1 + f32.neg + drop + local.get 2 + f64.neg + drop + local.get 3 + i32.eqz + drop + local.get 4 + i32.eqz + drop + local.get 5 + f32.neg + drop + local.get 6 + i64.eqz + drop + local.get 7 + i64.eqz + drop + local.get 8 + f64.neg + drop + ) + (func (;9;) (type 9) (param i64 f32 f64 i32 i32) (result f64) + (local f32 i64 i64 f64) + f32.const 0x1.6p+2 (;=5.5;) + local.set 5 + i64.const 6 + local.set 6 + f64.const 0x1p+3 (;=8;) + local.set 8 + local.get 0 + f64.convert_i64_u + local.get 1 + f64.promote_f32 + local.get 2 + local.get 3 + f64.convert_i32_u + local.get 4 + f64.convert_i32_s + local.get 5 + f64.promote_f32 + local.get 6 + f64.convert_i64_u + local.get 7 + f64.convert_i64_u + local.get 8 + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + ) + (func (;10;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + end + ) + (func (;11;) (type 4) (param i32) (result i32) + loop (result i32) ;; label = @1 + local.get 0 + end + ) + (func (;12;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + br 0 (;@1;) + end + ) + (func (;13;) (type 4) (param i32) (result i32) + block $l0 (result i32) ;; label = @1 + local.get 0 + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;14;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + local.get 0 + br_if 0 (;@1;) + end + ) + (func (;15;) (type 4) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 0 + return + end + i32.const 1 + return + end + i32.const 2 + return + end + i32.const 3 + ) + (func (;16;) (type 4) (param i32) (result i32) + local.get 0 + return + ) + (func (;17;) (type 4) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 0 + else + i32.const 0 + end + ) + (func (;18;) (type 4) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + local.get 0 + end + ) + (export "type-local-i32" (func 0)) + (export "type-local-i64" (func 1)) + (export "type-local-f32" (func 2)) + (export "type-local-f64" (func 3)) + (export "type-param-i32" (func 4)) + (export "type-param-i64" (func 5)) + (export "type-param-f32" (func 6)) + (export "type-param-f64" (func 7)) + (export "type-mixed" (func 8)) + (export "read" (func 9)) + (export "as-block-value" (func 10)) + (export "as-loop-value" (func 11)) + (export "as-br-value" (func 12)) + (export "as-br_if-value" (func 13)) + (export "as-br_if-value-cond" (func 14)) + (export "as-br_table-value" (func 15)) + (export "as-return-value" (func 16)) + (export "as-if-then" (func 17)) + (export "as-if-else" (func 18)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/local_init.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/local_init.wast/0.print new file mode 100644 index 0000000000..64848a6de7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/local_init.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param (ref extern)) (result (ref extern)))) + (func (;0;) (type 0) (param $p (ref extern)) (result (ref extern)) + (local $x (ref extern)) + local.get $p + local.set $x + local.get $x + ) + (func (;1;) (type 0) (param $p (ref extern)) (result (ref extern)) + (local $x (ref extern)) + local.get $p + local.tee $x + drop + local.get $x + ) + (func (;2;) (type 0) (param $p (ref extern)) (result (ref extern)) + (local $x (ref extern)) + local.get $p + local.set $x + block (result (ref extern)) ;; label = @1 + local.get $x + end + ) + (export "get-after-set" (func 0)) + (export "get-after-tee" (func 1)) + (export "get-in-block-after-set" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/local_init.wast/8.print b/tests/snapshots/testsuite/proposals/function-references/local_init.wast/8.print new file mode 100644 index 0000000000..ddfbeff8e1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/local_init.wast/8.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param (ref extern)) (result (ref extern)))) + (func (;0;) (type 0) (param $p (ref extern)) (result (ref extern)) + (local $x (ref extern)) + local.get $p + local.tee $x + drop + local.get $x + ) + (export "tee-init" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/ref.wast/0.print new file mode 100644 index 0000000000..8dfe3db26e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref.wast/0.print @@ -0,0 +1,5 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param funcref externref (ref func) (ref extern) (ref 0) (ref 0) (ref 0) (ref 0) funcref externref (ref null 0) (ref null 0)))) + (func (;0;) (type 1) (param funcref externref (ref func) (ref extern) (ref 0) (ref 0) (ref 0) (ref 0) funcref externref (ref null 0) (ref null 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref_as_non_null.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/ref_as_non_null.wast/0.print new file mode 100644 index 0000000000..d1387d3fa2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref_as_non_null.wast/0.print @@ -0,0 +1,40 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + local.get $r + ref.as_non_null + call_ref $t + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + local.get $r + ref.as_non_null + call_ref $t + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + unreachable + ref.as_non_null + call $nn + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref_as_non_null.wast/6.print b/tests/snapshots/testsuite/proposals/function-references/ref_as_non_null.wast/6.print new file mode 100644 index 0000000000..84c6c3f322 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref_as_non_null.wast/6.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref 0)))) + (type (;2;) (func (param (ref func)))) + (type (;3;) (func (param (ref extern)))) + (func (;0;) (type 1) (param $r (ref 0)) + local.get $r + ref.as_non_null + drop + ) + (func (;1;) (type 2) (param $r (ref func)) + local.get $r + ref.as_non_null + drop + ) + (func (;2;) (type 3) (param $r (ref extern)) + local.get $r + ref.as_non_null + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/0.print new file mode 100644 index 0000000000..acffc25333 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/0.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/14.print b/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/14.print new file mode 100644 index 0000000000..c509cd9ecf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/14.print @@ -0,0 +1,25 @@ +(module + (type (;0;) (func)) + (func $f1 (;0;) (type 0)) + (func $f2 (;1;) (type 0)) + (func $f3 (;2;) (type 0)) + (func $f4 (;3;) (type 0)) + (func $f5 (;4;) (type 0)) + (func $f6 (;5;) (type 0)) + (func (;6;) (type 0) + ref.func $f1 + ref.func $f2 + ref.func $f3 + ref.func $f4 + ref.func $f5 + ref.func $f6 + return + ) + (table $t (;0;) 1 funcref) + (global (;0;) funcref ref.func $f1) + (export "f" (func $f2)) + (elem (;0;) (i32.const 0) func $f3) + (elem (;1;) (i32.const 0) funcref (ref.func $f4)) + (elem (;2;) func $f5) + (elem (;3;) funcref (ref.func $f6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/2.print b/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/2.print new file mode 100644 index 0000000000..61b233dec6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref_func.wast/2.print @@ -0,0 +1,82 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (import "M" "f" (func $f (;0;) (type 0))) + (func $g (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 1 + i32.add + ) + (func (;2;) (type 1) + ref.func $ff1 + drop + ref.func $ff2 + drop + ) + (func $gf1 (;3;) (type 1)) + (func $gf2 (;4;) (type 1)) + (func $ff1 (;5;) (type 1)) + (func $ff2 (;6;) (type 1)) + (func (;7;) (type 2) (result i32) + ref.func $f + ref.is_null + ) + (func (;8;) (type 2) (result i32) + ref.func $g + ref.is_null + ) + (func (;9;) (type 2) (result i32) + global.get $v + ref.is_null + ) + (func (;10;) (type 1) + ref.func $f + global.set $v + ) + (func (;11;) (type 1) + ref.func $g + global.set $v + ) + (func (;12;) (type 0) (param $x i32) (result i32) + i32.const 0 + ref.func $f + table.set $t + local.get $x + i32.const 0 + call_indirect (type 0) + ) + (func (;13;) (type 0) (param $x i32) (result i32) + i32.const 0 + ref.func $g + table.set $t + local.get $x + i32.const 0 + call_indirect (type 0) + ) + (func (;14;) (type 0) (param $x i32) (result i32) + i32.const 0 + global.get $v + table.set $t + local.get $x + i32.const 0 + call_indirect (type 0) + ) + (table $t (;0;) 1 funcref) + (global (;0;) funcref ref.func $f) + (global (;1;) funcref ref.func $g) + (global $v (;2;) (mut funcref) ref.func $f) + (global (;3;) funcref ref.func $gf1) + (global (;4;) funcref ref.func $gf2) + (export "is_null-f" (func 7)) + (export "is_null-g" (func 8)) + (export "is_null-v" (func 9)) + (export "set-f" (func 10)) + (export "set-g" (func 11)) + (export "call-f" (func 12)) + (export "call-g" (func 13)) + (export "call-v" (func 14)) + (elem (;0;) declare func $gf1 $ff1) + (elem (;1;) declare funcref (ref.func $gf2) (ref.func $ff2)) + (elem (;2;) declare func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref_is_null.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/ref_is_null.wast/0.print new file mode 100644 index 0000000000..b021c3b78f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref_is_null.wast/0.print @@ -0,0 +1,70 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param funcref) (result i32))) + (type (;2;) (func (param externref) (result i32))) + (type (;3;) (func (param (ref null 0)) (result i32))) + (type (;4;) (func (result i32))) + (type (;5;) (func (param externref))) + (type (;6;) (func (param i32) (result i32))) + (func $dummy (;0;) (type $t)) + (func $f1 (;1;) (type 1) (param $x funcref) (result i32) + local.get $x + ref.is_null + ) + (func $f2 (;2;) (type 2) (param $x externref) (result i32) + local.get $x + ref.is_null + ) + (func $f3 (;3;) (type 3) (param $x (ref null 0)) (result i32) + local.get $x + ref.is_null + ) + (func $f3' (;4;) (type 4) (result i32) + ref.null 0 + call $f3 + ) + (func (;5;) (type 5) (param $r externref) + i32.const 1 + local.get $r + table.set $t2 + ) + (func (;6;) (type $t) + i32.const 1 + ref.null func + table.set $t1 + i32.const 1 + ref.null extern + table.set $t2 + i32.const 1 + ref.null 0 + table.set $t3 + ) + (func (;7;) (type 6) (param $x i32) (result i32) + local.get $x + table.get $t1 + call $f1 + ) + (func (;8;) (type 6) (param $x i32) (result i32) + local.get $x + table.get $t2 + call $f2 + ) + (func (;9;) (type 6) (param $x i32) (result i32) + local.get $x + table.get $t3 + call $f3 + ) + (table $t1 (;0;) 2 funcref) + (table $t2 (;1;) 2 externref) + (table $t3 (;2;) 2 (ref null 0)) + (export "funcref" (func $f1)) + (export "externref" (func $f2)) + (export "ref-null" (func $f3')) + (export "init" (func 5)) + (export "deinit" (func 6)) + (export "funcref-elem" (func 7)) + (export "externref-elem" (func 8)) + (export "ref-elem" (func 9)) + (elem (;0;) (i32.const 1) func $dummy) + (elem (;1;) (table $t3) (i32.const 1) (ref 0) (ref.func $dummy)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref_is_null.wast/19.print b/tests/snapshots/testsuite/proposals/function-references/ref_is_null.wast/19.print new file mode 100644 index 0000000000..e0896368df --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref_is_null.wast/19.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref 0)))) + (type (;2;) (func (param (ref func)))) + (type (;3;) (func (param (ref extern)))) + (func (;0;) (type 1) (param $r (ref 0)) + local.get $r + ref.is_null + drop + ) + (func (;1;) (type 2) (param $r (ref func)) + local.get $r + ref.is_null + drop + ) + (func (;2;) (type 3) (param $r (ref extern)) + local.get $r + ref.is_null + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/ref_null.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/ref_null.wast/0.print new file mode 100644 index 0000000000..a317b92700 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/ref_null.wast/0.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (result externref))) + (type (;2;) (func (result funcref))) + (type (;3;) (func (result (ref null 0)))) + (func (;0;) (type 1) (result externref) + ref.null extern + ) + (func (;1;) (type 2) (result funcref) + ref.null func + ) + (func (;2;) (type 3) (result (ref null 0)) + ref.null 0 + ) + (global (;0;) externref ref.null extern) + (global (;1;) funcref ref.null func) + (global (;2;) (ref null 0) ref.null 0) + (export "externref" (func 0)) + (export "funcref" (func 1)) + (export "ref" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/return_call.wast/0.print new file mode 100644 index 0000000000..8deaba4d9b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call.wast/0.print @@ -0,0 +1,167 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (type (;4;) (func (param i32) (result i32))) + (type (;5;) (func (param i64) (result i64))) + (type (;6;) (func (param f32) (result f32))) + (type (;7;) (func (param f64) (result f64))) + (type (;8;) (func (param f32 i32) (result i32))) + (type (;9;) (func (param i32 i64) (result i64))) + (type (;10;) (func (param f64 f32) (result f32))) + (type (;11;) (func (param i64 f64) (result f64))) + (type (;12;) (func (param i64 i64) (result i64))) + (type (;13;) (func (param i64) (result i32))) + (func $const-i32 (;0;) (type 0) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type 1) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type 2) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type 3) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type 4) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type 5) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type 6) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type 7) (param f64) (result f64) + local.get 0 + ) + (func $f32-i32 (;8;) (type 8) (param f32 i32) (result i32) + local.get 1 + ) + (func $i32-i64 (;9;) (type 9) (param i32 i64) (result i64) + local.get 1 + ) + (func $f64-f32 (;10;) (type 10) (param f64 f32) (result f32) + local.get 1 + ) + (func $i64-f64 (;11;) (type 11) (param i64 f64) (result f64) + local.get 1 + ) + (func (;12;) (type 0) (result i32) + return_call $const-i32 + ) + (func (;13;) (type 1) (result i64) + return_call $const-i64 + ) + (func (;14;) (type 2) (result f32) + return_call $const-f32 + ) + (func (;15;) (type 3) (result f64) + return_call $const-f64 + ) + (func (;16;) (type 0) (result i32) + i32.const 32 + return_call $id-i32 + ) + (func (;17;) (type 1) (result i64) + i64.const 64 + return_call $id-i64 + ) + (func (;18;) (type 2) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + return_call $id-f32 + ) + (func (;19;) (type 3) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + return_call $id-f64 + ) + (func (;20;) (type 0) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + return_call $f32-i32 + ) + (func (;21;) (type 1) (result i64) + i32.const 32 + i64.const 64 + return_call $i32-i64 + ) + (func (;22;) (type 2) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + return_call $f64-f32 + ) + (func (;23;) (type 3) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + return_call $i64-f64 + ) + (func $fac-acc (;24;) (type 12) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + return_call $fac-acc + end + ) + (func $count (;25;) (type 5) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 0 + else + local.get 0 + i64.const 1 + i64.sub + return_call $count + end + ) + (func $even (;26;) (type 13) (param i64) (result i32) + local.get 0 + i64.eqz + if (result i32) ;; label = @1 + i32.const 44 + else + local.get 0 + i64.const 1 + i64.sub + return_call $odd + end + ) + (func $odd (;27;) (type 13) (param i64) (result i32) + local.get 0 + i64.eqz + if (result i32) ;; label = @1 + i32.const 99 + else + local.get 0 + i64.const 1 + i64.sub + return_call $even + end + ) + (export "type-i32" (func 12)) + (export "type-i64" (func 13)) + (export "type-f32" (func 14)) + (export "type-f64" (func 15)) + (export "type-first-i32" (func 16)) + (export "type-first-i64" (func 17)) + (export "type-first-f32" (func 18)) + (export "type-first-f64" (func 19)) + (export "type-second-i32" (func 20)) + (export "type-second-i64" (func 21)) + (export "type-second-f32" (func 22)) + (export "type-second-f64" (func 23)) + (export "fac-acc" (func $fac-acc)) + (export "count" (func $count)) + (export "even" (func $even)) + (export "odd" (func $odd)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call.wast/36.print b/tests/snapshots/testsuite/proposals/function-references/return_call.wast/36.print new file mode 100644 index 0000000000..cd55a24384 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call.wast/36.print @@ -0,0 +1,8 @@ +(module + (type (;0;) (func)) + (func $arity-1-vs-0 (;0;) (type 0) + i32.const 1 + return_call 1 + ) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call.wast/37.print b/tests/snapshots/testsuite/proposals/function-references/return_call.wast/37.print new file mode 100644 index 0000000000..d4be01c6e9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call.wast/37.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func $arity-2-vs-0 (;0;) (type 0) + f64.const 0x1p+1 (;=2;) + i32.const 1 + return_call 1 + ) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/0.print new file mode 100644 index 0000000000..c8356e64ea --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/0.print @@ -0,0 +1,286 @@ +(module + (type $proc (;0;) (func)) + (type $out-i32 (;1;) (func (result i32))) + (type $out-i64 (;2;) (func (result i64))) + (type $out-f32 (;3;) (func (result f32))) + (type $out-f64 (;4;) (func (result f64))) + (type $over-i32 (;5;) (func (param i32) (result i32))) + (type $over-i64 (;6;) (func (param i64) (result i64))) + (type $over-f32 (;7;) (func (param f32) (result f32))) + (type $over-f64 (;8;) (func (param f64) (result f64))) + (type $f32-i32 (;9;) (func (param f32 i32) (result i32))) + (type $i32-i64 (;10;) (func (param i32 i64) (result i64))) + (type $f64-f32 (;11;) (func (param f64 f32) (result f32))) + (type $i64-f64 (;12;) (func (param i64 f64) (result f64))) + (type $over-i32-duplicate (;13;) (func (param i32) (result i32))) + (type $over-i64-duplicate (;14;) (func (param i64) (result i64))) + (type $over-f32-duplicate (;15;) (func (param f32) (result f32))) + (type $over-f64-duplicate (;16;) (func (param f64) (result f64))) + (type (;17;) (func (param i64))) + (type (;18;) (func (param i64 f64 i32 i64))) + (type (;19;) (func (param i64) (result i32))) + (type (;20;) (func (param i64 f64 i32 i64) (result i32))) + (type (;21;) (func (param i32) (result i64))) + (type (;22;) (func (param i64 i64) (result i64))) + (func $const-i32 (;0;) (type $out-i32) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type $out-i64) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type $out-f32) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type $out-f64) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type $over-i32) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type $over-i64) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type $over-f32) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type $over-f64) (param f64) (result f64) + local.get 0 + ) + (func $i32-i64 (;8;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + ) + (func $i64-f64 (;9;) (type $i64-f64) (param i64 f64) (result f64) + local.get 1 + ) + (func $f32-i32 (;10;) (type $f32-i32) (param f32 i32) (result i32) + local.get 1 + ) + (func $f64-f32 (;11;) (type $f64-f32) (param f64 f32) (result f32) + local.get 1 + ) + (func $over-i32-duplicate (;12;) (type $over-i32-duplicate) (param i32) (result i32) + local.get 0 + ) + (func $over-i64-duplicate (;13;) (type $over-i64-duplicate) (param i64) (result i64) + local.get 0 + ) + (func $over-f32-duplicate (;14;) (type $over-f32-duplicate) (param f32) (result f32) + local.get 0 + ) + (func $over-f64-duplicate (;15;) (type $over-f64-duplicate) (param f64) (result f64) + local.get 0 + ) + (func (;16;) (type $proc) + i32.const 0 + return_call_indirect (type $proc) + i64.const 0 + i32.const 0 + return_call_indirect (type 17) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i32.const 0 + return_call_indirect (type 18) + i32.const 0 + return_call_indirect (type $proc) + ) + (func (;17;) (type $out-i32) (result i32) + i32.const 0 + return_call_indirect (type $out-i32) + i32.const 0 + return_call_indirect (type $out-i32) + i64.const 0 + i32.const 0 + return_call_indirect (type 19) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i32.const 0 + return_call_indirect (type 20) + ) + (func (;18;) (type $out-i64) (result i64) + i64.const 0 + i32.const 0 + return_call_indirect (type $over-i64) + ) + (func (;19;) (type $out-i32) (result i32) + i32.const 0 + return_call_indirect (type $out-i32) + ) + (func (;20;) (type $out-i64) (result i64) + i32.const 1 + return_call_indirect (type $out-i64) + ) + (func (;21;) (type $out-f32) (result f32) + i32.const 2 + return_call_indirect (type $out-f32) + ) + (func (;22;) (type $out-f64) (result f64) + i32.const 3 + return_call_indirect (type $out-f64) + ) + (func (;23;) (type $out-i64) (result i64) + i64.const 100 + i32.const 5 + return_call_indirect (type $over-i64) + ) + (func (;24;) (type $out-i32) (result i32) + i32.const 32 + i32.const 4 + return_call_indirect (type $over-i32) + ) + (func (;25;) (type $out-i64) (result i64) + i64.const 64 + i32.const 5 + return_call_indirect (type $over-i64) + ) + (func (;26;) (type $out-f32) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + i32.const 6 + return_call_indirect (type $over-f32) + ) + (func (;27;) (type $out-f64) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + i32.const 7 + return_call_indirect (type $over-f64) + ) + (func (;28;) (type $out-i32) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + i32.const 8 + return_call_indirect (type $f32-i32) + ) + (func (;29;) (type $out-i64) (result i64) + i32.const 32 + i64.const 64 + i32.const 9 + return_call_indirect (type $i32-i64) + ) + (func (;30;) (type $out-f32) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + i32.const 10 + return_call_indirect (type $f64-f32) + ) + (func (;31;) (type $out-f64) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + i32.const 11 + return_call_indirect (type $i64-f64) + ) + (func (;32;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + local.get 0 + return_call_indirect (type $over-i64) + ) + (func (;33;) (type 21) (param i32) (result i64) + i64.const 9 + local.get 0 + return_call_indirect (type $over-i64-duplicate) + ) + (func $tab-f1 (;34;) (type $out-i32) (result i32) + i32.const 307 + ) + (func $tab-f2 (;35;) (type $out-i32) (result i32) + i32.const 308 + ) + (func (;36;) (type $over-i32) (param $i i32) (result i32) + local.get $i + i32.const 0 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect (type $out-i32) + end + local.get $i + i32.const 1 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect $tab2 (type $out-i32) + end + local.get $i + i32.const 2 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect $tab3 (type $out-i32) + end + i32.const 0 + ) + (func $fac (;37;) (type $over-i64) (param i64) (result i64) + local.get 0 + i64.const 1 + i32.const 13 + return_call_indirect (type 22) + ) + (func $fac-acc (;38;) (type 22) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + i32.const 13 + return_call_indirect (type 22) + end + ) + (func $even (;39;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 44 + else + local.get 0 + i32.const 1 + i32.sub + i32.const 15 + return_call_indirect (type $over-i32) + end + ) + (func $odd (;40;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 99 + else + local.get 0 + i32.const 1 + i32.sub + i32.const 14 + return_call_indirect (type $over-i32) + end + ) + (table (;0;) 20 20 funcref) + (table $tab2 (;1;) 1 1 funcref) + (table $tab3 (;2;) 1 1 funcref) + (export "type-i32" (func 19)) + (export "type-i64" (func 20)) + (export "type-f32" (func 21)) + (export "type-f64" (func 22)) + (export "type-index" (func 23)) + (export "type-first-i32" (func 24)) + (export "type-first-i64" (func 25)) + (export "type-first-f32" (func 26)) + (export "type-first-f64" (func 27)) + (export "type-second-i32" (func 28)) + (export "type-second-i64" (func 29)) + (export "type-second-f32" (func 30)) + (export "type-second-f64" (func 31)) + (export "dispatch" (func 32)) + (export "dispatch-structural" (func 33)) + (export "call-tab" (func 36)) + (export "fac" (func $fac)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) (i32.const 0) 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 $fac $fac-acc $even $odd $over-i32-duplicate $over-i64-duplicate $over-f32-duplicate $over-f64-duplicate) + (elem (;1;) (table $tab2) (i32.const 0) func $tab-f1) + (elem (;2;) (table $tab3) (i32.const 0) func $tab-f2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/64.print b/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/64.print new file mode 100644 index 0000000000..21d17b3e23 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/64.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func $arity-1-vs-0 (;0;) (type 0) + i32.const 1 + i32.const 0 + return_call_indirect (type 0) + ) + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/65.print b/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/65.print new file mode 100644 index 0000000000..c1f5719022 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call_indirect.wast/65.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func $arity-2-vs-0 (;0;) (type 0) + f64.const 0x1p+1 (;=2;) + i32.const 1 + i32.const 0 + return_call_indirect (type 0) + ) + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/0.print new file mode 100644 index 0000000000..fb2a39b0d2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/0.print @@ -0,0 +1,209 @@ +(module + (type $proc (;0;) (func)) + (type $-i32 (;1;) (func (result i32))) + (type $-i64 (;2;) (func (result i64))) + (type $-f32 (;3;) (func (result f32))) + (type $-f64 (;4;) (func (result f64))) + (type $i32-i32 (;5;) (func (param i32) (result i32))) + (type $i64-i64 (;6;) (func (param i64) (result i64))) + (type $f32-f32 (;7;) (func (param f32) (result f32))) + (type $f64-f64 (;8;) (func (param f64) (result f64))) + (type $f32-i32 (;9;) (func (param f32 i32) (result i32))) + (type $i32-i64 (;10;) (func (param i32 i64) (result i64))) + (type $f64-f32 (;11;) (func (param f64 f32) (result f32))) + (type $i64-f64 (;12;) (func (param i64 f64) (result f64))) + (type $i64i64-i64 (;13;) (func (param i64 i64) (result i64))) + (func $const-i32 (;0;) (type $-i32) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type $-i64) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type $-f32) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type $-f64) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type $i32-i32) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type $i64-i64) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type $f32-f32) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type $f64-f64) (param f64) (result f64) + local.get 0 + ) + (func $f32-i32 (;8;) (type $f32-i32) (param f32 i32) (result i32) + local.get 1 + ) + (func $i32-i64 (;9;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + ) + (func $f64-f32 (;10;) (type $f64-f32) (param f64 f32) (result f32) + local.get 1 + ) + (func $i64-f64 (;11;) (type $i64-f64) (param i64 f64) (result f64) + local.get 1 + ) + (func (;12;) (type $-i32) (result i32) + global.get $const-i32 + return_call_ref $-i32 + ) + (func (;13;) (type $-i64) (result i64) + global.get $const-i64 + return_call_ref $-i64 + ) + (func (;14;) (type $-f32) (result f32) + global.get $const-f32 + return_call_ref $-f32 + ) + (func (;15;) (type $-f64) (result f64) + global.get $const-f64 + return_call_ref $-f64 + ) + (func (;16;) (type $-i32) (result i32) + i32.const 32 + global.get $id-i32 + return_call_ref $i32-i32 + ) + (func (;17;) (type $-i64) (result i64) + i64.const 64 + global.get $id-i64 + return_call_ref $i64-i64 + ) + (func (;18;) (type $-f32) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + global.get $id-f32 + return_call_ref $f32-f32 + ) + (func (;19;) (type $-f64) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + global.get $id-f64 + return_call_ref $f64-f64 + ) + (func (;20;) (type $-i32) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + global.get $f32-i32 + return_call_ref $f32-i32 + ) + (func (;21;) (type $-i64) (result i64) + i32.const 32 + i64.const 64 + global.get $i32-i64 + return_call_ref $i32-i64 + ) + (func (;22;) (type $-f32) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + global.get $f64-f32 + return_call_ref $f64-f32 + ) + (func (;23;) (type $-f64) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + global.get $i64-f64 + return_call_ref $i64-f64 + ) + (func (;24;) (type $proc) + ref.null 0 + return_call_ref $proc + ) + (func $fac-acc (;25;) (type $i64i64-i64) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + global.get $fac-acc + return_call_ref $i64i64-i64 + end + ) + (func $count (;26;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 0 + else + local.get 0 + i64.const 1 + i64.sub + global.get $count + return_call_ref $i64-i64 + end + ) + (func $even (;27;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 44 + else + local.get 0 + i64.const 1 + i64.sub + global.get $odd + return_call_ref $i64-i64 + end + ) + (func $odd (;28;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 99 + else + local.get 0 + i64.const 1 + i64.sub + global.get $even + return_call_ref $i64-i64 + end + ) + (global $const-i32 (;0;) (ref 1) ref.func $const-i32) + (global $const-i64 (;1;) (ref 2) ref.func $const-i64) + (global $const-f32 (;2;) (ref 3) ref.func $const-f32) + (global $const-f64 (;3;) (ref 4) ref.func $const-f64) + (global $id-i32 (;4;) (ref 5) ref.func $id-i32) + (global $id-i64 (;5;) (ref 6) ref.func $id-i64) + (global $id-f32 (;6;) (ref 7) ref.func $id-f32) + (global $id-f64 (;7;) (ref 8) ref.func $id-f64) + (global $f32-i32 (;8;) (ref 9) ref.func $f32-i32) + (global $i32-i64 (;9;) (ref 10) ref.func $i32-i64) + (global $f64-f32 (;10;) (ref 11) ref.func $f64-f32) + (global $i64-f64 (;11;) (ref 12) ref.func $i64-f64) + (global $fac-acc (;12;) (ref 13) ref.func $fac-acc) + (global $count (;13;) (ref 6) ref.func $count) + (global $even (;14;) (ref 6) ref.func $even) + (global $odd (;15;) (ref 6) ref.func $odd) + (export "type-i32" (func 12)) + (export "type-i64" (func 13)) + (export "type-f32" (func 14)) + (export "type-f64" (func 15)) + (export "type-first-i32" (func 16)) + (export "type-first-i64" (func 17)) + (export "type-first-f32" (func 18)) + (export "type-first-f64" (func 19)) + (export "type-second-i32" (func 20)) + (export "type-second-i64" (func 21)) + (export "type-second-f32" (func 22)) + (export "type-second-f64" (func 23)) + (export "null" (func 24)) + (export "fac-acc" (func $fac-acc)) + (export "count" (func $count)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) 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) + (elem (;1;) declare func $fac-acc) + (elem (;2;) declare func $count) + (elem (;3;) declare func $even) + (elem (;4;) declare func $odd) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/33.print b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/33.print new file mode 100644 index 0000000000..db9c9d6516 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/33.print @@ -0,0 +1,44 @@ +(module + (type $t (;0;) (func)) + (type $t1 (;1;) (func (result (ref 0)))) + (type $t2 (;2;) (func (result (ref null 0)))) + (type $t3 (;3;) (func (result (ref func)))) + (type $t4 (;4;) (func (result funcref))) + (func $f11 (;0;) (type $t1) (result (ref 0)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f21 (;1;) (type $t2) (result (ref null 0)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f22 (;2;) (type $t2) (result (ref null 0)) + ref.func $f22 + return_call_ref $t2 + ) + (func $f31 (;3;) (type $t3) (result (ref func)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f33 (;4;) (type $t3) (result (ref func)) + ref.func $f33 + return_call_ref $t3 + ) + (func $f41 (;5;) (type $t4) (result funcref) + ref.func $f11 + return_call_ref $t1 + ) + (func $f42 (;6;) (type $t4) (result funcref) + ref.func $f22 + return_call_ref $t2 + ) + (func $f43 (;7;) (type $t4) (result funcref) + ref.func $f33 + return_call_ref $t3 + ) + (func $f44 (;8;) (type $t4) (result funcref) + ref.func $f44 + return_call_ref $t4 + ) + (elem (;0;) declare func $f11 $f22 $f33 $f44) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/40.print b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/40.print new file mode 100644 index 0000000000..70ed02cc52 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/40.print @@ -0,0 +1,8 @@ +(module + (type $t (;0;) (func (result i32))) + (func (;0;) (type $t) (result i32) + unreachable + return_call_ref $t + ) + (export "unreachable" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/42.print b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/42.print new file mode 100644 index 0000000000..09c8e10bb9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/42.print @@ -0,0 +1,14 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + ref.func $f + return_call_ref $t + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/44.print b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/44.print new file mode 100644 index 0000000000..97eaf8fe20 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/return_call_ref.wast/44.print @@ -0,0 +1,16 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + i32.const 0 + ref.func $f + return_call_ref $t + i32.const 0 + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/select.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/select.wast/0.print new file mode 100644 index 0000000000..114048621b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/select.wast/0.print @@ -0,0 +1,491 @@ +(module + (type $t (;0;) (func)) + (type $check (;1;) (func (param i32 i32) (result i32))) + (type (;2;) (func (param i32 i32 i32) (result i32))) + (type (;3;) (func (param i64 i64 i32) (result i64))) + (type (;4;) (func (param f32 f32 i32) (result f32))) + (type (;5;) (func (param f64 f64 i32) (result f64))) + (type (;6;) (func (param funcref funcref i32) (result funcref))) + (type (;7;) (func (param externref externref i32) (result externref))) + (type (;8;) (func (param i32) (result funcref))) + (type (;9;) (func (param i32) (result i32))) + (type (;10;) (func (result i32))) + (type (;11;) (func (result i64))) + (type (;12;) (func (param i32))) + (func $dummy (;0;) (type $t)) + (func (;1;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;2;) (type 3) (param i64 i64 i32) (result i64) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;3;) (type 4) (param f32 f32 i32) (result f32) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;4;) (type 5) (param f64 f64 i32) (result f64) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;5;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + select (result i32) + ) + (func (;6;) (type 3) (param i64 i64 i32) (result i64) + local.get 0 + local.get 1 + local.get 2 + select (result i64) + ) + (func (;7;) (type 4) (param f32 f32 i32) (result f32) + local.get 0 + local.get 1 + local.get 2 + select (result f32) + ) + (func (;8;) (type 5) (param f64 f64 i32) (result f64) + local.get 0 + local.get 1 + local.get 2 + select (result f64) + ) + (func (;9;) (type 6) (param funcref funcref i32) (result funcref) + local.get 0 + local.get 1 + local.get 2 + select (result funcref) + ) + (func (;10;) (type 7) (param externref externref i32) (result externref) + local.get 0 + local.get 1 + local.get 2 + select (result externref) + ) + (func $tf (;11;) (type $t)) + (func (;12;) (type 8) (param i32) (result funcref) + ref.func $tf + ref.null func + local.get 0 + select (result funcref) + ) + (func (;13;) (type 9) (param $cond i32) (result i32) + unreachable + i32.const 0 + local.get $cond + select + ) + (func (;14;) (type 9) (param $cond i32) (result i32) + i32.const 0 + unreachable + local.get $cond + select + ) + (func (;15;) (type $t) + 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 0x0p+0 (;=0;) + i32.const 0 + select + unreachable + ) + (func (;16;) (type 10) (result i32) + unreachable + select + i32.add + ) + (func (;17;) (type 11) (result i64) + unreachable + i64.const 0 + i32.const 0 + select + i64.add + ) + (func (;18;) (type 9) (param i32) (result i32) + i32.const 0 + i32.const 1 + local.get 0 + select + i32.const 2 + i32.const 3 + select + ) + (func (;19;) (type 9) (param i32) (result i32) + i32.const 2 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.const 3 + select + ) + (func (;20;) (type 9) (param i32) (result i32) + i32.const 2 + i32.const 3 + i32.const 0 + i32.const 1 + local.get 0 + select + select + ) + (func (;21;) (type 9) (param i32) (result i32) + loop (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + call $dummy + call $dummy + end + ) + (func (;22;) (type 9) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 2 + i32.const 3 + local.get 0 + select + call $dummy + end + ) + (func (;23;) (type 9) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 2 + i32.const 3 + local.get 0 + select + end + ) + (func (;24;) (type 12) (param i32) + i32.const 2 + i32.const 3 + local.get 0 + select + if ;; label = @1 + call $dummy + end + ) + (func (;25;) (type 9) (param i32) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + else + i32.const 4 + end + ) + (func (;26;) (type 9) (param i32) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 2 + else + i32.const 2 + i32.const 3 + local.get 0 + select + end + ) + (func (;27;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 4 + br_if 0 (;@1;) + end + ) + (func (;28;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 2 + i32.const 3 + local.get 0 + select + br_if 0 (;@1;) + end + ) + (func (;29;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;30;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 2 + i32.const 3 + local.get 0 + select + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;31;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;32;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 1 + i32.const 0 + call_indirect $t (type $check) + end + ) + (func (;33;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 0 + call_indirect $t (type $check) + end + ) + (func (;34;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 4 + i32.const 2 + i32.const 3 + local.get 0 + select + call_indirect $t (type $check) + end + ) + (func (;35;) (type 12) (param i32) + i32.const 0 + i32.const 4 + local.get 0 + select + i32.const 1 + i32.store + ) + (func (;36;) (type 12) (param i32) + i32.const 8 + i32.const 1 + i32.const 2 + local.get 0 + select + i32.store + ) + (func (;37;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + memory.grow + ) + (func $f (;38;) (type 9) (param i32) (result i32) + local.get 0 + ) + (func (;39;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + call $f + ) + (func (;40;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + return + ) + (func (;41;) (type 12) (param i32) + i32.const 1 + i32.const 2 + local.get 0 + select + drop + ) + (func (;42;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + local.get 0 + select + br 0 (;@1;) + end + ) + (func (;43;) (type 9) (param i32) (result i32) + (local i32) + i32.const 1 + i32.const 2 + local.get 0 + select + local.set 0 + local.get 0 + ) + (func (;44;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + local.tee 0 + ) + (func (;45;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + global.set $a + global.get $a + ) + (func (;46;) (type 9) (param i32) (result i32) + i32.const 0 + i32.const 4 + local.get 0 + select + i32.load + ) + (func (;47;) (type 9) (param i32) (result i32) + i32.const 0 + i32.const 1 + local.get 0 + select + i32.eqz + ) + (func (;48;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + i32.const 1 + i32.const 2 + local.get 0 + select + i32.mul + ) + (func (;49;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.eqz + end + ) + (func (;50;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + local.get 0 + select + i32.const 1 + i32.le_s + end + ) + (func (;51;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.ne + end + ) + (func (;52;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i64.const 1 + i64.const 0 + local.get 0 + select + i32.wrap_i64 + end + ) + (table $tab (;0;) 1 1 funcref) + (table $t (;1;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "select-i32" (func 1)) + (export "select-i64" (func 2)) + (export "select-f32" (func 3)) + (export "select-f64" (func 4)) + (export "select-i32-t" (func 5)) + (export "select-i64-t" (func 6)) + (export "select-f32-t" (func 7)) + (export "select-f64-t" (func 8)) + (export "select-funcref" (func 9)) + (export "select-externref" (func 10)) + (export "join-funcnull" (func 12)) + (export "select-trap-left" (func 13)) + (export "select-trap-right" (func 14)) + (export "select-unreached" (func 15)) + (export "select_unreached_result_1" (func 16)) + (export "select_unreached_result_2" (func 17)) + (export "as-select-first" (func 18)) + (export "as-select-mid" (func 19)) + (export "as-select-last" (func 20)) + (export "as-loop-first" (func 21)) + (export "as-loop-mid" (func 22)) + (export "as-loop-last" (func 23)) + (export "as-if-condition" (func 24)) + (export "as-if-then" (func 25)) + (export "as-if-else" (func 26)) + (export "as-br_if-first" (func 27)) + (export "as-br_if-last" (func 28)) + (export "as-br_table-first" (func 29)) + (export "as-br_table-last" (func 30)) + (export "as-call_indirect-first" (func 32)) + (export "as-call_indirect-mid" (func 33)) + (export "as-call_indirect-last" (func 34)) + (export "as-store-first" (func 35)) + (export "as-store-last" (func 36)) + (export "as-memory.grow-value" (func 37)) + (export "as-call-value" (func 39)) + (export "as-return-value" (func 40)) + (export "as-drop-operand" (func 41)) + (export "as-br-value" (func 42)) + (export "as-local.set-value" (func 43)) + (export "as-local.tee-value" (func 44)) + (export "as-global.set-value" (func 45)) + (export "as-load-operand" (func 46)) + (export "as-unary-operand" (func 47)) + (export "as-binary-operand" (func 48)) + (export "as-test-operand" (func 49)) + (export "as-compare-left" (func 50)) + (export "as-compare-right" (func 51)) + (export "as-convert-operand" (func 52)) + (elem (;0;) (i32.const 0) func $dummy) + (elem (;1;) declare func $tf) + (elem (;2;) (table $t) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/select.wast/131.print b/tests/snapshots/testsuite/proposals/function-references/select.wast/131.print new file mode 100644 index 0000000000..bc8243813e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/select.wast/131.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func $type-unreachable-ref-implicit (;0;) (type 0) + unreachable + i32.const 1 + select + ref.is_null + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/select.wast/156.print b/tests/snapshots/testsuite/proposals/function-references/select.wast/156.print new file mode 100644 index 0000000000..db37a358d8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/select.wast/156.print @@ -0,0 +1,59 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + unreachable + select + ) + (func (;1;) (type 0) (result i32) + unreachable + select + nop + ) + (func (;2;) (type 0) (result i32) + unreachable + select + select + ) + (func (;3;) (type 0) (result i32) + unreachable + select + select + ) + (func (;4;) (type 0) (result i32) + unreachable + select + select + select + ) + (func (;5;) (type 0) (result i32) + unreachable + select (result i32) + ) + (func (;6;) (type 0) (result i32) + unreachable + select (result i32) + ) + (func (;7;) (type 0) (result i32) + unreachable + select (result i32) + select + ) + (func (;8;) (type 0) (result i32) + unreachable + select (result i32) + select (result i32) + ) + (func (;9;) (type 0) (result i32) + unreachable + select + call_indirect (type 1) + ) + (func (;10;) (type 0) (result i32) + unreachable + select + call_indirect (type 1) + select + ) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table-sub.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/table-sub.wast/0.print new file mode 100644 index 0000000000..094a68ac7f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table-sub.wast/0.print @@ -0,0 +1,16 @@ +(module + (type $t (;0;) (func)) + (func $f (;0;) (type $t) + i32.const 0 + i32.const 1 + i32.const 2 + table.init $el + i32.const 0 + i32.const 1 + i32.const 2 + table.copy $t1 $t2 + ) + (table $t1 (;0;) 10 funcref) + (table $t2 (;1;) 10 (ref null 0)) + (elem $el (;0;) funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/0.print new file mode 100644 index 0000000000..328f5cbd46 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/0.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/1.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/1.print new file mode 100644 index 0000000000..56069a92bc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/1.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/10.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/10.print new file mode 100644 index 0000000000..ef6430337b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/10.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (table (;1;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/11.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/11.print new file mode 100644 index 0000000000..e059d68750 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/11.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (table (;1;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/12.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/12.print new file mode 100644 index 0000000000..f955c53e05 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/12.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 funcref ref.null func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/13.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/13.print new file mode 100644 index 0000000000..e64cebdf92 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/13.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref ref.null func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/14.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/14.print new file mode 100644 index 0000000000..e64cebdf92 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/14.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref ref.null func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/2.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/2.print new file mode 100644 index 0000000000..920f0e4379 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/2.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/29.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/29.print new file mode 100644 index 0000000000..4262eacb86 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/29.print @@ -0,0 +1,23 @@ +(module + (type $dummy (;0;) (func)) + (type (;1;) (func (result funcref))) + (func $dummy (;0;) (type $dummy)) + (func (;1;) (type 1) (result funcref) + i32.const 1 + table.get $t1 + ) + (func (;2;) (type 1) (result funcref) + i32.const 4 + table.get $t2 + ) + (func (;3;) (type 1) (result funcref) + i32.const 7 + table.get $t3 + ) + (table $t1 (;0;) 10 funcref) + (table $t2 (;1;) 10 funcref ref.func $dummy) + (table $t3 (;2;) 10 (ref 0) ref.func $dummy) + (export "get1" (func 1)) + (export "get2" (func 2)) + (export "get3" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/3.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/3.print new file mode 100644 index 0000000000..7f97709846 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/3.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/4.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/4.print new file mode 100644 index 0000000000..88fb1c3ca9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/4.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 256 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/5.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/5.print new file mode 100644 index 0000000000..83ff161c50 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/5.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 65536 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/6.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/6.print new file mode 100644 index 0000000000..bade100584 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/6.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 4294967295 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/7.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/7.print new file mode 100644 index 0000000000..56069a92bc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/7.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/8.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/8.print new file mode 100644 index 0000000000..bdac2b62e9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/8.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 externref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/table.wast/9.print b/tests/snapshots/testsuite/proposals/function-references/table.wast/9.print new file mode 100644 index 0000000000..f5cd045ec5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/table.wast/9.print @@ -0,0 +1,4 @@ +(module + (type $t (;0;) (func)) + (table (;0;) 1 (ref null 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/0.print new file mode 100644 index 0000000000..e6e986b450 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/0.print @@ -0,0 +1,14 @@ +(module + (type $t1 (;0;) (func (param f32 f32) (result f32))) + (type $t2 (;1;) (func (param f32 f32) (result f32))) + (type (;2;) (func (param (ref 0)))) + (type (;3;) (func (param (ref 1)))) + (func $f1 (;0;) (type 2) (param $r (ref 0)) + local.get $r + call $f2 + ) + (func $f2 (;1;) (type 3) (param $r (ref 1)) + local.get $r + call $f1 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/1.print b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/1.print new file mode 100644 index 0000000000..4677912b11 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/1.print @@ -0,0 +1,17 @@ +(module + (type $s0 (;0;) (func (param i32) (result f32))) + (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $t1 (;3;) (func (param (ref 1)) (result (ref 2)))) + (type $t2 (;4;) (func (param (ref 2)) (result (ref 1)))) + (type (;5;) (func (param (ref 3)))) + (type (;6;) (func (param (ref 4)))) + (func $f1 (;0;) (type 5) (param $r (ref 3)) + local.get $r + call $f2 + ) + (func $f2 (;1;) (type 6) (param $r (ref 4)) + local.get $r + call $f1 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/10.print b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/10.print new file mode 100644 index 0000000000..ff5f8b66a0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/10.print @@ -0,0 +1,5 @@ +(module + (type $t2 (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param (ref 0)))) + (import "M" "f" (func (;0;) (type 1))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/11.print b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/11.print new file mode 100644 index 0000000000..8dce052a31 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/11.print @@ -0,0 +1,12 @@ +(module + (type $s0 (;0;) (func (param i32) (result f32))) + (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $t1 (;3;) (func (param (ref 1)) (result (ref 2)))) + (type $t2 (;4;) (func (param (ref 2)) (result (ref 1)))) + (type (;5;) (func (param (ref 3)))) + (func (;0;) (type 5) (param (ref 3))) + (func (;1;) (type 5) (param (ref 3))) + (export "f1" (func 0)) + (export "f2" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/13.print b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/13.print new file mode 100644 index 0000000000..e5c72be0ac --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/13.print @@ -0,0 +1,13 @@ +(module + (type $s0 (;0;) (func (param i32) (result f32))) + (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0)))) + (type $t1 (;3;) (func (param (ref 1)) (result (ref 2)))) + (type $t2 (;4;) (func (param (ref 2)) (result (ref 1)))) + (type (;5;) (func (param (ref 3)))) + (type (;6;) (func (param (ref 4)))) + (import "N" "f1" (func (;0;) (type 5))) + (import "N" "f1" (func (;1;) (type 6))) + (import "N" "f2" (func (;2;) (type 5))) + (import "N" "f2" (func (;3;) (type 5))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/4.print b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/4.print new file mode 100644 index 0000000000..51cfc60256 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/4.print @@ -0,0 +1,20 @@ +(module + (type $t1 (;0;) (func (param f32 f32))) + (type $t2 (;1;) (func (param f32 f32))) + (type (;2;) (func)) + (func $f1 (;0;) (type $t1) (param f32 f32)) + (func $f2 (;1;) (type $t2) (param f32 f32)) + (func (;2;) (type 2) + f32.const 0x1p+0 (;=1;) + f32.const 0x1p+1 (;=2;) + i32.const 1 + call_indirect (type $t1) + f32.const 0x1p+0 (;=1;) + f32.const 0x1p+1 (;=2;) + i32.const 0 + call_indirect (type $t2) + ) + (table (;0;) 2 2 funcref) + (export "run" (func 2)) + (elem (;0;) (i32.const 0) func $f1 $f2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/6.print b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/6.print new file mode 100644 index 0000000000..790198e78d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/6.print @@ -0,0 +1,41 @@ +(module + (type $s0 (;0;) (func (param i32))) + (type $s1 (;1;) (func (param i32 (ref 0)))) + (type $s2 (;2;) (func (param i32 (ref 0)))) + (type $t1 (;3;) (func (param (ref 1)))) + (type $t2 (;4;) (func (param (ref 2)))) + (type (;5;) (func)) + (func $s1 (;0;) (type $s1) (param i32 (ref 0))) + (func $s2 (;1;) (type $s2) (param i32 (ref 0))) + (func $f1 (;2;) (type $t1) (param (ref 1))) + (func $f2 (;3;) (type $t2) (param (ref 2))) + (func (;4;) (type 5) + ref.func $s1 + i32.const 0 + call_indirect (type $t1) + ref.func $s1 + i32.const 1 + call_indirect (type $t1) + ref.func $s2 + i32.const 0 + call_indirect (type $t1) + ref.func $s2 + i32.const 1 + call_indirect (type $t1) + ref.func $s1 + i32.const 0 + call_indirect (type $t2) + ref.func $s1 + i32.const 1 + call_indirect (type $t2) + ref.func $s2 + i32.const 0 + call_indirect (type $t2) + ref.func $s2 + i32.const 1 + call_indirect (type $t2) + ) + (table (;0;) 4 4 funcref) + (export "run" (func 4)) + (elem (;0;) (i32.const 0) func $f1 $f2 $s1 $s2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/8.print b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/8.print new file mode 100644 index 0000000000..018898abd6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/type-equivalence.wast/8.print @@ -0,0 +1,6 @@ +(module + (type $t1 (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param (ref 0)))) + (func (;0;) (type 1) (param (ref 0))) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/unreached-valid.wast/0.print b/tests/snapshots/testsuite/proposals/function-references/unreached-valid.wast/0.print new file mode 100644 index 0000000000..9cf18d83b1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/unreached-valid.wast/0.print @@ -0,0 +1,75 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (func (;0;) (type $t) (param $cond i32) (result i32) + unreachable + i32.const 0 + local.get $cond + select + ) + (func (;1;) (type $t) (param $cond i32) (result i32) + i32.const 0 + unreachable + local.get $cond + select + ) + (func (;2;) (type 1) + 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 0x0p+0 (;=0;) + i32.const 0 + select + unreachable + ) + (func (;3;) (type 2) (result i32) + unreachable + select + i32.add + ) + (func (;4;) (type 3) (result i64) + unreachable + i64.const 0 + i32.const 0 + select + i64.add + ) + (func (;5;) (type 1) + unreachable + select + i32.eqz + drop + ) + (func (;6;) (type 1) + unreachable + select + ref.is_null + drop + ) + (func (;7;) (type 2) (result i32) + unreachable + call_ref $t + ) + (export "select-trap-left" (func 0)) + (export "select-trap-right" (func 1)) + (export "select-unreached" (func 2)) + (export "select-unreached-result1" (func 3)) + (export "select-unreached-result2" (func 4)) + (export "select-unreached-num" (func 5)) + (export "select-unreached-ref" (func 6)) + (export "call_ref-unreached" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/function-references/unreached-valid.wast/10.print b/tests/snapshots/testsuite/proposals/function-references/unreached-valid.wast/10.print new file mode 100644 index 0000000000..da1010d5be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/function-references/unreached-valid.wast/10.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block (result f64) ;; label = @1 + block (result f32) ;; label = @2 + unreachable + i32.const 1 + br_table 0 (;@2;) 1 (;@1;) 1 (;@1;) + end + drop + f64.const 0x0p+0 (;=0;) + end + drop + ) + (export "meet-bottom" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/0.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/1.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/103.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/103.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/103.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/108.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/108.print new file mode 100644 index 0000000000..17f0618fdf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/108.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 1 + if ;; label = @2 + i32.const 1 + br_table 2 (;@0;) + end + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/110.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/110.print new file mode 100644 index 0000000000..a2354a64c3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/110.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (start 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/2.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/2.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/2.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/3.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/3.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/3.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/55.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/55.print new file mode 100644 index 0000000000..3171d8f4fb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/55.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local f32 f32) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/60.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/60.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/60.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/61.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/61.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/61.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/68.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/68.print new file mode 100644 index 0000000000..a72fa86b64 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/68.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/69.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/69.print new file mode 100644 index 0000000000..8a3ff91247 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/69.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.null func)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/70.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/70.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/70.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/73.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/73.print new file mode 100644 index 0000000000..c47d05badc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/73.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/82.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/82.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/82.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/87.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/87.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/87.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/93.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/93.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/93.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/96.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/96.print new file mode 100644 index 0000000000..1270a74e97 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/96.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/binary.wast/99.print b/tests/snapshots/testsuite/proposals/gc/binary.wast/99.print new file mode 100644 index 0000000000..a0fe812a51 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/binary.wast/99.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/0.print b/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/0.print new file mode 100644 index 0000000000..f8045bc658 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/0.print @@ -0,0 +1,52 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + block $l (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + i32.const -1 + return + end + call_ref $t + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + block $l (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + i32.const -1 + return + end + call_ref $t + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + block $l (result (ref 0)) ;; label = @1 + unreachable + br_on_non_null 0 (;@1;) + i32.const -1 + return + end + call_ref $t + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/5.print b/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/5.print new file mode 100644 index 0000000000..e8ef804e8e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/5.print @@ -0,0 +1,30 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref null 0)))) + (type (;2;) (func (param funcref))) + (type (;3;) (func (param externref))) + (func (;0;) (type 1) (param $r (ref null 0)) + block (result (ref 0)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) + (func (;1;) (type 2) (param $r funcref) + block (result (ref func)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) + (func (;2;) (type 3) (param $r externref) + block (result (ref extern)) ;; label = @1 + local.get $r + br_on_non_null 0 (;@1;) + unreachable + end + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/6.print b/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/6.print new file mode 100644 index 0000000000..e370706479 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/br_on_non_null.wast/6.print @@ -0,0 +1,32 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 (ref null 0)) (result i32))) + (type (;2;) (func (result i32 (ref 0)))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $a (;1;) (type 1) (param $n i32) (param $r (ref null 0)) (result i32) + block $l (type 2) (result i32 (ref 0)) ;; label = @1 + local.get $n + local.get $r + br_on_non_null 0 (;@1;) + return + end + call_ref $t + ) + (func (;2;) (type $t) (param $n i32) (result i32) + local.get $n + ref.null 0 + call $a + ) + (func (;3;) (type $t) (param $n i32) (result i32) + local.get $n + ref.func $f + call $a + ) + (export "args-null" (func 2)) + (export "args-f" (func 3)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/0.print b/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/0.print new file mode 100644 index 0000000000..fdfd989b2e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/0.print @@ -0,0 +1,52 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + block $l ;; label = @1 + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + block $l ;; label = @1 + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + block $l ;; label = @1 + unreachable + br_on_null 0 (;@1;) + call_ref $t + return + end + i32.const -1 + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/5.print b/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/5.print new file mode 100644 index 0000000000..4dc0b2d305 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/5.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref null 0)))) + (type (;2;) (func (param funcref))) + (type (;3;) (func (param externref))) + (func (;0;) (type 1) (param $r (ref null 0)) + local.get $r + br_on_null 0 (;@0;) + drop + ) + (func (;1;) (type 2) (param $r funcref) + local.get $r + br_on_null 0 (;@0;) + drop + ) + (func (;2;) (type 3) (param $r externref) + local.get $r + br_on_null 0 (;@0;) + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/6.print b/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/6.print new file mode 100644 index 0000000000..8be1657f4f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/br_on_null.wast/6.print @@ -0,0 +1,31 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 (ref null 0)) (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $a (;1;) (type 1) (param $n i32) (param $r (ref null 0)) (result i32) + block $l (result i32) ;; label = @1 + local.get $n + local.get $r + br_on_null 0 (;@1;) + call_ref $t + return + end + ) + (func (;2;) (type $t) (param $n i32) (result i32) + local.get $n + ref.null 0 + call $a + ) + (func (;3;) (type $t) (param $n i32) (result i32) + local.get $n + ref.func $f + call $a + ) + (export "args-null" (func 2)) + (export "args-f" (func 3)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/br_table.wast/0.print b/tests/snapshots/testsuite/proposals/gc/br_table.wast/0.print new file mode 100644 index 0000000000..6c2628a1dc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/br_table.wast/0.print @@ -0,0 +1,928 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type $t (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (type (;4;) (func (result f32))) + (type (;5;) (func (result f64))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (param i32 i32) (result i32))) + (type (;8;) (func (param i32 externref) (result externref))) + (type (;9;) (func (param i32) (result funcref))) + (func $dummy (;0;) (type $t)) + (func (;1;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.ctz + drop + end + ) + (func (;2;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i64.ctz + drop + end + ) + (func (;3;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f32.neg + drop + end + ) + (func (;4;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.neg + drop + end + ) + (func (;5;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.ctz + end + ) + (func (;6;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 2 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i64.ctz + end + ) + (func (;7;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.8p+1 (;=3;) + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f32.neg + end + ) + (func (;8;) (type 5) (result f64) + block (result f64) ;; label = @1 + f64.const 0x1p+2 (;=4;) + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.neg + end + ) + (func (;9;) (type 6) (param i32) (result i32) + block ;; label = @1 + local.get 0 + br_table 0 (;@1;) + i32.const 21 + return + end + i32.const 22 + ) + (func (;10;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 33 + local.get 0 + br_table 0 (;@1;) + i32.const 31 + end + ) + (func (;11;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) + i32.const 21 + return + end + i32.const 20 + return + end + i32.const 22 + ) + (func (;12;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + i32.const 33 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) + i32.const 31 + return + end + drop + i32.const 32 + end + ) + (func (;13;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + local.get 0 + br_table 3 (;@2;) 2 (;@3;) 1 (;@4;) 0 (;@5;) 4 (;@1;) + i32.const 99 + return + end + i32.const 100 + return + end + i32.const 101 + return + end + i32.const 102 + return + end + i32.const 103 + return + end + i32.const 104 + ) + (func (;14;) (type 6) (param i32) (result i32) + (local i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + block (result i32) ;; label = @3 + block (result i32) ;; label = @4 + block (result i32) ;; label = @5 + i32.const 200 + local.get 0 + br_table 3 (;@2;) 2 (;@3;) 1 (;@4;) 0 (;@5;) 4 (;@1;) + local.get 1 + i32.const 99 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 10 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 11 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 12 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 13 + i32.add + return + end + local.set 1 + local.get 1 + i32.const 14 + i32.add + ) + (func (;15;) (type 6) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) 0 (;@2;) 1 (;@1;) + i32.const -1 + return + end + i32.const 0 + return + end + i32.const 1 + return + ) + (func (;16;) (type $t) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + call $dummy + end + ) + (func (;17;) (type $t) + block ;; label = @1 + call $dummy + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + call $dummy + end + ) + (func (;18;) (type $t) + block ;; label = @1 + nop + call $dummy + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;19;) (type 2) (result i32) + block (result i32) ;; label = @1 + nop + call $dummy + i32.const 2 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;20;) (type 2) (result i32) + loop (result i32) ;; label = @1 + i32.const 3 + i32.const 0 + br_table 1 (;@0;) 1 (;@0;) + i32.const 1 + end + ) + (func (;21;) (type 2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 4 + i32.const -1 + br_table 1 (;@0;) 1 (;@0;) 1 (;@0;) + i32.const 2 + end + ) + (func (;22;) (type 2) (result i32) + loop (result i32) ;; label = @1 + nop + call $dummy + i32.const 5 + i32.const 1 + br_table 1 (;@0;) 1 (;@0;) 1 (;@0;) + end + ) + (func (;23;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 9 + i32.const 0 + br_table 0 (;@1;) + br 0 (;@1;) + end + ) + (func (;24;) (type $t) + block ;; label = @1 + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + br_if 0 (;@1;) + end + ) + (func (;25;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 8 + i32.const 0 + br_table 0 (;@1;) + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;26;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 9 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;27;) (type $t) + block ;; label = @1 + i32.const 1 + br_table 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;28;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + i32.const 0 + br_table 0 (;@1;) + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;29;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 11 + i32.const 1 + br_table 0 (;@1;) + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;30;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 7 + i32.const 0 + br_table 0 (;@1;) + return + end + ) + (func (;31;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + br_table 0 (;@1;) + if (result i32) ;; label = @2 + i32.const 0 + else + i32.const 1 + end + end + ) + (func (;32;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + i32.const 3 + i32.const 0 + br_table 1 (;@1;) + else + local.get 1 + end + end + ) + (func (;33;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + local.get 1 + else + i32.const 4 + i32.const 0 + br_table 1 (;@1;) 0 (;@2;) + end + end + ) + (func (;34;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + i32.const 5 + i32.const 0 + br_table 0 (;@1;) + local.get 0 + local.get 1 + select + end + ) + (func (;35;) (type 7) (param i32 i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + i32.const 6 + i32.const 1 + br_table 0 (;@1;) + local.get 1 + select + end + ) + (func (;36;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 7 + i32.const 1 + br_table 0 (;@1;) + select + end + ) + (func $f (;37;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;38;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 12 + i32.const 1 + br_table 0 (;@1;) + i32.const 2 + i32.const 3 + call $f + end + ) + (func (;39;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 13 + i32.const 1 + br_table 0 (;@1;) + i32.const 3 + call $f + end + ) + (func (;40;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 14 + i32.const 1 + br_table 0 (;@1;) + call $f + end + ) + (func (;41;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 20 + i32.const 1 + br_table 0 (;@1;) + i32.const 1 + i32.const 2 + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;42;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 21 + i32.const 1 + br_table 0 (;@1;) + i32.const 2 + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;43;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 22 + i32.const 1 + br_table 0 (;@1;) + i32.const 3 + call_indirect (type $sig) + end + ) + (func (;44;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 2 + i32.const 23 + i32.const 1 + br_table 0 (;@1;) + call_indirect (type $sig) + end + ) + (func (;45;) (type 2) (result i32) + (local f32) + block (result i32) ;; label = @1 + i32.const 17 + i32.const 1 + br_table 0 (;@1;) + local.set 0 + i32.const -1 + end + ) + (func (;46;) (type 2) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_table 0 (;@1;) + local.set 0 + i32.const -1 + end + ) + (func (;47;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 1 + br_table 0 (;@1;) + global.set $a + i32.const -1 + end + ) + (func (;48;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.b33334p+0 (;=1.7;) + i32.const 1 + br_table 0 (;@1;) + f32.load + end + ) + (func (;49;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 30 + i32.const 1 + br_table 0 (;@1;) + i64.load8_s + end + ) + (func (;50;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 30 + i32.const 1 + br_table 0 (;@1;) + f64.const 0x1.cp+2 (;=7;) + f64.store + i32.const -1 + end + ) + (func (;51;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 31 + i32.const 1 + br_table 0 (;@1;) + i64.store + i32.const -1 + end + ) + (func (;52;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 32 + i32.const 0 + br_table 0 (;@1;) + i32.const 7 + i32.store8 + i32.const -1 + end + ) + (func (;53;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 33 + i32.const 0 + br_table 0 (;@1;) + i64.store16 + i32.const -1 + end + ) + (func (;54;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.b33334p+1 (;=3.4;) + i32.const 0 + br_table 0 (;@1;) + f32.neg + end + ) + (func (;55;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i32.const 10 + i32.add + end + ) + (func (;56;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 10 + i64.const 45 + i32.const 0 + br_table 0 (;@1;) + i64.sub + end + ) + (func (;57;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 44 + i32.const 0 + br_table 0 (;@1;) + i32.eqz + end + ) + (func (;58;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 43 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + f64.const 0x1.4p+3 (;=10;) + f64.le + end + ) + (func (;59;) (type 2) (result i32) + block (result i32) ;; label = @1 + f32.const 0x1.4p+3 (;=10;) + i32.const 42 + i32.const 0 + br_table 0 (;@1;) + f32.ne + end + ) + (func (;60;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 41 + i32.const 0 + br_table 0 (;@1;) + i32.wrap_i64 + end + ) + (func (;61;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 40 + i32.const 0 + br_table 0 (;@1;) + memory.grow + end + ) + (func (;62;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const -1 + drop + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + i32.const 16 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.add + end + i32.add + end + i32.add + end + ) + (func (;63;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 2 (;@1;) 1 (;@2;) 0 (;@3;) + br 0 (;@3;) + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;64;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 1 + br_if 0 (;@3;) + drop + i32.const 32 + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;65;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + i32.const 4 + i32.const 8 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) + br_if 0 (;@2;) + drop + i32.const 16 + end + i32.add + end + ) + (func (;66;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + block (result i32) ;; label = @3 + i32.const 4 + drop + i32.const 8 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 1 + br_table 0 (;@3;) + i32.const 32 + end + drop + i32.const 16 + end + i32.add + end + ) + (func (;67;) (type 6) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + block (result i32) ;; label = @2 + i32.const 2 + drop + i32.const 4 + i32.const 8 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) + br_table 0 (;@2;) + i32.const 16 + end + i32.add + end + ) + (func (;68;) (type 6) (param i32) (result i32) + loop (result i32) ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 0 (;@2;) + end + i32.const 0 + end + local.set 0 + loop (result i32) ;; label = @1 + block ;; label = @2 + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 1 (;@1;) + end + i32.const 3 + end + ) + (func (;69;) (type 8) (param i32 externref) (result externref) + block $l1 (result externref) ;; label = @1 + block $l2 (result externref) ;; label = @2 + local.get 1 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;70;) (type $t) + block (result f64) ;; label = @1 + block (result f32) ;; label = @2 + unreachable + i32.const 1 + br_table 0 (;@2;) 1 (;@1;) 1 (;@1;) + end + drop + f64.const 0x0p+0 (;=0;) + end + drop + ) + (func $tf (;71;) (type $t)) + (func (;72;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + i32.const 0 + table.get $t + local.get 0 + br_table 1 (;@1;) 1 (;@1;) 0 (;@2;) + end + end + ) + (func (;73;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + i32.const 0 + table.get $t + local.get 0 + br_table 0 (;@2;) 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;74;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + i32.const 0 + table.get $t + local.get 0 + br_table 0 (;@2;) 1 (;@1;) 0 (;@2;) + end + end + ) + (func (;75;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + i32.const 0 + table.get $t + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;76;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + ref.null 1 + local.get 0 + br_table 1 (;@1;) 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;77;) (type 9) (param i32) (result funcref) + block $l1 (result funcref) ;; label = @1 + block $l2 (result (ref null 1)) ;; label = @2 + block $l3 (result (ref 1)) ;; label = @3 + ref.func $tf + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + end + end + end + ) + (table (;0;) 1 1 funcref) + (table $t (;1;) 1 1 (ref null 1)) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "type-i32" (func 1)) + (export "type-i64" (func 2)) + (export "type-f32" (func 3)) + (export "type-f64" (func 4)) + (export "type-i32-value" (func 5)) + (export "type-i64-value" (func 6)) + (export "type-f32-value" (func 7)) + (export "type-f64-value" (func 8)) + (export "empty" (func 9)) + (export "empty-value" (func 10)) + (export "singleton" (func 11)) + (export "singleton-value" (func 12)) + (export "multiple" (func 13)) + (export "multiple-value" (func 14)) + (export "large" (func 15)) + (export "as-block-first" (func 16)) + (export "as-block-mid" (func 17)) + (export "as-block-last" (func 18)) + (export "as-block-value" (func 19)) + (export "as-loop-first" (func 20)) + (export "as-loop-mid" (func 21)) + (export "as-loop-last" (func 22)) + (export "as-br-value" (func 23)) + (export "as-br_if-cond" (func 24)) + (export "as-br_if-value" (func 25)) + (export "as-br_if-value-cond" (func 26)) + (export "as-br_table-index" (func 27)) + (export "as-br_table-value" (func 28)) + (export "as-br_table-value-index" (func 29)) + (export "as-return-value" (func 30)) + (export "as-if-cond" (func 31)) + (export "as-if-then" (func 32)) + (export "as-if-else" (func 33)) + (export "as-select-first" (func 34)) + (export "as-select-second" (func 35)) + (export "as-select-cond" (func 36)) + (export "as-call-first" (func 38)) + (export "as-call-mid" (func 39)) + (export "as-call-last" (func 40)) + (export "as-call_indirect-first" (func 41)) + (export "as-call_indirect-mid" (func 42)) + (export "as-call_indirect-last" (func 43)) + (export "as-call_indirect-func" (func 44)) + (export "as-local.set-value" (func 45)) + (export "as-local.tee-value" (func 46)) + (export "as-global.set-value" (func 47)) + (export "as-load-address" (func 48)) + (export "as-loadN-address" (func 49)) + (export "as-store-address" (func 50)) + (export "as-store-value" (func 51)) + (export "as-storeN-address" (func 52)) + (export "as-storeN-value" (func 53)) + (export "as-unary-operand" (func 54)) + (export "as-binary-left" (func 55)) + (export "as-binary-right" (func 56)) + (export "as-test-operand" (func 57)) + (export "as-compare-left" (func 58)) + (export "as-compare-right" (func 59)) + (export "as-convert-operand" (func 60)) + (export "as-memory.grow-size" (func 61)) + (export "nested-block-value" (func 62)) + (export "nested-br-value" (func 63)) + (export "nested-br_if-value" (func 64)) + (export "nested-br_if-value-cond" (func 65)) + (export "nested-br_table-value" (func 66)) + (export "nested-br_table-value-index" (func 67)) + (export "nested-br_table-loop-block" (func 68)) + (export "meet-externref" (func 69)) + (export "meet-bottom" (func 70)) + (export "meet-funcref-1" (func 72)) + (export "meet-funcref-2" (func 73)) + (export "meet-funcref-3" (func 74)) + (export "meet-funcref-4" (func 75)) + (export "meet-nullref" (func 76)) + (export "meet-multi-ref" (func 77)) + (elem (;0;) (i32.const 0) func $f) + (elem (;1;) (table $t) (i32.const 0) (ref null 1) (ref.func $tf)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/call_ref.wast/0.print b/tests/snapshots/testsuite/proposals/gc/call_ref.wast/0.print new file mode 100644 index 0000000000..b5339eab8e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/call_ref.wast/0.print @@ -0,0 +1,133 @@ +(module + (type $ii (;0;) (func (param i32) (result i32))) + (type $ll (;1;) (func (param i64) (result i64))) + (type $lll (;2;) (func (param i64 i64) (result i64))) + (type (;3;) (func (param (ref 0) i32) (result i32))) + (type (;4;) (func (result i32))) + (func $apply (;0;) (type 3) (param $f (ref 0)) (param $x i32) (result i32) + local.get $x + local.get $f + call_ref $ii + ) + (func $f (;1;) (type $ii) (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul + ) + (func $g (;2;) (type $ii) (param i32) (result i32) + i32.const 0 + local.get 0 + i32.sub + ) + (func (;3;) (type $ii) (param $x i32) (result i32) + (local $rf (ref null 0)) (local $rg (ref null 0)) + ref.func $f + local.set $rf + ref.func $g + local.set $rg + local.get $x + local.get $rf + call_ref $ii + local.get $rg + call_ref $ii + ) + (func (;4;) (type 4) (result i32) + i32.const 1 + ref.null 0 + call_ref $ii + ) + (func $fac (;5;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + local.get 0 + i64.const 1 + i64.sub + global.get $fac + call_ref $ll + i64.mul + end + ) + (func $fac-acc (;6;) (type $lll) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + global.get $fac-acc + call_ref $lll + end + ) + (func $fib (;7;) (type $ll) (param i64) (result i64) + local.get 0 + i64.const 1 + i64.le_u + if (result i64) ;; label = @1 + i64.const 1 + else + local.get 0 + i64.const 2 + i64.sub + global.get $fib + call_ref $ll + local.get 0 + i64.const 1 + i64.sub + global.get $fib + call_ref $ll + i64.add + end + ) + (func $even (;8;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 44 + else + local.get 0 + i64.const 1 + i64.sub + global.get $odd + call_ref $ll + end + ) + (func $odd (;9;) (type $ll) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 99 + else + local.get 0 + i64.const 1 + i64.sub + global.get $even + call_ref $ll + end + ) + (global $fac (;0;) (ref 1) ref.func $fac) + (global $fac-acc (;1;) (ref 2) ref.func $fac-acc) + (global $fib (;2;) (ref 1) ref.func $fib) + (global $even (;3;) (ref 1) ref.func $even) + (global $odd (;4;) (ref 1) ref.func $odd) + (export "run" (func 3)) + (export "null" (func 4)) + (export "fac" (func $fac)) + (export "fac-acc" (func $fac-acc)) + (export "fib" (func $fib)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) declare func $f $g) + (elem (;1;) declare func $fac) + (elem (;2;) declare func $fac-acc) + (elem (;3;) declare func $fib) + (elem (;4;) declare func $even $odd) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/call_ref.wast/25.print b/tests/snapshots/testsuite/proposals/gc/call_ref.wast/25.print new file mode 100644 index 0000000000..9b733d4659 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/call_ref.wast/25.print @@ -0,0 +1,9 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (result i32))) + (func (;0;) (type 1) (result i32) + unreachable + call_ref $t + ) + (export "unreachable" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/call_ref.wast/27.print b/tests/snapshots/testsuite/proposals/gc/call_ref.wast/27.print new file mode 100644 index 0000000000..3f690c6fbc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/call_ref.wast/27.print @@ -0,0 +1,14 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + ref.func $f + call_ref $t + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/call_ref.wast/29.print b/tests/snapshots/testsuite/proposals/gc/call_ref.wast/29.print new file mode 100644 index 0000000000..89b7ecc289 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/call_ref.wast/29.print @@ -0,0 +1,17 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + i32.const 0 + ref.func $f + call_ref $t + drop + i32.const 0 + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/func.wast/0.print b/tests/snapshots/testsuite/proposals/gc/func.wast/0.print new file mode 100644 index 0000000000..e05dc5fd34 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/func.wast/0.print @@ -0,0 +1,505 @@ +(module + (type $sig (;0;) (func)) + (type $sig-1 (;1;) (func)) + (type $sig-2 (;2;) (func (result i32))) + (type $sig-3 (;3;) (func (param i32))) + (type $sig-4 (;4;) (func (param i32 f64 i32) (result i32))) + (type $forward (;5;) (func)) + (type (;6;) (func (param i32 f64 i64))) + (type (;7;) (func (param i32 f64))) + (type (;8;) (func (param i32 f32 i64 i32 f64))) + (type (;9;) (func (result i32 f64 f32))) + (type (;10;) (func (result i32 f64))) + (type (;11;) (func (result i32 f32 i64 i32 f64))) + (type (;12;) (func (param i32 f32 i64 i32) (result i32 i64 i32))) + (type (;13;) (func (result i64))) + (type (;14;) (func (result f32))) + (type (;15;) (func (result f64))) + (type (;16;) (func (param i32 i32) (result i32))) + (type (;17;) (func (param i64 i64) (result i64))) + (type (;18;) (func (param f32 f32) (result f32))) + (type (;19;) (func (param f64 f64) (result f64))) + (type (;20;) (func (param f32 i32 i64 i32 f64 i32) (result f64))) + (type (;21;) (func (result i32 i32 i32))) + (type (;22;) (func (result i32 i64))) + (type (;23;) (func (param i32) (result i32))) + (type (;24;) (func (param i32) (result i32 i64))) + (type (;25;) (func (param i32) (result f32 i64))) + (type (;26;) (func (param i32) (result i32 i32))) + (type (;27;) (func (result i32 i32))) + (type (;28;) (func (param i32 i64 f32 f32 i32 f64 f32 i32 i32 i32 f32 f64 f64 f64 i32 i32 f32) (result f64 f32 i32 i32 i32 i64 f32 i32 i32 f32 f64 f64 i32 f32 i32 f64))) + (func $dummy (;0;) (type $sig)) + (func (;1;) (type $sig)) + (func (;2;) (type $sig)) + (func $f (;3;) (type $sig)) + (func $h (;4;) (type $sig)) + (func (;5;) (type $sig)) + (func (;6;) (type $sig)) + (func (;7;) (type $sig) + (local i32) + ) + (func (;8;) (type $sig) + (local $x i32) + ) + (func (;9;) (type $sig) + (local i32 f64 i64) + ) + (func (;10;) (type $sig) + (local i32 f64) + ) + (func (;11;) (type $sig) + (local i32 f32) (local $x i64) (local i32 f64) + ) + (func (;12;) (type $sig)) + (func (;13;) (type $sig)) + (func (;14;) (type $sig-3) (param i32)) + (func (;15;) (type $sig-3) (param $x i32)) + (func (;16;) (type 6) (param i32 f64 i64)) + (func (;17;) (type 7) (param i32 f64)) + (func (;18;) (type 8) (param i32 f32) (param $x i64) (param i32 f64)) + (func (;19;) (type $sig)) + (func (;20;) (type $sig)) + (func (;21;) (type $sig-2) (result i32) + unreachable + ) + (func (;22;) (type 9) (result i32 f64 f32) + unreachable + ) + (func (;23;) (type 10) (result i32 f64) + unreachable + ) + (func (;24;) (type 11) (result i32 f32 i64 i32 f64) + unreachable + ) + (func (;25;) (type $sig-1)) + (func (;26;) (type $sig-2) (result i32) + i32.const 0 + ) + (func (;27;) (type $sig-3) (param i32)) + (func (;28;) (type $sig-4) (param i32 f64 i32) (result i32) + i32.const 0 + ) + (func (;29;) (type $sig-2) (result i32) + i32.const 0 + ) + (func (;30;) (type $sig-3) (param i32)) + (func (;31;) (type $sig-4) (param i32 f64 i32) (result i32) + i32.const 0 + ) + (func (;32;) (type $sig)) + (func (;33;) (type $forward)) + (func $complex (;34;) (type 12) (param i32 f32) (param $x i64) (param i32) (result i32 i64 i32) + (local f32) (local $y i32) (local i64 i32 f64 i32) + unreachable + unreachable + ) + (func $complex-sig (;35;) (type $sig) + (local f32) (local $y i32) (local i64 i32 f64 i32) + unreachable + unreachable + ) + (func (;36;) (type $sig-2) (result i32) + (local i32 i32) + local.get 0 + ) + (func (;37;) (type 13) (result i64) + (local i64 i64) + local.get 0 + ) + (func (;38;) (type 14) (result f32) + (local f32 f32) + local.get 0 + ) + (func (;39;) (type 15) (result f64) + (local f64 f64) + local.get 0 + ) + (func (;40;) (type $sig-2) (result i32) + (local i32 i32) + local.get 1 + ) + (func (;41;) (type 13) (result i64) + (local i64 i64) + local.get 1 + ) + (func (;42;) (type 14) (result f32) + (local f32 f32) + local.get 1 + ) + (func (;43;) (type 15) (result f64) + (local f64 f64) + local.get 1 + ) + (func (;44;) (type 15) (result f64) + (local f32) (local $x i32) (local i64 i32 f64 i32) + local.get 0 + f32.neg + drop + local.get $x + i32.eqz + drop + local.get 2 + i64.eqz + drop + local.get 3 + i32.eqz + drop + local.get 4 + f64.neg + drop + local.get 5 + i32.eqz + drop + local.get 4 + ) + (func (;45;) (type 16) (param i32 i32) (result i32) + local.get 0 + ) + (func (;46;) (type 17) (param i64 i64) (result i64) + local.get 0 + ) + (func (;47;) (type 18) (param f32 f32) (result f32) + local.get 0 + ) + (func (;48;) (type 19) (param f64 f64) (result f64) + local.get 0 + ) + (func (;49;) (type 16) (param i32 i32) (result i32) + local.get 1 + ) + (func (;50;) (type 17) (param i64 i64) (result i64) + local.get 1 + ) + (func (;51;) (type 18) (param f32 f32) (result f32) + local.get 1 + ) + (func (;52;) (type 19) (param f64 f64) (result f64) + local.get 1 + ) + (func (;53;) (type 20) (param f32 i32) (param $x i64) (param i32 f64 i32) (result f64) + local.get 0 + f32.neg + drop + local.get 1 + i32.eqz + drop + local.get $x + i64.eqz + drop + local.get 3 + i32.eqz + drop + local.get 4 + f64.neg + drop + local.get 5 + i32.eqz + drop + local.get 4 + ) + (func (;54;) (type $sig)) + (func (;55;) (type $sig) + call $dummy + ) + (func (;56;) (type $sig-2) (result i32) + i32.const 77 + ) + (func (;57;) (type 13) (result i64) + i64.const 7777 + ) + (func (;58;) (type 14) (result f32) + f32.const 0x1.36ccccp+6 (;=77.7;) + ) + (func (;59;) (type 15) (result f64) + f64.const 0x1.37147ae147ae1p+6 (;=77.77;) + ) + (func (;60;) (type 10) (result i32 f64) + i32.const 77 + f64.const 0x1.cp+2 (;=7;) + ) + (func (;61;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + ) + (func (;62;) (type $sig) + block ;; label = @1 + call $dummy + call $dummy + end + ) + (func (;63;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + ) + (func (;64;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + ) + (func (;65;) (type $sig) + return + ) + (func (;66;) (type $sig-2) (result i32) + i32.const 78 + return + ) + (func (;67;) (type 13) (result i64) + i64.const 7878 + return + ) + (func (;68;) (type 14) (result f32) + f32.const 0x1.3accccp+6 (;=78.7;) + return + ) + (func (;69;) (type 15) (result f64) + f64.const 0x1.3b1eb851eb852p+6 (;=78.78;) + return + ) + (func (;70;) (type 10) (result i32 f64) + i32.const 78 + f64.const 0x1.3b1eb851eb852p+6 (;=78.78;) + return + ) + (func (;71;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + return + ) + (func (;72;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + return + ) + (func (;73;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + return + ) + (func (;74;) (type $sig) + br 0 (;@0;) + ) + (func (;75;) (type $sig-2) (result i32) + i32.const 79 + br 0 (;@0;) + ) + (func (;76;) (type 13) (result i64) + i64.const 7979 + br 0 (;@0;) + ) + (func (;77;) (type 14) (result f32) + f32.const 0x1.3f999ap+6 (;=79.9;) + br 0 (;@0;) + ) + (func (;78;) (type 15) (result f64) + f64.const 0x1.3f28f5c28f5c3p+6 (;=79.79;) + br 0 (;@0;) + ) + (func (;79;) (type 10) (result i32 f64) + i32.const 79 + f64.const 0x1.3f28f5c28f5c3p+6 (;=79.79;) + br 0 (;@0;) + ) + (func (;80;) (type 21) (result i32 i32 i32) + i32.const 1 + i32.const 2 + i32.const 3 + br 0 (;@0;) + ) + (func (;81;) (type $sig-2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 77 + end + br 0 (;@0;) + ) + (func (;82;) (type 22) (result i32 i64) + block (type 22) (result i32 i64) ;; label = @1 + call $dummy + i32.const 1 + i64.const 2 + end + br 0 (;@0;) + ) + (func (;83;) (type $sig-3) (param i32) + local.get 0 + br_if 0 (;@0;) + ) + (func (;84;) (type 23) (param i32) (result i32) + i32.const 50 + local.get 0 + br_if 0 (;@0;) + drop + i32.const 51 + ) + (func (;85;) (type 24) (param i32) (result i32 i64) + i32.const 50 + i64.const 51 + local.get 0 + br_if 0 (;@0;) + drop + drop + i32.const 51 + i64.const 52 + ) + (func (;86;) (type $sig-3) (param i32) + local.get 0 + br_table 0 (;@0;) 0 (;@0;) 0 (;@0;) + ) + (func (;87;) (type 23) (param i32) (result i32) + i32.const 50 + local.get 0 + br_table 0 (;@0;) 0 (;@0;) + i32.const 51 + ) + (func (;88;) (type 25) (param i32) (result f32 i64) + f32.const 0x1.9p+5 (;=50;) + i64.const 51 + local.get 0 + br_table 0 (;@0;) 0 (;@0;) + f32.const 0x1.98p+5 (;=51;) + i64.const 52 + ) + (func (;89;) (type $sig-3) (param i32) + block ;; label = @1 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + end + ) + (func (;90;) (type 23) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 50 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + i32.const 51 + end + i32.const 2 + i32.add + ) + (func (;91;) (type 26) (param i32) (result i32 i32) + block (type 27) (result i32 i32) ;; label = @1 + i32.const 50 + i32.const 51 + local.get 0 + br_table 0 (;@1;) 1 (;@0;) 0 (;@1;) + i32.const 51 + i32.const -3 + end + i32.add + i32.const 52 + ) + (func (;92;) (type 28) (param i32 i64 f32 f32 i32 f64 f32 i32 i32 i32 f32 f64 f64 f64 i32 i32 f32) (result f64 f32 i32 i32 i32 i64 f32 i32 i32 f32 f64 f64 i32 f32 i32 f64) + local.get 5 + local.get 2 + local.get 0 + local.get 8 + local.get 7 + local.get 1 + local.get 3 + local.get 9 + local.get 4 + local.get 6 + local.get 13 + local.get 11 + local.get 15 + local.get 16 + local.get 14 + local.get 12 + ) + (func (;93;) (type $sig-2) (result i32) + (local i32) + local.get 0 + ) + (func (;94;) (type 13) (result i64) + (local i64) + local.get 0 + ) + (func (;95;) (type 14) (result f32) + (local f32) + local.get 0 + ) + (func (;96;) (type 15) (result f64) + (local f64) + local.get 0 + ) + (export "f" (func 2)) + (export "g" (func $h)) + (export "type-use-1" (func 25)) + (export "type-use-2" (func 26)) + (export "type-use-3" (func 27)) + (export "type-use-4" (func 28)) + (export "type-use-5" (func 29)) + (export "type-use-6" (func 30)) + (export "type-use-7" (func 31)) + (export "local-first-i32" (func 36)) + (export "local-first-i64" (func 37)) + (export "local-first-f32" (func 38)) + (export "local-first-f64" (func 39)) + (export "local-second-i32" (func 40)) + (export "local-second-i64" (func 41)) + (export "local-second-f32" (func 42)) + (export "local-second-f64" (func 43)) + (export "local-mixed" (func 44)) + (export "param-first-i32" (func 45)) + (export "param-first-i64" (func 46)) + (export "param-first-f32" (func 47)) + (export "param-first-f64" (func 48)) + (export "param-second-i32" (func 49)) + (export "param-second-i64" (func 50)) + (export "param-second-f32" (func 51)) + (export "param-second-f64" (func 52)) + (export "param-mixed" (func 53)) + (export "empty" (func 54)) + (export "value-void" (func 55)) + (export "value-i32" (func 56)) + (export "value-i64" (func 57)) + (export "value-f32" (func 58)) + (export "value-f64" (func 59)) + (export "value-i32-f64" (func 60)) + (export "value-i32-i32-i32" (func 61)) + (export "value-block-void" (func 62)) + (export "value-block-i32" (func 63)) + (export "value-block-i32-i64" (func 64)) + (export "return-empty" (func 65)) + (export "return-i32" (func 66)) + (export "return-i64" (func 67)) + (export "return-f32" (func 68)) + (export "return-f64" (func 69)) + (export "return-i32-f64" (func 70)) + (export "return-i32-i32-i32" (func 71)) + (export "return-block-i32" (func 72)) + (export "return-block-i32-i64" (func 73)) + (export "break-empty" (func 74)) + (export "break-i32" (func 75)) + (export "break-i64" (func 76)) + (export "break-f32" (func 77)) + (export "break-f64" (func 78)) + (export "break-i32-f64" (func 79)) + (export "break-i32-i32-i32" (func 80)) + (export "break-block-i32" (func 81)) + (export "break-block-i32-i64" (func 82)) + (export "break-br_if-empty" (func 83)) + (export "break-br_if-num" (func 84)) + (export "break-br_if-num-num" (func 85)) + (export "break-br_table-empty" (func 86)) + (export "break-br_table-num" (func 87)) + (export "break-br_table-num-num" (func 88)) + (export "break-br_table-nested-empty" (func 89)) + (export "break-br_table-nested-num" (func 90)) + (export "break-br_table-nested-num-num" (func 91)) + (export "large-sig" (func 92)) + (export "init-local-i32" (func 93)) + (export "init-local-i64" (func 94)) + (export "init-local-f32" (func 95)) + (export "init-local-f64" (func 96)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/func.wast/90.print b/tests/snapshots/testsuite/proposals/gc/func.wast/90.print new file mode 100644 index 0000000000..73664e0df9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/func.wast/90.print @@ -0,0 +1,19 @@ +(module + (type $t (;0;) (func (param i32))) + (type (;1;) (func (result f64))) + (type (;2;) (func)) + (func $f (;0;) (type 1) (result f64) + f64.const 0x0p+0 (;=0;) + ) + (func $g (;1;) (type $t) (param i32)) + (func $i32->void (;2;) (type $t) (param i32)) + (func $void->f64 (;3;) (type 1) (result f64) + f64.const 0x0p+0 (;=0;) + ) + (func $check (;4;) (type 2) + i32.const 0 + call $i32->void + call $void->f64 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/func.wast/93.print b/tests/snapshots/testsuite/proposals/gc/func.wast/93.print new file mode 100644 index 0000000000..7748f47f12 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/func.wast/93.print @@ -0,0 +1,25 @@ +(module + (type $proc (;0;) (func (result i32))) + (type $sig (;1;) (func (param i32) (result i32))) + (func (;0;) (type $sig) (param $var i32) (result i32) + (local i32) + local.get 1 + ) + (func $g (;1;) (type $sig) (param $var i32) (result i32) + (local i32) + local.get 1 + ) + (func (;2;) (type $sig) (param i32) (result i32) + local.get 0 + call $g + ) + (func (;3;) (type $proc) (result i32) + (local $var i32) + i32.const 42 + local.set $var + local.get $var + ) + (export "f" (func 0)) + (export "g" (func 2)) + (export "p" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/func.wast/97.print b/tests/snapshots/testsuite/proposals/gc/func.wast/97.print new file mode 100644 index 0000000000..78856df296 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/func.wast/97.print @@ -0,0 +1,83 @@ +(module + (type $sig (;0;) (func)) + (type $empty-sig-duplicate (;1;) (func)) + (type $complex-sig-duplicate (;2;) (func (param i64 i64 f64 i64 f64 i64 f32 i32))) + (type (;3;) (func (param f64 i64 f64 i64 f64 i64 f32 i32))) + (func $empty-sig-1 (;0;) (type $sig)) + (func $complex-sig-1 (;1;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $empty-sig-2 (;2;) (type $sig)) + (func $complex-sig-2 (;3;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-3 (;4;) (type 3) (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-4 (;5;) (type $complex-sig-duplicate) (param i64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-5 (;6;) (type $complex-sig-duplicate) (param i64 i64 f64 i64 f64 i64 f32 i32)) + (func (;7;) (type $sig) + i32.const 1 + call_indirect (type $sig) + i32.const 4 + call_indirect (type $sig) + ) + (func (;8;) (type $sig) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 0 + call_indirect (type 3) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 2 + call_indirect (type 3) + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 3 + call_indirect (type 3) + ) + (func (;9;) (type $sig) + i32.const 1 + call_indirect (type $empty-sig-duplicate) + ) + (func (;10;) (type $sig) + i64.const 0 + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 5 + call_indirect (type $complex-sig-duplicate) + i64.const 0 + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i64.const 0 + f32.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 6 + call_indirect (type $complex-sig-duplicate) + ) + (table (;0;) 7 7 funcref) + (export "signature-explicit-reused" (func 7)) + (export "signature-implicit-reused" (func 8)) + (export "signature-explicit-duplicate" (func 9)) + (export "signature-implicit-duplicate" (func 10)) + (elem (;0;) (i32.const 0) func $complex-sig-3 $empty-sig-2 $complex-sig-1 $complex-sig-3 $empty-sig-1 $complex-sig-4 $complex-sig-5) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/if.wast/0.print b/tests/snapshots/testsuite/proposals/gc/if.wast/0.print new file mode 100644 index 0000000000..148a4b8282 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/if.wast/0.print @@ -0,0 +1,918 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type $block-sig-1 (;1;) (func)) + (type $block-sig-2 (;2;) (func (result i32))) + (type $block-sig-3 (;3;) (func (param i32))) + (type $block-sig-4 (;4;) (func (param i32 f64 i32) (result i32 f64 i32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i32) (result i32 i32))) + (type (;7;) (func (result i32 i64 i32))) + (type (;8;) (func (result i32 i32))) + (type (;9;) (func (result f32 f32))) + (type (;10;) (func (param i32) (result i32 i32 i64))) + (type (;11;) (func (result i32 i32 i64))) + (type (;12;) (func (param i32 i32) (result i32 i32))) + (type (;13;) (func (param i64 i64 i32) (result i64 i32))) + (type (;14;) (func (param i64 i64) (result i64))) + (type (;15;) (func (param i64) (result i64))) + (func $dummy (;0;) (type $block-sig-1)) + (func (;1;) (type $block-sig-3) (param i32) + local.get 0 + if ;; label = @1 + end + local.get 0 + if ;; label = @1 + else + end + local.get 0 + if $l ;; label = @1 + end + local.get 0 + if $l ;; label = @1 + else + end + ) + (func (;2;) (type 5) (param i32) (result i32) + local.get 0 + if ;; label = @1 + nop + end + local.get 0 + if ;; label = @1 + nop + else + nop + end + local.get 0 + if (result i32) ;; label = @1 + i32.const 7 + else + i32.const 8 + end + ) + (func (;3;) (type 6) (param i32) (result i32 i32) + local.get 0 + if ;; label = @1 + call $dummy + call $dummy + call $dummy + end + local.get 0 + if ;; label = @1 + else + call $dummy + call $dummy + call $dummy + end + local.get 0 + if (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 8 + call $dummy + else + call $dummy + call $dummy + i32.const 9 + call $dummy + end + local.get 0 + if (type 7) (result i32 i64 i32) ;; label = @1 + call $dummy + call $dummy + i32.const 1 + call $dummy + call $dummy + call $dummy + i64.const 2 + call $dummy + call $dummy + call $dummy + i32.const 3 + call $dummy + else + call $dummy + call $dummy + i32.const -1 + call $dummy + call $dummy + call $dummy + i64.const -2 + call $dummy + call $dummy + call $dummy + i32.const -3 + call $dummy + end + drop + drop + ) + (func (;4;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 1 + if ;; label = @2 + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if ;; label = @2 + else + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if (result i32) ;; label = @2 + call $dummy + i32.const 9 + else + call $dummy + i32.const 10 + end + else + local.get 1 + if ;; label = @2 + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if ;; label = @2 + else + call $dummy + block ;; label = @3 + end + nop + end + local.get 1 + if (result i32) ;; label = @2 + call $dummy + i32.const 10 + else + call $dummy + i32.const 11 + end + end + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.const 3 + select + ) + (func (;6;) (type 5) (param i32) (result i32) + i32.const 2 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 3 + select + ) + (func (;7;) (type 5) (param i32) (result i32) + i32.const 2 + i32.const 3 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + select + ) + (func (;8;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call $dummy + call $dummy + end + ) + (func (;9;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call $dummy + end + ) + (func (;10;) (type 5) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + end + ) + (func (;11;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + if (result i32) ;; label = @1 + call $dummy + i32.const 2 + else + call $dummy + i32.const 3 + end + ) + (func (;12;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;13;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + br_if 0 (;@1;) + i32.const 3 + return + end + ) + (func (;14;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;15;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;16;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;17;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.const 0 + call_indirect (type $check) + end + ) + (func (;18;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 0 + call_indirect (type $check) + end + ) + (func (;19;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 0 + local.get 0 + if (result i32) ;; label = @2 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + call_indirect (type $check) + end + ) + (func (;20;) (type $block-sig-3) (param i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.const 2 + i32.store + ) + (func (;21;) (type $block-sig-3) (param i32) + i32.const 2 + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 1 + else + call $dummy + i32.const 0 + end + i32.store + ) + (func (;22;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + memory.grow + ) + (func $f (;23;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;24;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + call $f + ) + (func (;25;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + return + ) + (func (;26;) (type $block-sig-3) (param i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + drop + ) + (func (;27;) (type 5) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + if (result i32) ;; label = @2 + i32.const 1 + else + i32.const 0 + end + br 0 (;@1;) + end + ) + (func (;28;) (type 5) (param i32) (result i32) + (local i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + local.set 0 + local.get 0 + ) + (func (;29;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + local.tee 0 + ) + (func (;30;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + global.set $a + global.get $a + ) + (func (;31;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 11 + else + i32.const 10 + end + i32.load + ) + (func (;32;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 13 + else + call $dummy + i32.const -13 + end + i32.ctz + ) + (func (;33;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 3 + else + call $dummy + i32.const -3 + end + local.get 1 + if (result i32) ;; label = @1 + call $dummy + i32.const 4 + else + call $dummy + i32.const -5 + end + i32.mul + ) + (func (;34;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + call $dummy + i32.const 13 + else + call $dummy + i32.const 0 + end + i32.eqz + ) + (func (;35;) (type $check) (param i32 i32) (result i32) + local.get 0 + if (result f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + else + call $dummy + f32.const -0x1.8p+1 (;=-3;) + end + local.get 1 + if (result f32) ;; label = @1 + call $dummy + f32.const 0x1p+2 (;=4;) + else + call $dummy + f32.const -0x1p+2 (;=-4;) + end + f32.gt + ) + (func (;36;) (type 5) (param i32) (result i32) + local.get 0 + if (type 8) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + else + call $dummy + i32.const 3 + call $dummy + i32.const -4 + end + i32.mul + ) + (func (;37;) (type 5) (param i32) (result i32) + local.get 0 + if (type 9) (result f32 f32) ;; label = @1 + call $dummy + f32.const 0x1.8p+1 (;=3;) + call $dummy + f32.const 0x1.8p+1 (;=3;) + else + call $dummy + f32.const -0x1p+1 (;=-2;) + call $dummy + f32.const -0x1.8p+1 (;=-3;) + end + f32.gt + ) + (func (;38;) (type 5) (param i32) (result i32) + local.get 0 + if (type 8) (result i32 i32) ;; label = @1 + call $dummy + i32.const 3 + call $dummy + i32.const 4 + else + call $dummy + i32.const -3 + call $dummy + i32.const -4 + end + i32.const 5 + i32.add + i32.mul + ) + (func (;39;) (type $block-sig-2) (result i32) + i32.const 1 + if ;; label = @1 + br 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + br 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + br 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 1 + br_if 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 1 + br_if 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + i32.const 1 + br_if 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + unreachable + end + i32.const 1 + if ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + unreachable + else + unreachable + end + i32.const 0 + if ;; label = @1 + unreachable + else + i32.const 0 + br_table 0 (;@1;) + unreachable + end + i32.const 19 + ) + (func (;40;) (type 5) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 18 + br 0 (;@1;) + i32.const 19 + else + i32.const 21 + br 0 (;@1;) + i32.const 20 + end + ) + (func (;41;) (type 10) (param i32) (result i32 i32 i64) + local.get 0 + if (type 11) (result i32 i32 i64) ;; label = @1 + i32.const 18 + i32.const -18 + i64.const 18 + br 0 (;@1;) + i32.const 19 + i32.const -19 + i64.const 19 + else + i32.const -18 + i32.const 18 + i64.const -18 + br 0 (;@1;) + i32.const -19 + i32.const 19 + i64.const -19 + end + ) + (func (;42;) (type 5) (param i32) (result i32) + i32.const 1 + local.get 0 + if (type 5) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + else + i32.const -2 + i32.add + end + ) + (func (;43;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + else + i32.sub + end + ) + (func (;44;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type 12) (param i32 i32) (result i32 i32) ;; label = @1 + end + i32.add + ) + (func (;45;) (type 5) (param i32) (result i32) + i32.const 1 + local.get 0 + if (type 5) (param i32) (result i32) ;; label = @1 + i32.const 2 + i32.add + br 0 (;@1;) + else + i32.const -2 + i32.add + br 0 (;@1;) + end + ) + (func (;46;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type $check) (param i32 i32) (result i32) ;; label = @1 + i32.add + br 0 (;@1;) + else + i32.sub + br 0 (;@1;) + end + ) + (func (;47;) (type 5) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + if (type 12) (param i32 i32) (result i32 i32) ;; label = @1 + br 0 (;@1;) + end + i32.add + ) + (func (;48;) (type 5) (param i32) (result i32) + (local i32) + block (result i32) ;; label = @1 + i32.const 1 + local.set 1 + local.get 0 + end + if ;; label = @1 + local.get 1 + i32.const 3 + i32.mul + local.set 1 + local.get 1 + i32.const 5 + i32.sub + local.set 1 + local.get 1 + i32.const 7 + i32.mul + local.set 1 + br 0 (;@1;) + local.get 1 + i32.const 100 + i32.mul + local.set 1 + else + local.get 1 + i32.const 5 + i32.mul + local.set 1 + local.get 1 + i32.const 7 + i32.sub + local.set 1 + local.get 1 + i32.const 3 + i32.mul + local.set 1 + br 0 (;@1;) + local.get 1 + i32.const 1000 + i32.mul + local.set 1 + end + local.get 1 + ) + (func $add64_u_with_carry (;49;) (type 13) (param $i i64) (param $j i64) (param $c i32) (result i64 i32) + (local $k i64) + local.get $i + local.get $j + i64.add + local.get $c + i64.extend_i32_u + i64.add + local.set $k + local.get $k + local.get $k + local.get $i + i64.lt_u + return + ) + (func $add64_u_saturated (;50;) (type 14) (param i64 i64) (result i64) + local.get 0 + local.get 1 + i32.const 0 + call $add64_u_with_carry + if (type 15) (param i64) (result i64) ;; label = @1 + drop + i64.const -1 + end + ) + (func (;51;) (type $block-sig-1) + i32.const 1 + if (type $block-sig-1) ;; label = @1 + end + i32.const 1 + if (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + else + i32.const 2 + end + i32.const 1 + if (type $block-sig-3) (param i32) ;; label = @1 + drop + else + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 1 + if (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + i32.const 1 + if (type $block-sig-2) (result i32) ;; label = @1 + i32.const 0 + else + i32.const 2 + end + i32.const 1 + if (type $block-sig-3) (param i32) ;; label = @1 + drop + else + drop + end + i32.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i32.const 1 + if (type $block-sig-4) (param i32 f64 i32) (result i32 f64 i32) ;; label = @1 + end + drop + drop + drop + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "empty" (func 1)) + (export "singular" (func 2)) + (export "multi" (func 3)) + (export "nested" (func 4)) + (export "as-select-first" (func 5)) + (export "as-select-mid" (func 6)) + (export "as-select-last" (func 7)) + (export "as-loop-first" (func 8)) + (export "as-loop-mid" (func 9)) + (export "as-loop-last" (func 10)) + (export "as-if-condition" (func 11)) + (export "as-br_if-first" (func 12)) + (export "as-br_if-last" (func 13)) + (export "as-br_table-first" (func 14)) + (export "as-br_table-last" (func 15)) + (export "as-call_indirect-first" (func 17)) + (export "as-call_indirect-mid" (func 18)) + (export "as-call_indirect-last" (func 19)) + (export "as-store-first" (func 20)) + (export "as-store-last" (func 21)) + (export "as-memory.grow-value" (func 22)) + (export "as-call-value" (func 24)) + (export "as-return-value" (func 25)) + (export "as-drop-operand" (func 26)) + (export "as-br-value" (func 27)) + (export "as-local.set-value" (func 28)) + (export "as-local.tee-value" (func 29)) + (export "as-global.set-value" (func 30)) + (export "as-load-operand" (func 31)) + (export "as-unary-operand" (func 32)) + (export "as-binary-operand" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-operand" (func 35)) + (export "as-binary-operands" (func 36)) + (export "as-compare-operands" (func 37)) + (export "as-mixed-operands" (func 38)) + (export "break-bare" (func 39)) + (export "break-value" (func 40)) + (export "break-multi-value" (func 41)) + (export "param" (func 42)) + (export "params" (func 43)) + (export "params-id" (func 44)) + (export "param-break" (func 45)) + (export "params-break" (func 46)) + (export "params-id-break" (func 47)) + (export "effects" (func 48)) + (export "add64_u_with_carry" (func $add64_u_with_carry)) + (export "add64_u_saturated" (func $add64_u_saturated)) + (export "type-use" (func 51)) + (elem (;0;) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/0.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/0.print new file mode 100644 index 0000000000..a9214ac0e3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/0.print @@ -0,0 +1,10 @@ +(module $Mf + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + call $g + ) + (func $g (;1;) (type 0) (result i32) + i32.const 2 + ) + (export "call" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/107.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/107.print new file mode 100644 index 0000000000..c3d1cec142 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/107.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (import "Mt" "tab" (table (;0;) 0 funcref)) + (func $f (;0;) (type 0)) + (elem (;0;) (i32.const 9) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/108.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/108.print new file mode 100644 index 0000000000..f11c4feb9d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/108.print @@ -0,0 +1,4 @@ +(module $G1 + (global (;0;) i32 i32.const 5) + (export "g" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/11.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/11.print new file mode 100644 index 0000000000..12315604a6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/11.print @@ -0,0 +1,21 @@ +(module $Mg + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + global.get $glob + ) + (func (;1;) (type 0) (result i32) + global.get $mut_glob + ) + (func (;2;) (type 1) (param i32) + local.get 0 + global.set $mut_glob + ) + (global $glob (;0;) i32 i32.const 42) + (global $mut_glob (;1;) (mut i32) i32.const 142) + (export "glob" (global $glob)) + (export "get" (func 0)) + (export "mut_glob" (global $mut_glob)) + (export "get_mut" (func 1)) + (export "set_mut" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/110.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/110.print new file mode 100644 index 0000000000..5950d0a90b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/110.print @@ -0,0 +1,5 @@ +(module $G2 + (import "G1" "g" (global (;0;) i32)) + (global (;1;) i32 global.get 0) + (export "g" (global 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/120.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/120.print new file mode 100644 index 0000000000..41ada7402e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/120.print @@ -0,0 +1,9 @@ +(module $Mtable_ex + (type $t (;0;) (func)) + (table (;0;) 1 funcref) + (table (;1;) 1 (ref null 0)) + (table (;2;) 1 externref) + (export "t-funcnull" (table 0)) + (export "t-refnull" (table 1)) + (export "t-extern" (table 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/122.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/122.print new file mode 100644 index 0000000000..32615439e4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/122.print @@ -0,0 +1,6 @@ +(module + (type $t (;0;) (func)) + (import "Mtable_ex" "t-funcnull" (table (;0;) 1 funcref)) + (import "Mtable_ex" "t-refnull" (table (;1;) 1 (ref null 0))) + (import "Mtable_ex" "t-extern" (table (;2;) 1 externref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/129.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/129.print new file mode 100644 index 0000000000..4bc82eb617 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/129.print @@ -0,0 +1,11 @@ +(module $Mm + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (memory (;0;) 1 5) + (export "mem" (memory 0)) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/13.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/13.print new file mode 100644 index 0000000000..45ee840475 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/13.print @@ -0,0 +1,20 @@ +(module $Ng + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (import "Mg" "glob" (global $x (;0;) i32)) + (import "Mg" "mut_glob" (global $mut_glob (;1;) (mut i32))) + (import "Mg" "get" (func $f (;0;) (type 0))) + (import "Mg" "get_mut" (func $get_mut (;1;) (type 0))) + (import "Mg" "set_mut" (func $set_mut (;2;) (type 1))) + (func (;3;) (type 0) (result i32) + global.get $glob + ) + (global $glob (;2;) i32 i32.const 43) + (export "Mg.glob" (global $x)) + (export "Mg.get" (func $f)) + (export "glob" (global $glob)) + (export "get" (func 3)) + (export "Mg.mut_glob" (global $mut_glob)) + (export "Mg.get_mut" (func $get_mut)) + (export "Mg.set_mut" (func $set_mut)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/131.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/131.print new file mode 100644 index 0000000000..b2d41df30d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/131.print @@ -0,0 +1,12 @@ +(module $Nm + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "load" (func $loadM (;0;) (type 0))) + (func (;1;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (memory (;0;) 1) + (export "Mm.load" (func $loadM)) + (export "load" (func 1)) + (data (;0;) (i32.const 10) "\f0\f1\f2\f3\f4\f5") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/135.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/135.print new file mode 100644 index 0000000000..31afc29676 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/135.print @@ -0,0 +1,10 @@ +(module $Om + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "mem" (memory (;0;) 1)) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (export "load" (func 0)) + (data (;0;) (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/140.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/140.print new file mode 100644 index 0000000000..56c92a9af5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/140.print @@ -0,0 +1,4 @@ +(module + (import "Mm" "mem" (memory (;0;) 0)) + (data (;0;) (i32.const 65535) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/142.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/142.print new file mode 100644 index 0000000000..17368b7ad7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/142.print @@ -0,0 +1,9 @@ +(module $Pm + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "mem" (memory (;0;) 1 8)) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + memory.grow + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/158.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/158.print new file mode 100644 index 0000000000..24a36bdfab --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/158.print @@ -0,0 +1,17 @@ +(module $Ms + (type $t (;0;) (func (result i32))) + (func (;0;) (type $t) (result i32) + i32.const 0 + i32.load8_u + ) + (func (;1;) (type $t) (result i32) + i32.const 0 + call_indirect (type $t) + ) + (table (;0;) 1 funcref) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "table" (table 0)) + (export "get memory[0]" (func 0)) + (export "get table[0]" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/2.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/2.print new file mode 100644 index 0000000000..20a34e4785 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/2.print @@ -0,0 +1,16 @@ +(module $Nf + (type (;0;) (func (result i32))) + (import "Mf" "call" (func $f (;0;) (type 0))) + (func (;1;) (type 0) (result i32) + call $f + ) + (func (;2;) (type 0) (result i32) + call $g + ) + (func $g (;3;) (type 0) (result i32) + i32.const 3 + ) + (export "Mf.call" (func $f)) + (export "call Mf.call" (func 1)) + (export "call" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/31.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/31.print new file mode 100644 index 0000000000..fe9f49e7d0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/31.print @@ -0,0 +1,25 @@ +(module $Mref_ex + (type $t (;0;) (func)) + (func $f (;0;) (type $t)) + (global (;0;) funcref ref.null func) + (global (;1;) (ref func) ref.func $f) + (global (;2;) (ref null 0) ref.null 0) + (global (;3;) (ref 0) ref.func $f) + (global (;4;) externref ref.null extern) + (global (;5;) (mut funcref) ref.null func) + (global (;6;) (mut (ref func)) ref.func $f) + (global (;7;) (mut (ref null 0)) ref.null 0) + (global (;8;) (mut (ref 0)) ref.func $f) + (global (;9;) (mut externref) ref.null extern) + (export "g-const-funcnull" (global 0)) + (export "g-const-func" (global 1)) + (export "g-const-refnull" (global 2)) + (export "g-const-ref" (global 3)) + (export "g-const-extern" (global 4)) + (export "g-var-funcnull" (global 5)) + (export "g-var-func" (global 6)) + (export "g-var-refnull" (global 7)) + (export "g-var-ref" (global 8)) + (export "g-var-extern" (global 9)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/33.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/33.print new file mode 100644 index 0000000000..f71d4c6a39 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/33.print @@ -0,0 +1,18 @@ +(module $Mref_im + (type $t (;0;) (func)) + (import "Mref_ex" "g-const-funcnull" (global (;0;) funcref)) + (import "Mref_ex" "g-const-func" (global (;1;) funcref)) + (import "Mref_ex" "g-const-refnull" (global (;2;) funcref)) + (import "Mref_ex" "g-const-ref" (global (;3;) funcref)) + (import "Mref_ex" "g-const-func" (global (;4;) (ref func))) + (import "Mref_ex" "g-const-ref" (global (;5;) (ref func))) + (import "Mref_ex" "g-const-refnull" (global (;6;) (ref null 0))) + (import "Mref_ex" "g-const-ref" (global (;7;) (ref null 0))) + (import "Mref_ex" "g-const-ref" (global (;8;) (ref 0))) + (import "Mref_ex" "g-const-extern" (global (;9;) externref)) + (import "Mref_ex" "g-var-funcnull" (global (;10;) (mut funcref))) + (import "Mref_ex" "g-var-func" (global (;11;) (mut (ref func)))) + (import "Mref_ex" "g-var-refnull" (global (;12;) (mut (ref null 0)))) + (import "Mref_ex" "g-var-ref" (global (;13;) (mut (ref 0)))) + (import "Mref_ex" "g-var-extern" (global (;14;) (mut externref))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/65.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/65.print new file mode 100644 index 0000000000..045b7e0e24 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/65.print @@ -0,0 +1,20 @@ +(module $Mt + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (func $g (;0;) (type 0) (result i32) + i32.const 4 + ) + (func (;1;) (type 0) (result i32) + i32.const -4 + ) + (func (;2;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table (;0;) 10 funcref) + (export "tab" (table 0)) + (export "h" (func 1)) + (export "call" (func 2)) + (elem (;0;) (i32.const 2) func $g $g $g $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/67.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/67.print new file mode 100644 index 0000000000..7021967aba --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/67.print @@ -0,0 +1,23 @@ +(module $Nt + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32) (result i32))) + (import "Mt" "call" (func $f (;0;) (type 2))) + (import "Mt" "h" (func $h (;1;) (type 1))) + (func $g (;2;) (type 1) (result i32) + i32.const 5 + ) + (func (;3;) (type 2) (param i32) (result i32) + local.get 0 + call $f + ) + (func (;4;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 1) + ) + (table (;0;) 5 5 funcref) + (export "Mt.call" (func $f)) + (export "call Mt.call" (func 3)) + (export "call" (func 4)) + (elem (;0;) (i32.const 0) func $g $g $g $h $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/7.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/7.print new file mode 100644 index 0000000000..ba4140f49a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/7.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func $f (;0;) (type 0))) + (export "print" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/linking.wast/86.print b/tests/snapshots/testsuite/proposals/gc/linking.wast/86.print new file mode 100644 index 0000000000..a9da3390ae --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/linking.wast/86.print @@ -0,0 +1,15 @@ +(module $Ot + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "Mt" "h" (func $h (;0;) (type 0))) + (import "Mt" "tab" (table (;0;) 5 funcref)) + (func $i (;1;) (type 0) (result i32) + i32.const 6 + ) + (func (;2;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (export "call" (func 2)) + (elem (;0;) (i32.const 1) func $i $h) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/local_get.wast/0.print b/tests/snapshots/testsuite/proposals/gc/local_get.wast/0.print new file mode 100644 index 0000000000..8016de3d6b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/local_get.wast/0.print @@ -0,0 +1,189 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (type (;4;) (func (param i32) (result i32))) + (type (;5;) (func (param i64) (result i64))) + (type (;6;) (func (param f32) (result f32))) + (type (;7;) (func (param f64) (result f64))) + (type (;8;) (func (param i64 f32 f64 i32 i32))) + (type (;9;) (func (param i64 f32 f64 i32 i32) (result f64))) + (func (;0;) (type 0) (result i32) + (local i32) + local.get 0 + ) + (func (;1;) (type 1) (result i64) + (local i64) + local.get 0 + ) + (func (;2;) (type 2) (result f32) + (local f32) + local.get 0 + ) + (func (;3;) (type 3) (result f64) + (local f64) + local.get 0 + ) + (func (;4;) (type 4) (param i32) (result i32) + local.get 0 + ) + (func (;5;) (type 5) (param i64) (result i64) + local.get 0 + ) + (func (;6;) (type 6) (param f32) (result f32) + local.get 0 + ) + (func (;7;) (type 7) (param f64) (result f64) + local.get 0 + ) + (func (;8;) (type 8) (param i64 f32 f64 i32 i32) + (local f32 i64 i64 f64) + local.get 0 + i64.eqz + drop + local.get 1 + f32.neg + drop + local.get 2 + f64.neg + drop + local.get 3 + i32.eqz + drop + local.get 4 + i32.eqz + drop + local.get 5 + f32.neg + drop + local.get 6 + i64.eqz + drop + local.get 7 + i64.eqz + drop + local.get 8 + f64.neg + drop + ) + (func (;9;) (type 9) (param i64 f32 f64 i32 i32) (result f64) + (local f32 i64 i64 f64) + f32.const 0x1.6p+2 (;=5.5;) + local.set 5 + i64.const 6 + local.set 6 + f64.const 0x1p+3 (;=8;) + local.set 8 + local.get 0 + f64.convert_i64_u + local.get 1 + f64.promote_f32 + local.get 2 + local.get 3 + f64.convert_i32_u + local.get 4 + f64.convert_i32_s + local.get 5 + f64.promote_f32 + local.get 6 + f64.convert_i64_u + local.get 7 + f64.convert_i64_u + local.get 8 + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + f64.add + ) + (func (;10;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + end + ) + (func (;11;) (type 4) (param i32) (result i32) + loop (result i32) ;; label = @1 + local.get 0 + end + ) + (func (;12;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + br 0 (;@1;) + end + ) + (func (;13;) (type 4) (param i32) (result i32) + block $l0 (result i32) ;; label = @1 + local.get 0 + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;14;) (type 4) (param i32) (result i32) + block (result i32) ;; label = @1 + local.get 0 + local.get 0 + br_if 0 (;@1;) + end + ) + (func (;15;) (type 4) (param i32) (result i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + i32.const 0 + return + end + i32.const 1 + return + end + i32.const 2 + return + end + i32.const 3 + ) + (func (;16;) (type 4) (param i32) (result i32) + local.get 0 + return + ) + (func (;17;) (type 4) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 0 + else + i32.const 0 + end + ) + (func (;18;) (type 4) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 1 + else + local.get 0 + end + ) + (export "type-local-i32" (func 0)) + (export "type-local-i64" (func 1)) + (export "type-local-f32" (func 2)) + (export "type-local-f64" (func 3)) + (export "type-param-i32" (func 4)) + (export "type-param-i64" (func 5)) + (export "type-param-f32" (func 6)) + (export "type-param-f64" (func 7)) + (export "type-mixed" (func 8)) + (export "read" (func 9)) + (export "as-block-value" (func 10)) + (export "as-loop-value" (func 11)) + (export "as-br-value" (func 12)) + (export "as-br_if-value" (func 13)) + (export "as-br_if-value-cond" (func 14)) + (export "as-br_table-value" (func 15)) + (export "as-return-value" (func 16)) + (export "as-if-then" (func 17)) + (export "as-if-else" (func 18)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/local_init.wast/0.print b/tests/snapshots/testsuite/proposals/gc/local_init.wast/0.print new file mode 100644 index 0000000000..64848a6de7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/local_init.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param (ref extern)) (result (ref extern)))) + (func (;0;) (type 0) (param $p (ref extern)) (result (ref extern)) + (local $x (ref extern)) + local.get $p + local.set $x + local.get $x + ) + (func (;1;) (type 0) (param $p (ref extern)) (result (ref extern)) + (local $x (ref extern)) + local.get $p + local.tee $x + drop + local.get $x + ) + (func (;2;) (type 0) (param $p (ref extern)) (result (ref extern)) + (local $x (ref extern)) + local.get $p + local.set $x + block (result (ref extern)) ;; label = @1 + local.get $x + end + ) + (export "get-after-set" (func 0)) + (export "get-after-tee" (func 1)) + (export "get-in-block-after-set" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/local_init.wast/8.print b/tests/snapshots/testsuite/proposals/gc/local_init.wast/8.print new file mode 100644 index 0000000000..ddfbeff8e1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/local_init.wast/8.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param (ref extern)) (result (ref extern)))) + (func (;0;) (type 0) (param $p (ref extern)) (result (ref extern)) + (local $x (ref extern)) + local.get $p + local.tee $x + drop + local.get $x + ) + (export "tee-init" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref.wast/0.print b/tests/snapshots/testsuite/proposals/gc/ref.wast/0.print new file mode 100644 index 0000000000..8dfe3db26e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref.wast/0.print @@ -0,0 +1,5 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param funcref externref (ref func) (ref extern) (ref 0) (ref 0) (ref 0) (ref 0) funcref externref (ref null 0) (ref null 0)))) + (func (;0;) (type 1) (param funcref externref (ref func) (ref extern) (ref 0) (ref 0) (ref 0) (ref 0) funcref externref (ref null 0) (ref null 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_as_non_null.wast/0.print b/tests/snapshots/testsuite/proposals/gc/ref_as_non_null.wast/0.print new file mode 100644 index 0000000000..d1387d3fa2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_as_non_null.wast/0.print @@ -0,0 +1,40 @@ +(module + (type $t (;0;) (func (result i32))) + (type (;1;) (func (param (ref 0)) (result i32))) + (type (;2;) (func (param (ref null 0)) (result i32))) + (func $nn (;0;) (type 1) (param $r (ref 0)) (result i32) + local.get $r + ref.as_non_null + call_ref $t + ) + (func $n (;1;) (type 2) (param $r (ref null 0)) (result i32) + local.get $r + ref.as_non_null + call_ref $t + ) + (func $f (;2;) (type $t) (result i32) + i32.const 7 + ) + (func (;3;) (type $t) (result i32) + ref.null 0 + call $n + ) + (func (;4;) (type $t) (result i32) + ref.func $f + call $nn + ) + (func (;5;) (type $t) (result i32) + ref.func $f + call $n + ) + (func (;6;) (type $t) (result i32) + unreachable + ref.as_non_null + call $nn + ) + (export "nullable-null" (func 3)) + (export "nonnullable-f" (func 4)) + (export "nullable-f" (func 5)) + (export "unreachable" (func 6)) + (elem (;0;) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_as_non_null.wast/6.print b/tests/snapshots/testsuite/proposals/gc/ref_as_non_null.wast/6.print new file mode 100644 index 0000000000..84c6c3f322 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_as_non_null.wast/6.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref 0)))) + (type (;2;) (func (param (ref func)))) + (type (;3;) (func (param (ref extern)))) + (func (;0;) (type 1) (param $r (ref 0)) + local.get $r + ref.as_non_null + drop + ) + (func (;1;) (type 2) (param $r (ref func)) + local.get $r + ref.as_non_null + drop + ) + (func (;2;) (type 3) (param $r (ref extern)) + local.get $r + ref.as_non_null + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_is_null.wast/0.print b/tests/snapshots/testsuite/proposals/gc/ref_is_null.wast/0.print new file mode 100644 index 0000000000..b021c3b78f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_is_null.wast/0.print @@ -0,0 +1,70 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param funcref) (result i32))) + (type (;2;) (func (param externref) (result i32))) + (type (;3;) (func (param (ref null 0)) (result i32))) + (type (;4;) (func (result i32))) + (type (;5;) (func (param externref))) + (type (;6;) (func (param i32) (result i32))) + (func $dummy (;0;) (type $t)) + (func $f1 (;1;) (type 1) (param $x funcref) (result i32) + local.get $x + ref.is_null + ) + (func $f2 (;2;) (type 2) (param $x externref) (result i32) + local.get $x + ref.is_null + ) + (func $f3 (;3;) (type 3) (param $x (ref null 0)) (result i32) + local.get $x + ref.is_null + ) + (func $f3' (;4;) (type 4) (result i32) + ref.null 0 + call $f3 + ) + (func (;5;) (type 5) (param $r externref) + i32.const 1 + local.get $r + table.set $t2 + ) + (func (;6;) (type $t) + i32.const 1 + ref.null func + table.set $t1 + i32.const 1 + ref.null extern + table.set $t2 + i32.const 1 + ref.null 0 + table.set $t3 + ) + (func (;7;) (type 6) (param $x i32) (result i32) + local.get $x + table.get $t1 + call $f1 + ) + (func (;8;) (type 6) (param $x i32) (result i32) + local.get $x + table.get $t2 + call $f2 + ) + (func (;9;) (type 6) (param $x i32) (result i32) + local.get $x + table.get $t3 + call $f3 + ) + (table $t1 (;0;) 2 funcref) + (table $t2 (;1;) 2 externref) + (table $t3 (;2;) 2 (ref null 0)) + (export "funcref" (func $f1)) + (export "externref" (func $f2)) + (export "ref-null" (func $f3')) + (export "init" (func 5)) + (export "deinit" (func 6)) + (export "funcref-elem" (func 7)) + (export "externref-elem" (func 8)) + (export "ref-elem" (func 9)) + (elem (;0;) (i32.const 1) func $dummy) + (elem (;1;) (table $t3) (i32.const 1) (ref 0) (ref.func $dummy)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_is_null.wast/19.print b/tests/snapshots/testsuite/proposals/gc/ref_is_null.wast/19.print new file mode 100644 index 0000000000..e0896368df --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_is_null.wast/19.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (param (ref 0)))) + (type (;2;) (func (param (ref func)))) + (type (;3;) (func (param (ref extern)))) + (func (;0;) (type 1) (param $r (ref 0)) + local.get $r + ref.is_null + drop + ) + (func (;1;) (type 2) (param $r (ref func)) + local.get $r + ref.is_null + drop + ) + (func (;2;) (type 3) (param $r (ref extern)) + local.get $r + ref.is_null + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_null.wast/0.print b/tests/snapshots/testsuite/proposals/gc/ref_null.wast/0.print new file mode 100644 index 0000000000..e91db7dce2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_null.wast/0.print @@ -0,0 +1,21 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (result anyref))) + (type (;2;) (func (result funcref))) + (type (;3;) (func (result (ref null 0)))) + (func (;0;) (type 1) (result anyref) + ref.null any + ) + (func (;1;) (type 2) (result funcref) + ref.null func + ) + (func (;2;) (type 3) (result (ref null 0)) + ref.null 0 + ) + (global (;0;) anyref ref.null any) + (global (;1;) funcref ref.null func) + (global (;2;) (ref null 0) ref.null 0) + (export "anyref" (func 0)) + (export "funcref" (func 1)) + (export "ref" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_null.wast/4.print b/tests/snapshots/testsuite/proposals/gc/ref_null.wast/4.print new file mode 100644 index 0000000000..06bd88401c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_null.wast/4.print @@ -0,0 +1,52 @@ +(module + (type $t (;0;) (func)) + (type (;1;) (func (result anyref))) + (type (;2;) (func (result nullref))) + (type (;3;) (func (result funcref))) + (type (;4;) (func (result nullfuncref))) + (type (;5;) (func (result externref))) + (type (;6;) (func (result nullexternref))) + (type (;7;) (func (result (ref null 0)))) + (func (;0;) (type 1) (result anyref) + global.get $null + ) + (func (;1;) (type 2) (result nullref) + global.get $null + ) + (func (;2;) (type 3) (result funcref) + global.get $nullfunc + ) + (func (;3;) (type 4) (result nullfuncref) + global.get $nullfunc + ) + (func (;4;) (type 5) (result externref) + global.get $nullextern + ) + (func (;5;) (type 6) (result nullexternref) + global.get $nullextern + ) + (func (;6;) (type 7) (result (ref null 0)) + global.get $nullfunc + ) + (global $null (;0;) nullref ref.null none) + (global $nullfunc (;1;) nullfuncref ref.null nofunc) + (global $nullextern (;2;) nullexternref ref.null noextern) + (global (;3;) anyref ref.null any) + (global (;4;) anyref ref.null none) + (global (;5;) funcref ref.null func) + (global (;6;) funcref ref.null nofunc) + (global (;7;) externref ref.null extern) + (global (;8;) externref ref.null noextern) + (global (;9;) nullref ref.null none) + (global (;10;) nullfuncref ref.null nofunc) + (global (;11;) nullexternref ref.null noextern) + (global (;12;) (ref null 0) ref.null 0) + (global (;13;) (ref null 0) ref.null nofunc) + (export "anyref" (func 0)) + (export "nullref" (func 1)) + (export "funcref" (func 2)) + (export "nullfuncref" (func 3)) + (export "externref" (func 4)) + (export "nullexternref" (func 5)) + (export "ref" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call.wast/0.print b/tests/snapshots/testsuite/proposals/gc/return_call.wast/0.print new file mode 100644 index 0000000000..8deaba4d9b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call.wast/0.print @@ -0,0 +1,167 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (type (;4;) (func (param i32) (result i32))) + (type (;5;) (func (param i64) (result i64))) + (type (;6;) (func (param f32) (result f32))) + (type (;7;) (func (param f64) (result f64))) + (type (;8;) (func (param f32 i32) (result i32))) + (type (;9;) (func (param i32 i64) (result i64))) + (type (;10;) (func (param f64 f32) (result f32))) + (type (;11;) (func (param i64 f64) (result f64))) + (type (;12;) (func (param i64 i64) (result i64))) + (type (;13;) (func (param i64) (result i32))) + (func $const-i32 (;0;) (type 0) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type 1) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type 2) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type 3) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type 4) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type 5) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type 6) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type 7) (param f64) (result f64) + local.get 0 + ) + (func $f32-i32 (;8;) (type 8) (param f32 i32) (result i32) + local.get 1 + ) + (func $i32-i64 (;9;) (type 9) (param i32 i64) (result i64) + local.get 1 + ) + (func $f64-f32 (;10;) (type 10) (param f64 f32) (result f32) + local.get 1 + ) + (func $i64-f64 (;11;) (type 11) (param i64 f64) (result f64) + local.get 1 + ) + (func (;12;) (type 0) (result i32) + return_call $const-i32 + ) + (func (;13;) (type 1) (result i64) + return_call $const-i64 + ) + (func (;14;) (type 2) (result f32) + return_call $const-f32 + ) + (func (;15;) (type 3) (result f64) + return_call $const-f64 + ) + (func (;16;) (type 0) (result i32) + i32.const 32 + return_call $id-i32 + ) + (func (;17;) (type 1) (result i64) + i64.const 64 + return_call $id-i64 + ) + (func (;18;) (type 2) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + return_call $id-f32 + ) + (func (;19;) (type 3) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + return_call $id-f64 + ) + (func (;20;) (type 0) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + return_call $f32-i32 + ) + (func (;21;) (type 1) (result i64) + i32.const 32 + i64.const 64 + return_call $i32-i64 + ) + (func (;22;) (type 2) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + return_call $f64-f32 + ) + (func (;23;) (type 3) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + return_call $i64-f64 + ) + (func $fac-acc (;24;) (type 12) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + return_call $fac-acc + end + ) + (func $count (;25;) (type 5) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 0 + else + local.get 0 + i64.const 1 + i64.sub + return_call $count + end + ) + (func $even (;26;) (type 13) (param i64) (result i32) + local.get 0 + i64.eqz + if (result i32) ;; label = @1 + i32.const 44 + else + local.get 0 + i64.const 1 + i64.sub + return_call $odd + end + ) + (func $odd (;27;) (type 13) (param i64) (result i32) + local.get 0 + i64.eqz + if (result i32) ;; label = @1 + i32.const 99 + else + local.get 0 + i64.const 1 + i64.sub + return_call $even + end + ) + (export "type-i32" (func 12)) + (export "type-i64" (func 13)) + (export "type-f32" (func 14)) + (export "type-f64" (func 15)) + (export "type-first-i32" (func 16)) + (export "type-first-i64" (func 17)) + (export "type-first-f32" (func 18)) + (export "type-first-f64" (func 19)) + (export "type-second-i32" (func 20)) + (export "type-second-i64" (func 21)) + (export "type-second-f32" (func 22)) + (export "type-second-f64" (func 23)) + (export "fac-acc" (func $fac-acc)) + (export "count" (func $count)) + (export "even" (func $even)) + (export "odd" (func $odd)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call.wast/36.print b/tests/snapshots/testsuite/proposals/gc/return_call.wast/36.print new file mode 100644 index 0000000000..cd55a24384 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call.wast/36.print @@ -0,0 +1,8 @@ +(module + (type (;0;) (func)) + (func $arity-1-vs-0 (;0;) (type 0) + i32.const 1 + return_call 1 + ) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call.wast/37.print b/tests/snapshots/testsuite/proposals/gc/return_call.wast/37.print new file mode 100644 index 0000000000..d4be01c6e9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call.wast/37.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func $arity-2-vs-0 (;0;) (type 0) + f64.const 0x1p+1 (;=2;) + i32.const 1 + return_call 1 + ) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/0.print b/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/0.print new file mode 100644 index 0000000000..c8356e64ea --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/0.print @@ -0,0 +1,286 @@ +(module + (type $proc (;0;) (func)) + (type $out-i32 (;1;) (func (result i32))) + (type $out-i64 (;2;) (func (result i64))) + (type $out-f32 (;3;) (func (result f32))) + (type $out-f64 (;4;) (func (result f64))) + (type $over-i32 (;5;) (func (param i32) (result i32))) + (type $over-i64 (;6;) (func (param i64) (result i64))) + (type $over-f32 (;7;) (func (param f32) (result f32))) + (type $over-f64 (;8;) (func (param f64) (result f64))) + (type $f32-i32 (;9;) (func (param f32 i32) (result i32))) + (type $i32-i64 (;10;) (func (param i32 i64) (result i64))) + (type $f64-f32 (;11;) (func (param f64 f32) (result f32))) + (type $i64-f64 (;12;) (func (param i64 f64) (result f64))) + (type $over-i32-duplicate (;13;) (func (param i32) (result i32))) + (type $over-i64-duplicate (;14;) (func (param i64) (result i64))) + (type $over-f32-duplicate (;15;) (func (param f32) (result f32))) + (type $over-f64-duplicate (;16;) (func (param f64) (result f64))) + (type (;17;) (func (param i64))) + (type (;18;) (func (param i64 f64 i32 i64))) + (type (;19;) (func (param i64) (result i32))) + (type (;20;) (func (param i64 f64 i32 i64) (result i32))) + (type (;21;) (func (param i32) (result i64))) + (type (;22;) (func (param i64 i64) (result i64))) + (func $const-i32 (;0;) (type $out-i32) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type $out-i64) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type $out-f32) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type $out-f64) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type $over-i32) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type $over-i64) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type $over-f32) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type $over-f64) (param f64) (result f64) + local.get 0 + ) + (func $i32-i64 (;8;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + ) + (func $i64-f64 (;9;) (type $i64-f64) (param i64 f64) (result f64) + local.get 1 + ) + (func $f32-i32 (;10;) (type $f32-i32) (param f32 i32) (result i32) + local.get 1 + ) + (func $f64-f32 (;11;) (type $f64-f32) (param f64 f32) (result f32) + local.get 1 + ) + (func $over-i32-duplicate (;12;) (type $over-i32-duplicate) (param i32) (result i32) + local.get 0 + ) + (func $over-i64-duplicate (;13;) (type $over-i64-duplicate) (param i64) (result i64) + local.get 0 + ) + (func $over-f32-duplicate (;14;) (type $over-f32-duplicate) (param f32) (result f32) + local.get 0 + ) + (func $over-f64-duplicate (;15;) (type $over-f64-duplicate) (param f64) (result f64) + local.get 0 + ) + (func (;16;) (type $proc) + i32.const 0 + return_call_indirect (type $proc) + i64.const 0 + i32.const 0 + return_call_indirect (type 17) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i32.const 0 + return_call_indirect (type 18) + i32.const 0 + return_call_indirect (type $proc) + ) + (func (;17;) (type $out-i32) (result i32) + i32.const 0 + return_call_indirect (type $out-i32) + i32.const 0 + return_call_indirect (type $out-i32) + i64.const 0 + i32.const 0 + return_call_indirect (type 19) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i32.const 0 + return_call_indirect (type 20) + ) + (func (;18;) (type $out-i64) (result i64) + i64.const 0 + i32.const 0 + return_call_indirect (type $over-i64) + ) + (func (;19;) (type $out-i32) (result i32) + i32.const 0 + return_call_indirect (type $out-i32) + ) + (func (;20;) (type $out-i64) (result i64) + i32.const 1 + return_call_indirect (type $out-i64) + ) + (func (;21;) (type $out-f32) (result f32) + i32.const 2 + return_call_indirect (type $out-f32) + ) + (func (;22;) (type $out-f64) (result f64) + i32.const 3 + return_call_indirect (type $out-f64) + ) + (func (;23;) (type $out-i64) (result i64) + i64.const 100 + i32.const 5 + return_call_indirect (type $over-i64) + ) + (func (;24;) (type $out-i32) (result i32) + i32.const 32 + i32.const 4 + return_call_indirect (type $over-i32) + ) + (func (;25;) (type $out-i64) (result i64) + i64.const 64 + i32.const 5 + return_call_indirect (type $over-i64) + ) + (func (;26;) (type $out-f32) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + i32.const 6 + return_call_indirect (type $over-f32) + ) + (func (;27;) (type $out-f64) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + i32.const 7 + return_call_indirect (type $over-f64) + ) + (func (;28;) (type $out-i32) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + i32.const 8 + return_call_indirect (type $f32-i32) + ) + (func (;29;) (type $out-i64) (result i64) + i32.const 32 + i64.const 64 + i32.const 9 + return_call_indirect (type $i32-i64) + ) + (func (;30;) (type $out-f32) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + i32.const 10 + return_call_indirect (type $f64-f32) + ) + (func (;31;) (type $out-f64) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + i32.const 11 + return_call_indirect (type $i64-f64) + ) + (func (;32;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + local.get 0 + return_call_indirect (type $over-i64) + ) + (func (;33;) (type 21) (param i32) (result i64) + i64.const 9 + local.get 0 + return_call_indirect (type $over-i64-duplicate) + ) + (func $tab-f1 (;34;) (type $out-i32) (result i32) + i32.const 307 + ) + (func $tab-f2 (;35;) (type $out-i32) (result i32) + i32.const 308 + ) + (func (;36;) (type $over-i32) (param $i i32) (result i32) + local.get $i + i32.const 0 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect (type $out-i32) + end + local.get $i + i32.const 1 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect $tab2 (type $out-i32) + end + local.get $i + i32.const 2 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect $tab3 (type $out-i32) + end + i32.const 0 + ) + (func $fac (;37;) (type $over-i64) (param i64) (result i64) + local.get 0 + i64.const 1 + i32.const 13 + return_call_indirect (type 22) + ) + (func $fac-acc (;38;) (type 22) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + i32.const 13 + return_call_indirect (type 22) + end + ) + (func $even (;39;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 44 + else + local.get 0 + i32.const 1 + i32.sub + i32.const 15 + return_call_indirect (type $over-i32) + end + ) + (func $odd (;40;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 99 + else + local.get 0 + i32.const 1 + i32.sub + i32.const 14 + return_call_indirect (type $over-i32) + end + ) + (table (;0;) 20 20 funcref) + (table $tab2 (;1;) 1 1 funcref) + (table $tab3 (;2;) 1 1 funcref) + (export "type-i32" (func 19)) + (export "type-i64" (func 20)) + (export "type-f32" (func 21)) + (export "type-f64" (func 22)) + (export "type-index" (func 23)) + (export "type-first-i32" (func 24)) + (export "type-first-i64" (func 25)) + (export "type-first-f32" (func 26)) + (export "type-first-f64" (func 27)) + (export "type-second-i32" (func 28)) + (export "type-second-i64" (func 29)) + (export "type-second-f32" (func 30)) + (export "type-second-f64" (func 31)) + (export "dispatch" (func 32)) + (export "dispatch-structural" (func 33)) + (export "call-tab" (func 36)) + (export "fac" (func $fac)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) (i32.const 0) 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 $fac $fac-acc $even $odd $over-i32-duplicate $over-i64-duplicate $over-f32-duplicate $over-f64-duplicate) + (elem (;1;) (table $tab2) (i32.const 0) func $tab-f1) + (elem (;2;) (table $tab3) (i32.const 0) func $tab-f2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/64.print b/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/64.print new file mode 100644 index 0000000000..21d17b3e23 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/64.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func $arity-1-vs-0 (;0;) (type 0) + i32.const 1 + i32.const 0 + return_call_indirect (type 0) + ) + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/65.print b/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/65.print new file mode 100644 index 0000000000..c1f5719022 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call_indirect.wast/65.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func $arity-2-vs-0 (;0;) (type 0) + f64.const 0x1p+1 (;=2;) + i32.const 1 + i32.const 0 + return_call_indirect (type 0) + ) + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/0.print b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/0.print new file mode 100644 index 0000000000..fb2a39b0d2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/0.print @@ -0,0 +1,209 @@ +(module + (type $proc (;0;) (func)) + (type $-i32 (;1;) (func (result i32))) + (type $-i64 (;2;) (func (result i64))) + (type $-f32 (;3;) (func (result f32))) + (type $-f64 (;4;) (func (result f64))) + (type $i32-i32 (;5;) (func (param i32) (result i32))) + (type $i64-i64 (;6;) (func (param i64) (result i64))) + (type $f32-f32 (;7;) (func (param f32) (result f32))) + (type $f64-f64 (;8;) (func (param f64) (result f64))) + (type $f32-i32 (;9;) (func (param f32 i32) (result i32))) + (type $i32-i64 (;10;) (func (param i32 i64) (result i64))) + (type $f64-f32 (;11;) (func (param f64 f32) (result f32))) + (type $i64-f64 (;12;) (func (param i64 f64) (result f64))) + (type $i64i64-i64 (;13;) (func (param i64 i64) (result i64))) + (func $const-i32 (;0;) (type $-i32) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type $-i64) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type $-f32) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type $-f64) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type $i32-i32) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type $i64-i64) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type $f32-f32) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type $f64-f64) (param f64) (result f64) + local.get 0 + ) + (func $f32-i32 (;8;) (type $f32-i32) (param f32 i32) (result i32) + local.get 1 + ) + (func $i32-i64 (;9;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + ) + (func $f64-f32 (;10;) (type $f64-f32) (param f64 f32) (result f32) + local.get 1 + ) + (func $i64-f64 (;11;) (type $i64-f64) (param i64 f64) (result f64) + local.get 1 + ) + (func (;12;) (type $-i32) (result i32) + global.get $const-i32 + return_call_ref $-i32 + ) + (func (;13;) (type $-i64) (result i64) + global.get $const-i64 + return_call_ref $-i64 + ) + (func (;14;) (type $-f32) (result f32) + global.get $const-f32 + return_call_ref $-f32 + ) + (func (;15;) (type $-f64) (result f64) + global.get $const-f64 + return_call_ref $-f64 + ) + (func (;16;) (type $-i32) (result i32) + i32.const 32 + global.get $id-i32 + return_call_ref $i32-i32 + ) + (func (;17;) (type $-i64) (result i64) + i64.const 64 + global.get $id-i64 + return_call_ref $i64-i64 + ) + (func (;18;) (type $-f32) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + global.get $id-f32 + return_call_ref $f32-f32 + ) + (func (;19;) (type $-f64) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + global.get $id-f64 + return_call_ref $f64-f64 + ) + (func (;20;) (type $-i32) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + global.get $f32-i32 + return_call_ref $f32-i32 + ) + (func (;21;) (type $-i64) (result i64) + i32.const 32 + i64.const 64 + global.get $i32-i64 + return_call_ref $i32-i64 + ) + (func (;22;) (type $-f32) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + global.get $f64-f32 + return_call_ref $f64-f32 + ) + (func (;23;) (type $-f64) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + global.get $i64-f64 + return_call_ref $i64-f64 + ) + (func (;24;) (type $proc) + ref.null 0 + return_call_ref $proc + ) + (func $fac-acc (;25;) (type $i64i64-i64) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + global.get $fac-acc + return_call_ref $i64i64-i64 + end + ) + (func $count (;26;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 0 + else + local.get 0 + i64.const 1 + i64.sub + global.get $count + return_call_ref $i64-i64 + end + ) + (func $even (;27;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 44 + else + local.get 0 + i64.const 1 + i64.sub + global.get $odd + return_call_ref $i64-i64 + end + ) + (func $odd (;28;) (type $i64-i64) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + i64.const 99 + else + local.get 0 + i64.const 1 + i64.sub + global.get $even + return_call_ref $i64-i64 + end + ) + (global $const-i32 (;0;) (ref 1) ref.func $const-i32) + (global $const-i64 (;1;) (ref 2) ref.func $const-i64) + (global $const-f32 (;2;) (ref 3) ref.func $const-f32) + (global $const-f64 (;3;) (ref 4) ref.func $const-f64) + (global $id-i32 (;4;) (ref 5) ref.func $id-i32) + (global $id-i64 (;5;) (ref 6) ref.func $id-i64) + (global $id-f32 (;6;) (ref 7) ref.func $id-f32) + (global $id-f64 (;7;) (ref 8) ref.func $id-f64) + (global $f32-i32 (;8;) (ref 9) ref.func $f32-i32) + (global $i32-i64 (;9;) (ref 10) ref.func $i32-i64) + (global $f64-f32 (;10;) (ref 11) ref.func $f64-f32) + (global $i64-f64 (;11;) (ref 12) ref.func $i64-f64) + (global $fac-acc (;12;) (ref 13) ref.func $fac-acc) + (global $count (;13;) (ref 6) ref.func $count) + (global $even (;14;) (ref 6) ref.func $even) + (global $odd (;15;) (ref 6) ref.func $odd) + (export "type-i32" (func 12)) + (export "type-i64" (func 13)) + (export "type-f32" (func 14)) + (export "type-f64" (func 15)) + (export "type-first-i32" (func 16)) + (export "type-first-i64" (func 17)) + (export "type-first-f32" (func 18)) + (export "type-first-f64" (func 19)) + (export "type-second-i32" (func 20)) + (export "type-second-i64" (func 21)) + (export "type-second-f32" (func 22)) + (export "type-second-f64" (func 23)) + (export "null" (func 24)) + (export "fac-acc" (func $fac-acc)) + (export "count" (func $count)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) 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) + (elem (;1;) declare func $fac-acc) + (elem (;2;) declare func $count) + (elem (;3;) declare func $even) + (elem (;4;) declare func $odd) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/33.print b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/33.print new file mode 100644 index 0000000000..db9c9d6516 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/33.print @@ -0,0 +1,44 @@ +(module + (type $t (;0;) (func)) + (type $t1 (;1;) (func (result (ref 0)))) + (type $t2 (;2;) (func (result (ref null 0)))) + (type $t3 (;3;) (func (result (ref func)))) + (type $t4 (;4;) (func (result funcref))) + (func $f11 (;0;) (type $t1) (result (ref 0)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f21 (;1;) (type $t2) (result (ref null 0)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f22 (;2;) (type $t2) (result (ref null 0)) + ref.func $f22 + return_call_ref $t2 + ) + (func $f31 (;3;) (type $t3) (result (ref func)) + ref.func $f11 + return_call_ref $t1 + ) + (func $f33 (;4;) (type $t3) (result (ref func)) + ref.func $f33 + return_call_ref $t3 + ) + (func $f41 (;5;) (type $t4) (result funcref) + ref.func $f11 + return_call_ref $t1 + ) + (func $f42 (;6;) (type $t4) (result funcref) + ref.func $f22 + return_call_ref $t2 + ) + (func $f43 (;7;) (type $t4) (result funcref) + ref.func $f33 + return_call_ref $t3 + ) + (func $f44 (;8;) (type $t4) (result funcref) + ref.func $f44 + return_call_ref $t4 + ) + (elem (;0;) declare func $f11 $f22 $f33 $f44) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/40.print b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/40.print new file mode 100644 index 0000000000..70ed02cc52 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/40.print @@ -0,0 +1,8 @@ +(module + (type $t (;0;) (func (result i32))) + (func (;0;) (type $t) (result i32) + unreachable + return_call_ref $t + ) + (export "unreachable" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/42.print b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/42.print new file mode 100644 index 0000000000..09c8e10bb9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/42.print @@ -0,0 +1,14 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + ref.func $f + return_call_ref $t + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/44.print b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/44.print new file mode 100644 index 0000000000..97eaf8fe20 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/return_call_ref.wast/44.print @@ -0,0 +1,16 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $f (;0;) (type $t) (param i32) (result i32) + local.get 0 + ) + (func (;1;) (type 1) (result i32) + unreachable + i32.const 0 + ref.func $f + return_call_ref $t + i32.const 0 + ) + (export "unreachable" (func 1)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/select.wast/0.print b/tests/snapshots/testsuite/proposals/gc/select.wast/0.print new file mode 100644 index 0000000000..114048621b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/select.wast/0.print @@ -0,0 +1,491 @@ +(module + (type $t (;0;) (func)) + (type $check (;1;) (func (param i32 i32) (result i32))) + (type (;2;) (func (param i32 i32 i32) (result i32))) + (type (;3;) (func (param i64 i64 i32) (result i64))) + (type (;4;) (func (param f32 f32 i32) (result f32))) + (type (;5;) (func (param f64 f64 i32) (result f64))) + (type (;6;) (func (param funcref funcref i32) (result funcref))) + (type (;7;) (func (param externref externref i32) (result externref))) + (type (;8;) (func (param i32) (result funcref))) + (type (;9;) (func (param i32) (result i32))) + (type (;10;) (func (result i32))) + (type (;11;) (func (result i64))) + (type (;12;) (func (param i32))) + (func $dummy (;0;) (type $t)) + (func (;1;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;2;) (type 3) (param i64 i64 i32) (result i64) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;3;) (type 4) (param f32 f32 i32) (result f32) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;4;) (type 5) (param f64 f64 i32) (result f64) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;5;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + select (result i32) + ) + (func (;6;) (type 3) (param i64 i64 i32) (result i64) + local.get 0 + local.get 1 + local.get 2 + select (result i64) + ) + (func (;7;) (type 4) (param f32 f32 i32) (result f32) + local.get 0 + local.get 1 + local.get 2 + select (result f32) + ) + (func (;8;) (type 5) (param f64 f64 i32) (result f64) + local.get 0 + local.get 1 + local.get 2 + select (result f64) + ) + (func (;9;) (type 6) (param funcref funcref i32) (result funcref) + local.get 0 + local.get 1 + local.get 2 + select (result funcref) + ) + (func (;10;) (type 7) (param externref externref i32) (result externref) + local.get 0 + local.get 1 + local.get 2 + select (result externref) + ) + (func $tf (;11;) (type $t)) + (func (;12;) (type 8) (param i32) (result funcref) + ref.func $tf + ref.null func + local.get 0 + select (result funcref) + ) + (func (;13;) (type 9) (param $cond i32) (result i32) + unreachable + i32.const 0 + local.get $cond + select + ) + (func (;14;) (type 9) (param $cond i32) (result i32) + i32.const 0 + unreachable + local.get $cond + select + ) + (func (;15;) (type $t) + 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 0x0p+0 (;=0;) + i32.const 0 + select + unreachable + ) + (func (;16;) (type 10) (result i32) + unreachable + select + i32.add + ) + (func (;17;) (type 11) (result i64) + unreachable + i64.const 0 + i32.const 0 + select + i64.add + ) + (func (;18;) (type 9) (param i32) (result i32) + i32.const 0 + i32.const 1 + local.get 0 + select + i32.const 2 + i32.const 3 + select + ) + (func (;19;) (type 9) (param i32) (result i32) + i32.const 2 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.const 3 + select + ) + (func (;20;) (type 9) (param i32) (result i32) + i32.const 2 + i32.const 3 + i32.const 0 + i32.const 1 + local.get 0 + select + select + ) + (func (;21;) (type 9) (param i32) (result i32) + loop (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + call $dummy + call $dummy + end + ) + (func (;22;) (type 9) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 2 + i32.const 3 + local.get 0 + select + call $dummy + end + ) + (func (;23;) (type 9) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 2 + i32.const 3 + local.get 0 + select + end + ) + (func (;24;) (type 12) (param i32) + i32.const 2 + i32.const 3 + local.get 0 + select + if ;; label = @1 + call $dummy + end + ) + (func (;25;) (type 9) (param i32) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + else + i32.const 4 + end + ) + (func (;26;) (type 9) (param i32) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 2 + else + i32.const 2 + i32.const 3 + local.get 0 + select + end + ) + (func (;27;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 4 + br_if 0 (;@1;) + end + ) + (func (;28;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 2 + i32.const 3 + local.get 0 + select + br_if 0 (;@1;) + end + ) + (func (;29;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;30;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 2 + i32.const 3 + local.get 0 + select + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;31;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;32;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 1 + i32.const 0 + call_indirect $t (type $check) + end + ) + (func (;33;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 0 + call_indirect $t (type $check) + end + ) + (func (;34;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 4 + i32.const 2 + i32.const 3 + local.get 0 + select + call_indirect $t (type $check) + end + ) + (func (;35;) (type 12) (param i32) + i32.const 0 + i32.const 4 + local.get 0 + select + i32.const 1 + i32.store + ) + (func (;36;) (type 12) (param i32) + i32.const 8 + i32.const 1 + i32.const 2 + local.get 0 + select + i32.store + ) + (func (;37;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + memory.grow + ) + (func $f (;38;) (type 9) (param i32) (result i32) + local.get 0 + ) + (func (;39;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + call $f + ) + (func (;40;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + return + ) + (func (;41;) (type 12) (param i32) + i32.const 1 + i32.const 2 + local.get 0 + select + drop + ) + (func (;42;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + local.get 0 + select + br 0 (;@1;) + end + ) + (func (;43;) (type 9) (param i32) (result i32) + (local i32) + i32.const 1 + i32.const 2 + local.get 0 + select + local.set 0 + local.get 0 + ) + (func (;44;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + local.tee 0 + ) + (func (;45;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + global.set $a + global.get $a + ) + (func (;46;) (type 9) (param i32) (result i32) + i32.const 0 + i32.const 4 + local.get 0 + select + i32.load + ) + (func (;47;) (type 9) (param i32) (result i32) + i32.const 0 + i32.const 1 + local.get 0 + select + i32.eqz + ) + (func (;48;) (type 9) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + i32.const 1 + i32.const 2 + local.get 0 + select + i32.mul + ) + (func (;49;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.eqz + end + ) + (func (;50;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + local.get 0 + select + i32.const 1 + i32.le_s + end + ) + (func (;51;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.ne + end + ) + (func (;52;) (type 9) (param i32) (result i32) + block (result i32) ;; label = @1 + i64.const 1 + i64.const 0 + local.get 0 + select + i32.wrap_i64 + end + ) + (table $tab (;0;) 1 1 funcref) + (table $t (;1;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "select-i32" (func 1)) + (export "select-i64" (func 2)) + (export "select-f32" (func 3)) + (export "select-f64" (func 4)) + (export "select-i32-t" (func 5)) + (export "select-i64-t" (func 6)) + (export "select-f32-t" (func 7)) + (export "select-f64-t" (func 8)) + (export "select-funcref" (func 9)) + (export "select-externref" (func 10)) + (export "join-funcnull" (func 12)) + (export "select-trap-left" (func 13)) + (export "select-trap-right" (func 14)) + (export "select-unreached" (func 15)) + (export "select_unreached_result_1" (func 16)) + (export "select_unreached_result_2" (func 17)) + (export "as-select-first" (func 18)) + (export "as-select-mid" (func 19)) + (export "as-select-last" (func 20)) + (export "as-loop-first" (func 21)) + (export "as-loop-mid" (func 22)) + (export "as-loop-last" (func 23)) + (export "as-if-condition" (func 24)) + (export "as-if-then" (func 25)) + (export "as-if-else" (func 26)) + (export "as-br_if-first" (func 27)) + (export "as-br_if-last" (func 28)) + (export "as-br_table-first" (func 29)) + (export "as-br_table-last" (func 30)) + (export "as-call_indirect-first" (func 32)) + (export "as-call_indirect-mid" (func 33)) + (export "as-call_indirect-last" (func 34)) + (export "as-store-first" (func 35)) + (export "as-store-last" (func 36)) + (export "as-memory.grow-value" (func 37)) + (export "as-call-value" (func 39)) + (export "as-return-value" (func 40)) + (export "as-drop-operand" (func 41)) + (export "as-br-value" (func 42)) + (export "as-local.set-value" (func 43)) + (export "as-local.tee-value" (func 44)) + (export "as-global.set-value" (func 45)) + (export "as-load-operand" (func 46)) + (export "as-unary-operand" (func 47)) + (export "as-binary-operand" (func 48)) + (export "as-test-operand" (func 49)) + (export "as-compare-left" (func 50)) + (export "as-compare-right" (func 51)) + (export "as-convert-operand" (func 52)) + (elem (;0;) (i32.const 0) func $dummy) + (elem (;1;) declare func $tf) + (elem (;2;) (table $t) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/select.wast/131.print b/tests/snapshots/testsuite/proposals/gc/select.wast/131.print new file mode 100644 index 0000000000..bc8243813e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/select.wast/131.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func $type-unreachable-ref-implicit (;0;) (type 0) + unreachable + i32.const 1 + select + ref.is_null + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/select.wast/156.print b/tests/snapshots/testsuite/proposals/gc/select.wast/156.print new file mode 100644 index 0000000000..db37a358d8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/select.wast/156.print @@ -0,0 +1,59 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + unreachable + select + ) + (func (;1;) (type 0) (result i32) + unreachable + select + nop + ) + (func (;2;) (type 0) (result i32) + unreachable + select + select + ) + (func (;3;) (type 0) (result i32) + unreachable + select + select + ) + (func (;4;) (type 0) (result i32) + unreachable + select + select + select + ) + (func (;5;) (type 0) (result i32) + unreachable + select (result i32) + ) + (func (;6;) (type 0) (result i32) + unreachable + select (result i32) + ) + (func (;7;) (type 0) (result i32) + unreachable + select (result i32) + select + ) + (func (;8;) (type 0) (result i32) + unreachable + select (result i32) + select (result i32) + ) + (func (;9;) (type 0) (result i32) + unreachable + select + call_indirect (type 1) + ) + (func (;10;) (type 0) (result i32) + unreachable + select + call_indirect (type 1) + select + ) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table-sub.wast/0.print b/tests/snapshots/testsuite/proposals/gc/table-sub.wast/0.print new file mode 100644 index 0000000000..094a68ac7f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table-sub.wast/0.print @@ -0,0 +1,16 @@ +(module + (type $t (;0;) (func)) + (func $f (;0;) (type $t) + i32.const 0 + i32.const 1 + i32.const 2 + table.init $el + i32.const 0 + i32.const 1 + i32.const 2 + table.copy $t1 $t2 + ) + (table $t1 (;0;) 10 funcref) + (table $t2 (;1;) 10 (ref null 0)) + (elem $el (;0;) funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/0.print b/tests/snapshots/testsuite/proposals/gc/table.wast/0.print new file mode 100644 index 0000000000..328f5cbd46 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/0.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/1.print b/tests/snapshots/testsuite/proposals/gc/table.wast/1.print new file mode 100644 index 0000000000..56069a92bc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/1.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/10.print b/tests/snapshots/testsuite/proposals/gc/table.wast/10.print new file mode 100644 index 0000000000..ef6430337b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/10.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (table (;1;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/11.print b/tests/snapshots/testsuite/proposals/gc/table.wast/11.print new file mode 100644 index 0000000000..e059d68750 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/11.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (table (;1;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/12.print b/tests/snapshots/testsuite/proposals/gc/table.wast/12.print new file mode 100644 index 0000000000..f955c53e05 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/12.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 funcref ref.null func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/13.print b/tests/snapshots/testsuite/proposals/gc/table.wast/13.print new file mode 100644 index 0000000000..e64cebdf92 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/13.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref ref.null func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/14.print b/tests/snapshots/testsuite/proposals/gc/table.wast/14.print new file mode 100644 index 0000000000..e64cebdf92 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/14.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref ref.null func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/2.print b/tests/snapshots/testsuite/proposals/gc/table.wast/2.print new file mode 100644 index 0000000000..920f0e4379 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/2.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/29.print b/tests/snapshots/testsuite/proposals/gc/table.wast/29.print new file mode 100644 index 0000000000..4262eacb86 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/29.print @@ -0,0 +1,23 @@ +(module + (type $dummy (;0;) (func)) + (type (;1;) (func (result funcref))) + (func $dummy (;0;) (type $dummy)) + (func (;1;) (type 1) (result funcref) + i32.const 1 + table.get $t1 + ) + (func (;2;) (type 1) (result funcref) + i32.const 4 + table.get $t2 + ) + (func (;3;) (type 1) (result funcref) + i32.const 7 + table.get $t3 + ) + (table $t1 (;0;) 10 funcref) + (table $t2 (;1;) 10 funcref ref.func $dummy) + (table $t3 (;2;) 10 (ref 0) ref.func $dummy) + (export "get1" (func 1)) + (export "get2" (func 2)) + (export "get3" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/3.print b/tests/snapshots/testsuite/proposals/gc/table.wast/3.print new file mode 100644 index 0000000000..7f97709846 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/3.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/4.print b/tests/snapshots/testsuite/proposals/gc/table.wast/4.print new file mode 100644 index 0000000000..88fb1c3ca9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/4.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 256 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/5.print b/tests/snapshots/testsuite/proposals/gc/table.wast/5.print new file mode 100644 index 0000000000..83ff161c50 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/5.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 65536 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/6.print b/tests/snapshots/testsuite/proposals/gc/table.wast/6.print new file mode 100644 index 0000000000..bade100584 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/6.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 4294967295 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/7.print b/tests/snapshots/testsuite/proposals/gc/table.wast/7.print new file mode 100644 index 0000000000..56069a92bc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/7.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/8.print b/tests/snapshots/testsuite/proposals/gc/table.wast/8.print new file mode 100644 index 0000000000..bdac2b62e9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/8.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 externref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/table.wast/9.print b/tests/snapshots/testsuite/proposals/gc/table.wast/9.print new file mode 100644 index 0000000000..f5cd045ec5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/table.wast/9.print @@ -0,0 +1,4 @@ +(module + (type $t (;0;) (func)) + (table (;0;) 1 (ref null 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/type-canon.wast/0.print b/tests/snapshots/testsuite/proposals/gc/type-canon.wast/0.print new file mode 100644 index 0000000000..fdb8f5609e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/type-canon.wast/0.print @@ -0,0 +1,7 @@ +(module + (rec + (type $t1 (;0;) (func (param i32 (ref 2)))) + (type $t2 (;1;) (func (param i32 (ref 0)))) + (type $t3 (;2;) (func (param i32 (ref 1)))) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/type-canon.wast/1.print b/tests/snapshots/testsuite/proposals/gc/type-canon.wast/1.print new file mode 100644 index 0000000000..704f2fdd2a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/type-canon.wast/1.print @@ -0,0 +1,9 @@ +(module + (rec + (type $t0 (;0;) (func (param i32 (ref 2) (ref 3)))) + (type $t1 (;1;) (func (param i32 (ref 0) i32 (ref 4)))) + (type $t2 (;2;) (func (param i32 (ref 2) (ref 1)))) + (type $t3 (;3;) (func (param i32 (ref 2) i32 (ref 4)))) + (type $t4 (;4;) (func (param (ref 0) (ref 2)))) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/0.print b/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/0.print new file mode 100644 index 0000000000..9cf18d83b1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/0.print @@ -0,0 +1,75 @@ +(module + (type $t (;0;) (func (param i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (func (;0;) (type $t) (param $cond i32) (result i32) + unreachable + i32.const 0 + local.get $cond + select + ) + (func (;1;) (type $t) (param $cond i32) (result i32) + i32.const 0 + unreachable + local.get $cond + select + ) + (func (;2;) (type 1) + 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 0x0p+0 (;=0;) + i32.const 0 + select + unreachable + ) + (func (;3;) (type 2) (result i32) + unreachable + select + i32.add + ) + (func (;4;) (type 3) (result i64) + unreachable + i64.const 0 + i32.const 0 + select + i64.add + ) + (func (;5;) (type 1) + unreachable + select + i32.eqz + drop + ) + (func (;6;) (type 1) + unreachable + select + ref.is_null + drop + ) + (func (;7;) (type 2) (result i32) + unreachable + call_ref $t + ) + (export "select-trap-left" (func 0)) + (export "select-trap-right" (func 1)) + (export "select-unreached" (func 2)) + (export "select-unreached-result1" (func 3)) + (export "select-unreached-result2" (func 4)) + (export "select-unreached-num" (func 5)) + (export "select-unreached-ref" (func 6)) + (export "call_ref-unreached" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/10.print b/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/10.print new file mode 100644 index 0000000000..da1010d5be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/10.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block (result f64) ;; label = @1 + block (result f32) ;; label = @2 + unreachable + i32.const 1 + br_table 0 (;@2;) 1 (;@1;) 1 (;@1;) + end + drop + f64.const 0x0p+0 (;=0;) + end + drop + ) + (export "meet-bottom" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/12.print b/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/12.print new file mode 100644 index 0000000000..9af2f6bfb2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/unreached-valid.wast/12.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (result (ref func)))) + (type (;1;) (func (result (ref extern)))) + (func (;0;) (type 0) (result (ref func)) + unreachable + ref.as_non_null + ) + (func (;1;) (type 1) (result (ref extern)) + unreachable + ref.as_non_null + ) + (func (;2;) (type 0) (result (ref func)) + block (result funcref) ;; label = @1 + unreachable + br_on_null 0 (;@1;) + return + end + unreachable + ) + (func (;3;) (type 1) (result (ref extern)) + block (result externref) ;; label = @1 + unreachable + br_on_null 0 (;@1;) + return + end + unreachable + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/address.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/address.wast/0.print new file mode 100644 index 0000000000..b97b1265e9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/address.wast/0.print @@ -0,0 +1,161 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u + ) + (func (;1;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u + ) + (func (;2;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u offset=1 + ) + (func (;3;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u offset=2 + ) + (func (;4;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u offset=25 + ) + (func (;5;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s + ) + (func (;6;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s + ) + (func (;7;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s offset=1 + ) + (func (;8;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s offset=2 + ) + (func (;9;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s offset=25 + ) + (func (;10;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u + ) + (func (;11;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u align=1 + ) + (func (;12;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u offset=1 align=1 + ) + (func (;13;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u offset=2 + ) + (func (;14;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u offset=25 + ) + (func (;15;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s + ) + (func (;16;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s align=1 + ) + (func (;17;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s offset=1 align=1 + ) + (func (;18;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s offset=2 + ) + (func (;19;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s offset=25 + ) + (func (;20;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load + ) + (func (;21;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load align=1 + ) + (func (;22;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load offset=1 align=1 + ) + (func (;23;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load offset=2 align=2 + ) + (func (;24;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load offset=25 + ) + (func (;25;) (type 1) (param $i i32) + local.get $i + i32.load8_u offset=4294967295 + drop + ) + (func (;26;) (type 1) (param $i i32) + local.get $i + i32.load8_s offset=4294967295 + drop + ) + (func (;27;) (type 1) (param $i i32) + local.get $i + i32.load16_u offset=4294967295 + drop + ) + (func (;28;) (type 1) (param $i i32) + local.get $i + i32.load16_s offset=4294967295 + drop + ) + (func (;29;) (type 1) (param $i i32) + local.get $i + i32.load offset=4294967295 + drop + ) + (memory (;0;) 1) + (export "8u_good1" (func 0)) + (export "8u_good2" (func 1)) + (export "8u_good3" (func 2)) + (export "8u_good4" (func 3)) + (export "8u_good5" (func 4)) + (export "8s_good1" (func 5)) + (export "8s_good2" (func 6)) + (export "8s_good3" (func 7)) + (export "8s_good4" (func 8)) + (export "8s_good5" (func 9)) + (export "16u_good1" (func 10)) + (export "16u_good2" (func 11)) + (export "16u_good3" (func 12)) + (export "16u_good4" (func 13)) + (export "16u_good5" (func 14)) + (export "16s_good1" (func 15)) + (export "16s_good2" (func 16)) + (export "16s_good3" (func 17)) + (export "16s_good4" (func 18)) + (export "16s_good5" (func 19)) + (export "32_good1" (func 20)) + (export "32_good2" (func 21)) + (export "32_good3" (func 22)) + (export "32_good4" (func 23)) + (export "32_good5" (func 24)) + (export "8u_bad" (func 25)) + (export "8s_bad" (func 26)) + (export "16u_bad" (func 27)) + (export "16s_bad" (func 28)) + (export "32_bad" (func 29)) + (data (;0;) (i32.const 0) "abcdefghijklmnopqrstuvwxyz") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/address.wast/220.print b/tests/snapshots/testsuite/proposals/memory64/address.wast/220.print new file mode 100644 index 0000000000..ccfcc7a769 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/address.wast/220.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32) (result f32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load + ) + (func (;1;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load align=1 + ) + (func (;2;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load offset=1 align=1 + ) + (func (;3;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load offset=2 align=2 + ) + (func (;4;) (type 0) (param $i i32) (result f32) + local.get $i + f32.load offset=8 + ) + (func (;5;) (type 1) (param $i i32) + local.get $i + f32.load offset=4294967295 + drop + ) + (memory (;0;) 1) + (export "32_good1" (func 0)) + (export "32_good2" (func 1)) + (export "32_good3" (func 2)) + (export "32_good4" (func 3)) + (export "32_good5" (func 4)) + (export "32_bad" (func 5)) + (data (;0;) (i32.const 0) "\00\00\00\00\00\00\a0\7f\01\00\d0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/address.wast/240.print b/tests/snapshots/testsuite/proposals/memory64/address.wast/240.print new file mode 100644 index 0000000000..831f78f7ed --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/address.wast/240.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i32) (result f64))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load + ) + (func (;1;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load align=1 + ) + (func (;2;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load offset=1 align=1 + ) + (func (;3;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load offset=2 align=2 + ) + (func (;4;) (type 0) (param $i i32) (result f64) + local.get $i + f64.load offset=18 + ) + (func (;5;) (type 1) (param $i i32) + local.get $i + f64.load offset=4294967295 + drop + ) + (memory (;0;) 1) + (export "64_good1" (func 0)) + (export "64_good2" (func 1)) + (export "64_good3" (func 2)) + (export "64_good4" (func 3)) + (export "64_good5" (func 4)) + (export "64_bad" (func 5)) + (data (;0;) (i32.const 0) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\f4\7f\01\00\00\00\00\00\fc\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/address.wast/93.print b/tests/snapshots/testsuite/proposals/memory64/address.wast/93.print new file mode 100644 index 0000000000..c976a1180c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/address.wast/93.print @@ -0,0 +1,223 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u + ) + (func (;1;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u + ) + (func (;2;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u offset=1 + ) + (func (;3;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u offset=2 + ) + (func (;4;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u offset=25 + ) + (func (;5;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s + ) + (func (;6;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s + ) + (func (;7;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s offset=1 + ) + (func (;8;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s offset=2 + ) + (func (;9;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s offset=25 + ) + (func (;10;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u + ) + (func (;11;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u align=1 + ) + (func (;12;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u offset=1 align=1 + ) + (func (;13;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u offset=2 + ) + (func (;14;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u offset=25 + ) + (func (;15;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s + ) + (func (;16;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s align=1 + ) + (func (;17;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s offset=1 align=1 + ) + (func (;18;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s offset=2 + ) + (func (;19;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s offset=25 + ) + (func (;20;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u + ) + (func (;21;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u align=1 + ) + (func (;22;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u offset=1 align=1 + ) + (func (;23;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u offset=2 align=2 + ) + (func (;24;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u offset=25 + ) + (func (;25;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s + ) + (func (;26;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s align=1 + ) + (func (;27;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s offset=1 align=1 + ) + (func (;28;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s offset=2 align=2 + ) + (func (;29;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s offset=25 + ) + (func (;30;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load + ) + (func (;31;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load align=1 + ) + (func (;32;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load offset=1 align=1 + ) + (func (;33;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load offset=2 align=2 + ) + (func (;34;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load offset=25 + ) + (func (;35;) (type 1) (param $i i32) + local.get $i + i64.load8_u offset=4294967295 + drop + ) + (func (;36;) (type 1) (param $i i32) + local.get $i + i64.load8_s offset=4294967295 + drop + ) + (func (;37;) (type 1) (param $i i32) + local.get $i + i64.load16_u offset=4294967295 + drop + ) + (func (;38;) (type 1) (param $i i32) + local.get $i + i64.load16_s offset=4294967295 + drop + ) + (func (;39;) (type 1) (param $i i32) + local.get $i + i64.load32_u offset=4294967295 + drop + ) + (func (;40;) (type 1) (param $i i32) + local.get $i + i64.load32_s offset=4294967295 + drop + ) + (func (;41;) (type 1) (param $i i32) + local.get $i + i64.load offset=4294967295 + drop + ) + (memory (;0;) 1) + (export "8u_good1" (func 0)) + (export "8u_good2" (func 1)) + (export "8u_good3" (func 2)) + (export "8u_good4" (func 3)) + (export "8u_good5" (func 4)) + (export "8s_good1" (func 5)) + (export "8s_good2" (func 6)) + (export "8s_good3" (func 7)) + (export "8s_good4" (func 8)) + (export "8s_good5" (func 9)) + (export "16u_good1" (func 10)) + (export "16u_good2" (func 11)) + (export "16u_good3" (func 12)) + (export "16u_good4" (func 13)) + (export "16u_good5" (func 14)) + (export "16s_good1" (func 15)) + (export "16s_good2" (func 16)) + (export "16s_good3" (func 17)) + (export "16s_good4" (func 18)) + (export "16s_good5" (func 19)) + (export "32u_good1" (func 20)) + (export "32u_good2" (func 21)) + (export "32u_good3" (func 22)) + (export "32u_good4" (func 23)) + (export "32u_good5" (func 24)) + (export "32s_good1" (func 25)) + (export "32s_good2" (func 26)) + (export "32s_good3" (func 27)) + (export "32s_good4" (func 28)) + (export "32s_good5" (func 29)) + (export "64_good1" (func 30)) + (export "64_good2" (func 31)) + (export "64_good3" (func 32)) + (export "64_good4" (func 33)) + (export "64_good5" (func 34)) + (export "8u_bad" (func 35)) + (export "8s_bad" (func 36)) + (export "16u_bad" (func 37)) + (export "16s_bad" (func 38)) + (export "32u_bad" (func 39)) + (export "32s_bad" (func 40)) + (export "64_bad" (func 41)) + (data (;0;) (i32.const 0) "abcdefghijklmnopqrstuvwxyz") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/address64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/address64.wast/0.print new file mode 100644 index 0000000000..85d1a8d8f6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/address64.wast/0.print @@ -0,0 +1,161 @@ +(module + (type (;0;) (func (param i64) (result i32))) + (type (;1;) (func (param i64))) + (func (;0;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_u + ) + (func (;1;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_u + ) + (func (;2;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_u offset=1 + ) + (func (;3;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_u offset=2 + ) + (func (;4;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_u offset=25 + ) + (func (;5;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_s + ) + (func (;6;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_s + ) + (func (;7;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_s offset=1 + ) + (func (;8;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_s offset=2 + ) + (func (;9;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load8_s offset=25 + ) + (func (;10;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_u + ) + (func (;11;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_u align=1 + ) + (func (;12;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_u offset=1 align=1 + ) + (func (;13;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_u offset=2 + ) + (func (;14;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_u offset=25 + ) + (func (;15;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_s + ) + (func (;16;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_s align=1 + ) + (func (;17;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_s offset=1 align=1 + ) + (func (;18;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_s offset=2 + ) + (func (;19;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load16_s offset=25 + ) + (func (;20;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load + ) + (func (;21;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load align=1 + ) + (func (;22;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load offset=1 align=1 + ) + (func (;23;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load offset=2 align=2 + ) + (func (;24;) (type 0) (param $i i64) (result i32) + local.get $i + i32.load offset=25 + ) + (func (;25;) (type 1) (param $i i64) + local.get $i + i32.load8_u offset=4294967295 + drop + ) + (func (;26;) (type 1) (param $i i64) + local.get $i + i32.load8_s offset=4294967295 + drop + ) + (func (;27;) (type 1) (param $i i64) + local.get $i + i32.load16_u offset=4294967295 + drop + ) + (func (;28;) (type 1) (param $i i64) + local.get $i + i32.load16_s offset=4294967295 + drop + ) + (func (;29;) (type 1) (param $i i64) + local.get $i + i32.load offset=4294967295 + drop + ) + (memory (;0;) i64 1) + (export "8u_good1" (func 0)) + (export "8u_good2" (func 1)) + (export "8u_good3" (func 2)) + (export "8u_good4" (func 3)) + (export "8u_good5" (func 4)) + (export "8s_good1" (func 5)) + (export "8s_good2" (func 6)) + (export "8s_good3" (func 7)) + (export "8s_good4" (func 8)) + (export "8s_good5" (func 9)) + (export "16u_good1" (func 10)) + (export "16u_good2" (func 11)) + (export "16u_good3" (func 12)) + (export "16u_good4" (func 13)) + (export "16u_good5" (func 14)) + (export "16s_good1" (func 15)) + (export "16s_good2" (func 16)) + (export "16s_good3" (func 17)) + (export "16s_good4" (func 18)) + (export "16s_good5" (func 19)) + (export "32_good1" (func 20)) + (export "32_good2" (func 21)) + (export "32_good3" (func 22)) + (export "32_good4" (func 23)) + (export "32_good5" (func 24)) + (export "8u_bad" (func 25)) + (export "8s_bad" (func 26)) + (export "16u_bad" (func 27)) + (export "16s_bad" (func 28)) + (export "32_bad" (func 29)) + (data (;0;) (i64.const 0) "abcdefghijklmnopqrstuvwxyz") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/address64.wast/206.print b/tests/snapshots/testsuite/proposals/memory64/address64.wast/206.print new file mode 100644 index 0000000000..4f28c7120b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/address64.wast/206.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i64) (result f32))) + (type (;1;) (func (param i64))) + (func (;0;) (type 0) (param $i i64) (result f32) + local.get $i + f32.load + ) + (func (;1;) (type 0) (param $i i64) (result f32) + local.get $i + f32.load align=1 + ) + (func (;2;) (type 0) (param $i i64) (result f32) + local.get $i + f32.load offset=1 align=1 + ) + (func (;3;) (type 0) (param $i i64) (result f32) + local.get $i + f32.load offset=2 align=2 + ) + (func (;4;) (type 0) (param $i i64) (result f32) + local.get $i + f32.load offset=8 + ) + (func (;5;) (type 1) (param $i i64) + local.get $i + f32.load offset=4294967295 + drop + ) + (memory (;0;) i64 1) + (export "32_good1" (func 0)) + (export "32_good2" (func 1)) + (export "32_good3" (func 2)) + (export "32_good4" (func 3)) + (export "32_good5" (func 4)) + (export "32_bad" (func 5)) + (data (;0;) (i64.const 0) "\00\00\00\00\00\00\a0\7f\01\00\d0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/address64.wast/224.print b/tests/snapshots/testsuite/proposals/memory64/address64.wast/224.print new file mode 100644 index 0000000000..534c71825b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/address64.wast/224.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (param i64) (result f64))) + (type (;1;) (func (param i64))) + (func (;0;) (type 0) (param $i i64) (result f64) + local.get $i + f64.load + ) + (func (;1;) (type 0) (param $i i64) (result f64) + local.get $i + f64.load align=1 + ) + (func (;2;) (type 0) (param $i i64) (result f64) + local.get $i + f64.load offset=1 align=1 + ) + (func (;3;) (type 0) (param $i i64) (result f64) + local.get $i + f64.load offset=2 align=2 + ) + (func (;4;) (type 0) (param $i i64) (result f64) + local.get $i + f64.load offset=18 + ) + (func (;5;) (type 1) (param $i i64) + local.get $i + f64.load offset=4294967295 + drop + ) + (memory (;0;) i64 1) + (export "64_good1" (func 0)) + (export "64_good2" (func 1)) + (export "64_good3" (func 2)) + (export "64_good4" (func 3)) + (export "64_good5" (func 4)) + (export "64_bad" (func 5)) + (data (;0;) (i64.const 0) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\f4\7f\01\00\00\00\00\00\fc\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/address64.wast/86.print b/tests/snapshots/testsuite/proposals/memory64/address64.wast/86.print new file mode 100644 index 0000000000..4b43532165 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/address64.wast/86.print @@ -0,0 +1,223 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (type (;1;) (func (param i64))) + (func (;0;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_u + ) + (func (;1;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_u + ) + (func (;2;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_u offset=1 + ) + (func (;3;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_u offset=2 + ) + (func (;4;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_u offset=25 + ) + (func (;5;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_s + ) + (func (;6;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_s + ) + (func (;7;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_s offset=1 + ) + (func (;8;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_s offset=2 + ) + (func (;9;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load8_s offset=25 + ) + (func (;10;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_u + ) + (func (;11;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_u align=1 + ) + (func (;12;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_u offset=1 align=1 + ) + (func (;13;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_u offset=2 + ) + (func (;14;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_u offset=25 + ) + (func (;15;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_s + ) + (func (;16;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_s align=1 + ) + (func (;17;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_s offset=1 align=1 + ) + (func (;18;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_s offset=2 + ) + (func (;19;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load16_s offset=25 + ) + (func (;20;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_u + ) + (func (;21;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_u align=1 + ) + (func (;22;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_u offset=1 align=1 + ) + (func (;23;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_u offset=2 align=2 + ) + (func (;24;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_u offset=25 + ) + (func (;25;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_s + ) + (func (;26;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_s align=1 + ) + (func (;27;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_s offset=1 align=1 + ) + (func (;28;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_s offset=2 align=2 + ) + (func (;29;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load32_s offset=25 + ) + (func (;30;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load + ) + (func (;31;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load align=1 + ) + (func (;32;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load offset=1 align=1 + ) + (func (;33;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load offset=2 align=2 + ) + (func (;34;) (type 0) (param $i i64) (result i64) + local.get $i + i64.load offset=25 + ) + (func (;35;) (type 1) (param $i i64) + local.get $i + i64.load8_u offset=4294967295 + drop + ) + (func (;36;) (type 1) (param $i i64) + local.get $i + i64.load8_s offset=4294967295 + drop + ) + (func (;37;) (type 1) (param $i i64) + local.get $i + i64.load16_u offset=4294967295 + drop + ) + (func (;38;) (type 1) (param $i i64) + local.get $i + i64.load16_s offset=4294967295 + drop + ) + (func (;39;) (type 1) (param $i i64) + local.get $i + i64.load32_u offset=4294967295 + drop + ) + (func (;40;) (type 1) (param $i i64) + local.get $i + i64.load32_s offset=4294967295 + drop + ) + (func (;41;) (type 1) (param $i i64) + local.get $i + i64.load offset=4294967295 + drop + ) + (memory (;0;) i64 1) + (export "8u_good1" (func 0)) + (export "8u_good2" (func 1)) + (export "8u_good3" (func 2)) + (export "8u_good4" (func 3)) + (export "8u_good5" (func 4)) + (export "8s_good1" (func 5)) + (export "8s_good2" (func 6)) + (export "8s_good3" (func 7)) + (export "8s_good4" (func 8)) + (export "8s_good5" (func 9)) + (export "16u_good1" (func 10)) + (export "16u_good2" (func 11)) + (export "16u_good3" (func 12)) + (export "16u_good4" (func 13)) + (export "16u_good5" (func 14)) + (export "16s_good1" (func 15)) + (export "16s_good2" (func 16)) + (export "16s_good3" (func 17)) + (export "16s_good4" (func 18)) + (export "16s_good5" (func 19)) + (export "32u_good1" (func 20)) + (export "32u_good2" (func 21)) + (export "32u_good3" (func 22)) + (export "32u_good4" (func 23)) + (export "32u_good5" (func 24)) + (export "32s_good1" (func 25)) + (export "32s_good2" (func 26)) + (export "32s_good3" (func 27)) + (export "32s_good4" (func 28)) + (export "32s_good5" (func 29)) + (export "64_good1" (func 30)) + (export "64_good2" (func 31)) + (export "64_good3" (func 32)) + (export "64_good4" (func 33)) + (export "64_good5" (func 34)) + (export "8u_bad" (func 35)) + (export "8s_bad" (func 36)) + (export "16u_bad" (func 37)) + (export "16s_bad" (func 38)) + (export "32u_bad" (func 39)) + (export "32s_bad" (func 40)) + (export "64_bad" (func 41)) + (data (;0;) (i64.const 0) "abcdefghijklmnopqrstuvwxyz") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/0.print new file mode 100644 index 0000000000..e57c996f16 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/0.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i32.load8_s + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/1.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/1.print new file mode 100644 index 0000000000..bf0fb76bc1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/1.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i32.load8_u + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/10.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/10.print new file mode 100644 index 0000000000..fa5ab27936 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/10.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.load32_u + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/106.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/106.print new file mode 100644 index 0000000000..a0e4fe5ded --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/106.print @@ -0,0 +1,571 @@ +(module + (type (;0;) (func (param i32) (result f32))) + (type (;1;) (func (param i32) (result f64))) + (type (;2;) (func (param i32 i32) (result i32))) + (type (;3;) (func (param i32 i32) (result i64))) + (func (;0;) (type 0) (param i32) (result f32) + (local f32 f32) + f32.const 0x1.4p+3 (;=10;) + local.set 1 + block $4 ;; label = @1 + block $2 ;; label = @2 + block $1 ;; label = @3 + block $default ;; label = @4 + block $0 ;; label = @5 + local.get 0 + br_table 0 (;@5;) 1 (;@4;) 2 (;@3;) 3 (;@2;) 4 (;@1;) + end + i64.const 0 + local.get 1 + f32.store + i64.const 0 + f32.load + local.set 2 + br 3 (;@1;) + end + i64.const 0 + local.get 1 + f32.store align=1 + i64.const 0 + f32.load align=1 + local.set 2 + br 2 (;@1;) + end + i64.const 0 + local.get 1 + f32.store align=2 + i64.const 0 + f32.load align=2 + local.set 2 + br 1 (;@1;) + end + i64.const 0 + local.get 1 + f32.store + i64.const 0 + f32.load + local.set 2 + end + local.get 2 + ) + (func (;1;) (type 1) (param i32) (result f64) + (local f64 f64) + f64.const 0x1.4p+3 (;=10;) + local.set 1 + block $8 ;; label = @1 + block $4 ;; label = @2 + block $2 ;; label = @3 + block $1 ;; label = @4 + block $default ;; label = @5 + block $0 ;; label = @6 + local.get 0 + br_table 0 (;@6;) 1 (;@5;) 2 (;@4;) 3 (;@3;) 4 (;@2;) 5 (;@1;) + end + i64.const 0 + local.get 1 + f64.store + i64.const 0 + f64.load + local.set 2 + br 4 (;@1;) + end + i64.const 0 + local.get 1 + f64.store align=1 + i64.const 0 + f64.load align=1 + local.set 2 + br 3 (;@1;) + end + i64.const 0 + local.get 1 + f64.store align=2 + i64.const 0 + f64.load align=2 + local.set 2 + br 2 (;@1;) + end + i64.const 0 + local.get 1 + f64.store align=4 + i64.const 0 + f64.load align=4 + local.set 2 + br 1 (;@1;) + end + i64.const 0 + local.get 1 + f64.store + i64.const 0 + f64.load + local.set 2 + end + local.get 2 + ) + (func (;2;) (type 2) (param i32 i32) (result i32) + (local i32 i32) + i32.const 10 + local.set 2 + block $32 ;; label = @1 + block $16u ;; label = @2 + block $16s ;; label = @3 + block $8u ;; label = @4 + block $8s ;; label = @5 + block $0 ;; label = @6 + local.get 0 + br_table 0 (;@6;) 1 (;@5;) 2 (;@4;) 3 (;@3;) 4 (;@2;) 5 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @6 + i64.const 0 + local.get 2 + i32.store8 + i64.const 0 + i32.load8_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @6 + i64.const 0 + local.get 2 + i32.store8 + i64.const 0 + i32.load8_s + local.set 3 + end + br 4 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @5 + i64.const 0 + local.get 2 + i32.store8 + i64.const 0 + i32.load8_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @5 + i64.const 0 + local.get 2 + i32.store8 + i64.const 0 + i32.load8_u + local.set 3 + end + br 3 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @4 + i64.const 0 + local.get 2 + i32.store16 + i64.const 0 + i32.load16_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @4 + i64.const 0 + local.get 2 + i32.store16 align=1 + i64.const 0 + i32.load16_s align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @4 + i64.const 0 + local.get 2 + i32.store16 + i64.const 0 + i32.load16_s + local.set 3 + end + br 2 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @3 + i64.const 0 + local.get 2 + i32.store16 + i64.const 0 + i32.load16_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @3 + i64.const 0 + local.get 2 + i32.store16 align=1 + i64.const 0 + i32.load16_u align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @3 + i64.const 0 + local.get 2 + i32.store16 + i64.const 0 + i32.load16_u + local.set 3 + end + br 1 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i32.store + i64.const 0 + i32.load + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i32.store align=1 + i64.const 0 + i32.load align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i32.store align=2 + i64.const 0 + i32.load align=2 + local.set 3 + end + local.get 1 + i32.const 4 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i32.store + i64.const 0 + i32.load + local.set 3 + end + end + local.get 3 + ) + (func (;3;) (type 3) (param i32 i32) (result i64) + (local i64 i64) + i64.const 10 + local.set 2 + block $64 ;; label = @1 + block $32u ;; label = @2 + block $32s ;; label = @3 + block $16u ;; label = @4 + block $16s ;; label = @5 + block $8u ;; label = @6 + block $8s ;; label = @7 + block $0 ;; label = @8 + local.get 0 + br_table 0 (;@8;) 1 (;@7;) 2 (;@6;) 3 (;@5;) 4 (;@4;) 5 (;@3;) 6 (;@2;) 7 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @8 + i64.const 0 + local.get 2 + i64.store8 + i64.const 0 + i64.load8_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @8 + i64.const 0 + local.get 2 + i64.store8 + i64.const 0 + i64.load8_s + local.set 3 + end + br 6 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @7 + i64.const 0 + local.get 2 + i64.store8 + i64.const 0 + i64.load8_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @7 + i64.const 0 + local.get 2 + i64.store8 + i64.const 0 + i64.load8_u + local.set 3 + end + br 5 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @6 + i64.const 0 + local.get 2 + i64.store16 + i64.const 0 + i64.load16_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @6 + i64.const 0 + local.get 2 + i64.store16 align=1 + i64.const 0 + i64.load16_s align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @6 + i64.const 0 + local.get 2 + i64.store16 + i64.const 0 + i64.load16_s + local.set 3 + end + br 4 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @5 + i64.const 0 + local.get 2 + i64.store16 + i64.const 0 + i64.load16_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @5 + i64.const 0 + local.get 2 + i64.store16 align=1 + i64.const 0 + i64.load16_u align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @5 + i64.const 0 + local.get 2 + i64.store16 + i64.const 0 + i64.load16_u + local.set 3 + end + br 3 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @4 + i64.const 0 + local.get 2 + i64.store32 + i64.const 0 + i64.load32_s + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @4 + i64.const 0 + local.get 2 + i64.store32 align=1 + i64.const 0 + i64.load32_s align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @4 + i64.const 0 + local.get 2 + i64.store32 align=2 + i64.const 0 + i64.load32_s align=2 + local.set 3 + end + local.get 1 + i32.const 4 + i32.eq + if ;; label = @4 + i64.const 0 + local.get 2 + i64.store32 + i64.const 0 + i64.load32_s + local.set 3 + end + br 2 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @3 + i64.const 0 + local.get 2 + i64.store32 + i64.const 0 + i64.load32_u + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @3 + i64.const 0 + local.get 2 + i64.store32 align=1 + i64.const 0 + i64.load32_u align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @3 + i64.const 0 + local.get 2 + i64.store32 align=2 + i64.const 0 + i64.load32_u align=2 + local.set 3 + end + local.get 1 + i32.const 4 + i32.eq + if ;; label = @3 + i64.const 0 + local.get 2 + i64.store32 + i64.const 0 + i64.load32_u + local.set 3 + end + br 1 (;@1;) + end + local.get 1 + i32.const 0 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i64.store + i64.const 0 + i64.load + local.set 3 + end + local.get 1 + i32.const 1 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i64.store align=1 + i64.const 0 + i64.load align=1 + local.set 3 + end + local.get 1 + i32.const 2 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i64.store align=2 + i64.const 0 + i64.load align=2 + local.set 3 + end + local.get 1 + i32.const 4 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i64.store align=4 + i64.const 0 + i64.load align=4 + local.set 3 + end + local.get 1 + i32.const 8 + i32.eq + if ;; label = @2 + i64.const 0 + local.get 2 + i64.store + i64.const 0 + i64.load + local.set 3 + end + end + local.get 3 + ) + (memory (;0;) i64 1) + (export "f32_align_switch" (func 0)) + (export "f64_align_switch" (func 1)) + (export "i32_align_switch" (func 2)) + (export "i64_align_switch" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/11.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/11.print new file mode 100644 index 0000000000..16a612a6cd --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/11.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.load + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/12.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/12.print new file mode 100644 index 0000000000..da23120209 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/12.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + f32.load + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/13.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/13.print new file mode 100644 index 0000000000..2c301497da --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/13.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + f64.load + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/14.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/14.print new file mode 100644 index 0000000000..d7ee879448 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/14.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i32.const 1 + i32.store8 + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/15.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/15.print new file mode 100644 index 0000000000..158731025b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/15.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i32.const 1 + i32.store16 + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/153.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/153.print new file mode 100644 index 0000000000..f7525dbd52 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/153.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param i64 i64))) + (type (;1;) (func (param i64) (result i32))) + (func (;0;) (type 0) (param i64 i64) + local.get 0 + local.get 1 + i64.store align=4 + ) + (func (;1;) (type 1) (param i64) (result i32) + local.get 0 + i32.load + ) + (memory (;0;) i64 1) + (export "store" (func 0)) + (export "load" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/16.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/16.print new file mode 100644 index 0000000000..9b3be643d5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/16.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i32.const 1 + i32.store + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/17.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/17.print new file mode 100644 index 0000000000..c818093902 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/17.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.const 1 + i64.store8 + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/18.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/18.print new file mode 100644 index 0000000000..20b672f6e7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/18.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.const 1 + i64.store16 + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/19.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/19.print new file mode 100644 index 0000000000..0e49b938eb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/19.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.const 1 + i64.store32 + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/2.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/2.print new file mode 100644 index 0000000000..378e5e4629 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/2.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i32.load16_s + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/20.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/20.print new file mode 100644 index 0000000000..78e2b80a1d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/20.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.const 1 + i64.store + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/21.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/21.print new file mode 100644 index 0000000000..57def06d57 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/21.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + f32.const 0x1p+0 (;=1;) + f32.store + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/22.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/22.print new file mode 100644 index 0000000000..e1c892793b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/22.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + f64.const 0x1p+0 (;=1;) + f64.store + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/3.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/3.print new file mode 100644 index 0000000000..18cbf8f795 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/3.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i32.load16_u + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/4.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/4.print new file mode 100644 index 0000000000..34607d77bf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/4.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i32.load + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/5.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/5.print new file mode 100644 index 0000000000..8265b4a772 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/5.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.load8_s + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/6.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/6.print new file mode 100644 index 0000000000..a47860d563 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/6.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.load8_u + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/7.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/7.print new file mode 100644 index 0000000000..53532a4552 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/7.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.load16_s + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/8.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/8.print new file mode 100644 index 0000000000..a713710fbc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/8.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.load16_u + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/align64.wast/9.print b/tests/snapshots/testsuite/proposals/memory64/align64.wast/9.print new file mode 100644 index 0000000000..9015ce134b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/align64.wast/9.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i64.const 0 + i64.load32_s + drop + ) + (memory (;0;) i64 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/0.print new file mode 100644 index 0000000000..f18cc54f26 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/0.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/1.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/1.print new file mode 100644 index 0000000000..f18cc54f26 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/1.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/10.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/10.print new file mode 100644 index 0000000000..2dce17095d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/10.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/11.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/11.print new file mode 100644 index 0000000000..2dce17095d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/11.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/12.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/12.print new file mode 100644 index 0000000000..2dce17095d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/12.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/13.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/13.print new file mode 100644 index 0000000000..f81d636a1b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/13.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/14.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/14.print new file mode 100644 index 0000000000..274e55d61c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/14.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "f1" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/15.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/15.print new file mode 100644 index 0000000000..274e55d61c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/15.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "f1" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/16.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/16.print new file mode 100644 index 0000000000..f81d636a1b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/16.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/17.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/17.print new file mode 100644 index 0000000000..e6b79c4e23 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/17.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/18.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/18.print new file mode 100644 index 0000000000..98af8924d4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/18.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const -1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/19.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/19.print new file mode 100644 index 0000000000..e6b79c4e23 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/19.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/2.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/2.print new file mode 100644 index 0000000000..c7d9da5741 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/2.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 2 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/20.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/20.print new file mode 100644 index 0000000000..98af8924d4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/20.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i32 i32.const -1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/21.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/21.print new file mode 100644 index 0000000000..78d137b2e3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/21.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i64 i64.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/22.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/22.print new file mode 100644 index 0000000000..9d1440296d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/22.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i64 i64.const -1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/23.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/23.print new file mode 100644 index 0000000000..78d137b2e3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/23.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i64 i64.const 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/24.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/24.print new file mode 100644 index 0000000000..9d1440296d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/24.print @@ -0,0 +1,3 @@ +(module + (global (;0;) i64 i64.const -1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/3.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/3.print new file mode 100644 index 0000000000..c7d9da5741 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/3.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 2 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/4.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/4.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/4.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/5.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/5.print new file mode 100644 index 0000000000..3a1c6fc5f6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/5.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (elem (;0;) (i32.const 0) func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/6.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/6.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/6.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/7.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/7.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/7.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/8.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/8.print new file mode 100644 index 0000000000..7435af94e8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/8.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32 i64) (result i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/81.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/81.print new file mode 100644 index 0000000000..160d4c8f91 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/81.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + unreachable + i32.trunc_sat_f32_s + unreachable + i32.trunc_sat_f32_u + unreachable + i64.trunc_sat_f64_s + unreachable + i64.trunc_sat_f64_u + unreachable + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/9.print b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/9.print new file mode 100644 index 0000000000..7435af94e8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary-leb128.wast/9.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32 i64) (result i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/1.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/101.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/101.print new file mode 100644 index 0000000000..17f0618fdf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/101.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 1 + if ;; label = @2 + i32.const 1 + br_table 2 (;@0;) + end + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/103.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/103.print new file mode 100644 index 0000000000..a2354a64c3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/103.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (start 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/2.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/2.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/2.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/3.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/3.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/3.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/56.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/56.print new file mode 100644 index 0000000000..3171d8f4fb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/56.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local f32 f32) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/61.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/61.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/61.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/62.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/62.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/62.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/63.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/63.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/63.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/66.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/66.print new file mode 100644 index 0000000000..c47d05badc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/66.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/75.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/75.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/75.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/80.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/80.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/80.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/86.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/86.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/86.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/89.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/89.print new file mode 100644 index 0000000000..1270a74e97 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/89.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/92.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/92.print new file mode 100644 index 0000000000..a0fe812a51 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/92.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/binary.wast/96.print b/tests/snapshots/testsuite/proposals/memory64/binary.wast/96.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/binary.wast/96.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/endianness64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/endianness64.wast/0.print new file mode 100644 index 0000000000..ec25622da3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/endianness64.wast/0.print @@ -0,0 +1,229 @@ +(module + (type (;0;) (func (param i64 i32))) + (type (;1;) (func (param i64 i64))) + (type (;2;) (func (param i64) (result i32))) + (type (;3;) (func (param i64) (result i64))) + (type (;4;) (func (param i32) (result i32))) + (type (;5;) (func (param f32) (result f32))) + (type (;6;) (func (param f64) (result f64))) + (func $i16_store_little (;0;) (type 0) (param $address i64) (param $value i32) + local.get $address + local.get $value + i32.store8 + local.get $address + i64.const 1 + i64.add + local.get $value + i32.const 8 + i32.shr_u + i32.store8 + ) + (func $i32_store_little (;1;) (type 0) (param $address i64) (param $value i32) + local.get $address + local.get $value + call $i16_store_little + local.get $address + i64.const 2 + i64.add + local.get $value + i32.const 16 + i32.shr_u + call $i16_store_little + ) + (func $i64_store_little (;2;) (type 1) (param $address i64) (param $value i64) + local.get $address + local.get $value + i32.wrap_i64 + call $i32_store_little + local.get $address + i64.const 4 + i64.add + local.get $value + i64.const 32 + i64.shr_u + i32.wrap_i64 + call $i32_store_little + ) + (func $i16_load_little (;3;) (type 2) (param $address i64) (result i32) + local.get $address + i32.load8_u + local.get $address + i64.const 1 + i64.add + i32.load8_u + i32.const 8 + i32.shl + i32.or + ) + (func $i32_load_little (;4;) (type 2) (param $address i64) (result i32) + local.get $address + call $i16_load_little + local.get $address + i64.const 2 + i64.add + call $i16_load_little + i32.const 16 + i32.shl + i32.or + ) + (func $i64_load_little (;5;) (type 3) (param $address i64) (result i64) + local.get $address + call $i32_load_little + i64.extend_i32_u + local.get $address + i64.const 4 + i64.add + call $i32_load_little + i64.extend_i32_u + i64.const 32 + i64.shl + i64.or + ) + (func (;6;) (type 4) (param $value i32) (result i32) + i64.const 0 + local.get $value + call $i16_store_little + i64.const 0 + i32.load16_s + ) + (func (;7;) (type 4) (param $value i32) (result i32) + i64.const 0 + local.get $value + call $i16_store_little + i64.const 0 + i32.load16_u + ) + (func (;8;) (type 4) (param $value i32) (result i32) + i64.const 0 + local.get $value + call $i32_store_little + i64.const 0 + i32.load + ) + (func (;9;) (type 3) (param $value i64) (result i64) + i64.const 0 + local.get $value + i32.wrap_i64 + call $i16_store_little + i64.const 0 + i64.load16_s + ) + (func (;10;) (type 3) (param $value i64) (result i64) + i64.const 0 + local.get $value + i32.wrap_i64 + call $i16_store_little + i64.const 0 + i64.load16_u + ) + (func (;11;) (type 3) (param $value i64) (result i64) + i64.const 0 + local.get $value + i32.wrap_i64 + call $i32_store_little + i64.const 0 + i64.load32_s + ) + (func (;12;) (type 3) (param $value i64) (result i64) + i64.const 0 + local.get $value + i32.wrap_i64 + call $i32_store_little + i64.const 0 + i64.load32_u + ) + (func (;13;) (type 3) (param $value i64) (result i64) + i64.const 0 + local.get $value + call $i64_store_little + i64.const 0 + i64.load + ) + (func (;14;) (type 5) (param $value f32) (result f32) + i64.const 0 + local.get $value + i32.reinterpret_f32 + call $i32_store_little + i64.const 0 + f32.load + ) + (func (;15;) (type 6) (param $value f64) (result f64) + i64.const 0 + local.get $value + i64.reinterpret_f64 + call $i64_store_little + i64.const 0 + f64.load + ) + (func (;16;) (type 4) (param $value i32) (result i32) + i64.const 0 + local.get $value + i32.store16 + i64.const 0 + call $i16_load_little + ) + (func (;17;) (type 4) (param $value i32) (result i32) + i64.const 0 + local.get $value + i32.store + i64.const 0 + call $i32_load_little + ) + (func (;18;) (type 3) (param $value i64) (result i64) + i64.const 0 + local.get $value + i64.store16 + i64.const 0 + call $i16_load_little + i64.extend_i32_u + ) + (func (;19;) (type 3) (param $value i64) (result i64) + i64.const 0 + local.get $value + i64.store32 + i64.const 0 + call $i32_load_little + i64.extend_i32_u + ) + (func (;20;) (type 3) (param $value i64) (result i64) + i64.const 0 + local.get $value + i64.store + i64.const 0 + call $i64_load_little + ) + (func (;21;) (type 5) (param $value f32) (result f32) + i64.const 0 + local.get $value + f32.store + i64.const 0 + call $i32_load_little + f32.reinterpret_i32 + ) + (func (;22;) (type 6) (param $value f64) (result f64) + i64.const 0 + local.get $value + f64.store + i64.const 0 + call $i64_load_little + f64.reinterpret_i64 + ) + (memory (;0;) i64 1) + (export "i32_load16_s" (func 6)) + (export "i32_load16_u" (func 7)) + (export "i32_load" (func 8)) + (export "i64_load16_s" (func 9)) + (export "i64_load16_u" (func 10)) + (export "i64_load32_s" (func 11)) + (export "i64_load32_u" (func 12)) + (export "i64_load" (func 13)) + (export "f32_load" (func 14)) + (export "f64_load" (func 15)) + (export "i32_store16" (func 16)) + (export "i32_store" (func 17)) + (export "i64_store16" (func 18)) + (export "i64_store32" (func 19)) + (export "i64_store" (func 20)) + (export "f32_store" (func 21)) + (export "f64_store" (func 22)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/0.print new file mode 100644 index 0000000000..eabd027945 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/0.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f32) + i64.const 0 + f32.load + ) + (func (;1;) (type 1) (result i32) + i64.const 0 + i32.load + ) + (func (;2;) (type 2) + i64.const 0 + f32.const nan:0x200000 (;=NaN;) + f32.store + ) + (func (;3;) (type 2) + i64.const 0 + i32.const 2141192192 + i32.store + ) + (func (;4;) (type 2) + i64.const 0 + i32.const 0 + i32.store + ) + (memory (;0;) i64 1 1) + (export "f32.load" (func 0)) + (export "i32.load" (func 1)) + (export "f32.store" (func 2)) + (export "i32.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i64.const 0) "\00\00\a0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/15.print b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/15.print new file mode 100644 index 0000000000..e5b670081a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/15.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f64))) + (type (;1;) (func (result i64))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f64) + i64.const 0 + f64.load + ) + (func (;1;) (type 1) (result i64) + i64.const 0 + i64.load + ) + (func (;2;) (type 2) + i64.const 0 + f64.const nan:0x4000000000000 (;=NaN;) + f64.store + ) + (func (;3;) (type 2) + i64.const 0 + i64.const 9219994337134247936 + i64.store + ) + (func (;4;) (type 2) + i64.const 0 + i64.const 0 + i64.store + ) + (memory (;0;) i64 1 1) + (export "f64.load" (func 0)) + (export "i64.load" (func 1)) + (export "f64.store" (func 2)) + (export "i64.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i64.const 0) "\00\00\00\00\00\00\f4\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/30.print b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/30.print new file mode 100644 index 0000000000..872dc0cbc1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/30.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f32) + i64.const 1 + f32.load + ) + (func (;1;) (type 1) (result i32) + i64.const 1 + i32.load + ) + (func (;2;) (type 2) + i64.const 1 + f32.const nan:0x200000 (;=NaN;) + f32.store + ) + (func (;3;) (type 2) + i64.const 1 + i32.const 2141192192 + i32.store + ) + (func (;4;) (type 2) + i64.const 1 + i32.const 0 + i32.store + ) + (memory (;0;) i64 1 1) + (export "f32.load" (func 0)) + (export "i32.load" (func 1)) + (export "f32.store" (func 2)) + (export "i32.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i64.const 0) "\00\00\00\a0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/45.print b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/45.print new file mode 100644 index 0000000000..c8be4ad8f0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/45.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f64))) + (type (;1;) (func (result i64))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f64) + i64.const 1 + f64.load + ) + (func (;1;) (type 1) (result i64) + i64.const 1 + i64.load + ) + (func (;2;) (type 2) + i64.const 1 + f64.const nan:0x4000000000000 (;=NaN;) + f64.store + ) + (func (;3;) (type 2) + i64.const 1 + i64.const 9219994337134247936 + i64.store + ) + (func (;4;) (type 2) + i64.const 1 + i64.const 0 + i64.store + ) + (memory (;0;) i64 1 1) + (export "f64.load" (func 0)) + (export "i64.load" (func 1)) + (export "f64.store" (func 2)) + (export "i64.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i64.const 0) "\00\00\00\00\00\00\00\f4\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/60.print b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/60.print new file mode 100644 index 0000000000..41e9330020 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/60.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f32) + i64.const 0 + f32.load + ) + (func (;1;) (type 1) (result i32) + i64.const 0 + i32.load + ) + (func (;2;) (type 2) + i64.const 0 + f32.const nan:0x500001 (;=NaN;) + f32.store + ) + (func (;3;) (type 2) + i64.const 0 + i32.const 2144337921 + i32.store + ) + (func (;4;) (type 2) + i64.const 0 + i32.const 0 + i32.store + ) + (memory (;0;) i64 1 1) + (export "f32.load" (func 0)) + (export "i32.load" (func 1)) + (export "f32.store" (func 2)) + (export "i32.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i64.const 0) "\01\00\d0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/75.print b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/75.print new file mode 100644 index 0000000000..57627f1d37 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/float_memory64.wast/75.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func (result f64))) + (type (;1;) (func (result i64))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f64) + i64.const 0 + f64.load + ) + (func (;1;) (type 1) (result i64) + i64.const 0 + i64.load + ) + (func (;2;) (type 2) + i64.const 0 + f64.const nan:0xc000000000001 (;=NaN;) + f64.store + ) + (func (;3;) (type 2) + i64.const 0 + i64.const 9222246136947933185 + i64.store + ) + (func (;4;) (type 2) + i64.const 0 + i64.const 0 + i64.store + ) + (memory (;0;) i64 1 1) + (export "f64.load" (func 0)) + (export "i64.load" (func 1)) + (export "f64.store" (func 2)) + (export "i64.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (i64.const 0) "\01\00\00\00\00\00\fc\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/load64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/load64.wast/0.print new file mode 100644 index 0000000000..f1aaa931d9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/load64.wast/0.print @@ -0,0 +1,307 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (type (;3;) (func (param i32 i32) (result i32))) + (type (;4;) (func (result i64))) + (func (;0;) (type 1) (result i32) + block (result i32) ;; label = @1 + i64.const 0 + i32.load + br 0 (;@1;) + end + ) + (func (;1;) (type 2) + block ;; label = @1 + i64.const 0 + i32.load + br_if 0 (;@1;) + end + ) + (func (;2;) (type 1) (result i32) + block (result i32) ;; label = @1 + i64.const 0 + i32.load + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;3;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i64.const 0 + i32.load + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;4;) (type 2) + block ;; label = @1 + i64.const 0 + i32.load + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;5;) (type 1) (result i32) + block (result i32) ;; label = @1 + i64.const 0 + i32.load + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;6;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i64.const 0 + i32.load + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;7;) (type 1) (result i32) + i64.const 0 + i32.load + return + ) + (func (;8;) (type 1) (result i32) + i64.const 0 + i32.load + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;9;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i64.const 0 + i32.load + else + i32.const 0 + end + ) + (func (;10;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 0 + else + i64.const 0 + i32.load + end + ) + (func (;11;) (type 3) (param i32 i32) (result i32) + i64.const 0 + i32.load + local.get 0 + local.get 1 + select + ) + (func (;12;) (type 3) (param i32 i32) (result i32) + local.get 0 + i64.const 0 + i32.load + local.get 1 + select + ) + (func (;13;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i64.const 0 + i32.load + select + ) + (func $f (;14;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;15;) (type 1) (result i32) + i64.const 0 + i32.load + i32.const 2 + i32.const 3 + call $f + ) + (func (;16;) (type 1) (result i32) + i32.const 1 + i64.const 0 + i32.load + i32.const 3 + call $f + ) + (func (;17;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i64.const 0 + i32.load + call $f + ) + (func (;18;) (type 1) (result i32) + i64.const 0 + i32.load + i32.const 2 + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;19;) (type 1) (result i32) + i32.const 1 + i64.const 0 + i32.load + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;20;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i64.const 0 + i32.load + i32.const 0 + call_indirect (type $sig) + ) + (func (;21;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + i64.const 0 + i32.load + call_indirect (type $sig) + ) + (func (;22;) (type 2) + (local i32) + i64.const 0 + i32.load + local.set 0 + ) + (func (;23;) (type 1) (result i32) + (local i32) + i64.const 0 + i32.load + local.tee 0 + ) + (func (;24;) (type 2) + (local i32) + i64.const 0 + i32.load + global.set $g + ) + (func (;25;) (type 1) (result i32) + i64.const 0 + i64.load + i32.load + ) + (func (;26;) (type 1) (result i32) + i64.const 0 + i64.load + i32.load8_s + ) + (func (;27;) (type 2) + i64.const 0 + i64.load + i32.const 7 + i32.store + ) + (func (;28;) (type 2) + i64.const 2 + i64.const 0 + i32.load + i32.store + ) + (func (;29;) (type 2) + i64.const 0 + i64.load8_s + i32.const 7 + i32.store8 + ) + (func (;30;) (type 2) + i64.const 2 + i64.const 0 + i32.load + i32.store16 + ) + (func (;31;) (type 1) (result i32) + i64.const 100 + i32.load + i32.clz + ) + (func (;32;) (type 1) (result i32) + i64.const 100 + i32.load + i32.const 10 + i32.add + ) + (func (;33;) (type 1) (result i32) + i32.const 10 + i64.const 100 + i32.load + i32.sub + ) + (func (;34;) (type 1) (result i32) + i64.const 100 + i32.load + i32.eqz + ) + (func (;35;) (type 1) (result i32) + i64.const 100 + i32.load + i32.const 10 + i32.le_s + ) + (func (;36;) (type 1) (result i32) + i32.const 10 + i64.const 100 + i32.load + i32.ne + ) + (func (;37;) (type 4) (result i64) + i64.const 100 + i64.load + memory.grow + ) + (table (;0;) 1 1 funcref) + (memory (;0;) i64 1) + (global $g (;0;) (mut i32) i32.const 0) + (export "as-br-value" (func 0)) + (export "as-br_if-cond" (func 1)) + (export "as-br_if-value" (func 2)) + (export "as-br_if-value-cond" (func 3)) + (export "as-br_table-index" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-br_table-value-index" (func 6)) + (export "as-return-value" (func 7)) + (export "as-if-cond" (func 8)) + (export "as-if-then" (func 9)) + (export "as-if-else" (func 10)) + (export "as-select-first" (func 11)) + (export "as-select-second" (func 12)) + (export "as-select-cond" (func 13)) + (export "as-call-first" (func 15)) + (export "as-call-mid" (func 16)) + (export "as-call-last" (func 17)) + (export "as-call_indirect-first" (func 18)) + (export "as-call_indirect-mid" (func 19)) + (export "as-call_indirect-last" (func 20)) + (export "as-call_indirect-index" (func 21)) + (export "as-local.set-value" (func 22)) + (export "as-local.tee-value" (func 23)) + (export "as-global.set-value" (func 24)) + (export "as-load-address" (func 25)) + (export "as-loadN-address" (func 26)) + (export "as-store-address" (func 27)) + (export "as-store-value" (func 28)) + (export "as-storeN-address" (func 29)) + (export "as-storeN-value" (func 30)) + (export "as-unary-operand" (func 31)) + (export "as-binary-left" (func 32)) + (export "as-binary-right" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-left" (func 35)) + (export "as-compare-right" (func 36)) + (export "as-memory.grow-size" (func 37)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/0.print new file mode 100644 index 0000000000..36938759b9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/0.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/1.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/1.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/1.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/10.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/10.print new file mode 100644 index 0000000000..0cdda46d31 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/10.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0 0) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/12.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/12.print new file mode 100644 index 0000000000..94e698954c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/12.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 1 1) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "x") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/2.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/2.print new file mode 100644 index 0000000000..d76aa6a0fa --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/2.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/3.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/3.print new file mode 100644 index 0000000000..0f5c3ea229 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/3.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/33.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/33.print new file mode 100644 index 0000000000..1dc6026a7b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/33.print @@ -0,0 +1,154 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result f64))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i64) (result i64))) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.load8_u + i32.const 65 + i32.eq + i32.const 3 + i32.load8_u + i32.const 167 + i32.eq + i32.and + i32.const 6 + i32.load8_u + i32.const 0 + i32.eq + i32.const 19 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.const 20 + i32.load8_u + i32.const 87 + i32.eq + i32.const 23 + i32.load8_u + i32.const 77 + i32.eq + i32.and + i32.const 24 + i32.load8_u + i32.const 0 + i32.eq + i32.const 1023 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.and + ) + (func (;1;) (type 1) (result f64) + i32.const 8 + i64.const -12345 + i64.store + i32.const 8 + f64.load + i64.const -12345 + f64.reinterpret_i64 + f64.eq + if ;; label = @1 + f64.const 0x0p+0 (;=0;) + return + end + i32.const 9 + i64.const 0 + i64.store align=1 + i32.const 15 + i32.const 16453 + i32.store16 align=1 + i32.const 9 + f64.load align=1 + ) + (func (;2;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store8 + i32.const 8 + i32.load8_s + ) + (func (;3;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store8 + i32.const 8 + i32.load8_u + ) + (func (;4;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store16 + i32.const 8 + i32.load16_s + ) + (func (;5;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store16 + i32.const 8 + i32.load16_u + ) + (func (;6;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store8 + i32.const 8 + i64.load8_s + ) + (func (;7;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store8 + i32.const 8 + i64.load8_u + ) + (func (;8;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store16 + i32.const 8 + i64.load16_s + ) + (func (;9;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store16 + i32.const 8 + i64.load16_u + ) + (func (;10;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store32 + i32.const 8 + i64.load32_s + ) + (func (;11;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store32 + i32.const 8 + i64.load32_u + ) + (memory (;0;) 1) + (export "data" (func 0)) + (export "cast" (func 1)) + (export "i32_load8_s" (func 2)) + (export "i32_load8_u" (func 3)) + (export "i32_load16_s" (func 4)) + (export "i32_load16_u" (func 5)) + (export "i64_load8_s" (func 6)) + (export "i64_load8_u" (func 7)) + (export "i64_load16_s" (func 8)) + (export "i64_load16_u" (func 9)) + (export "i64_load32_s" (func 10)) + (export "i64_load32_u" (func 11)) + (data (;0;) (i32.const 0) "ABC\a7D") + (data (;1;) (i32.const 20) "WASM") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/4.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/4.print new file mode 100644 index 0000000000..d280c1e33b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/4.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1 256) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/5.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/5.print new file mode 100644 index 0000000000..21d5f6b5c9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/5.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 65536) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory.wast/8.print b/tests/snapshots/testsuite/proposals/memory64/memory.wast/8.print new file mode 100644 index 0000000000..0cdda46d31 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory.wast/8.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0 0) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/0.print new file mode 100644 index 0000000000..8df4919bf5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/0.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) i64 0 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory64.wast/1.print b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/1.print new file mode 100644 index 0000000000..a0a7abddea --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/1.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) i64 0 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory64.wast/10.print b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/10.print new file mode 100644 index 0000000000..038e96ce41 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/10.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i64))) + (func (;0;) (type 0) (result i64) + memory.size + ) + (memory (;0;) i64 1 1) + (export "memsize" (func 0)) + (data (;0;) (i64.const 0) "x") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory64.wast/2.print b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/2.print new file mode 100644 index 0000000000..d55d056021 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/2.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) i64 1 256) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory64.wast/22.print b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/22.print new file mode 100644 index 0000000000..f731f5f78c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/22.print @@ -0,0 +1,154 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result f64))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i64) (result i64))) + (func (;0;) (type 0) (result i32) + i64.const 0 + i32.load8_u + i32.const 65 + i32.eq + i64.const 3 + i32.load8_u + i32.const 167 + i32.eq + i32.and + i64.const 6 + i32.load8_u + i32.const 0 + i32.eq + i64.const 19 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i64.const 20 + i32.load8_u + i32.const 87 + i32.eq + i64.const 23 + i32.load8_u + i32.const 77 + i32.eq + i32.and + i64.const 24 + i32.load8_u + i32.const 0 + i32.eq + i64.const 1023 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.and + ) + (func (;1;) (type 1) (result f64) + i64.const 8 + i64.const -12345 + i64.store + i64.const 8 + f64.load + i64.const -12345 + f64.reinterpret_i64 + f64.eq + if ;; label = @1 + f64.const 0x0p+0 (;=0;) + return + end + i64.const 9 + i64.const 0 + i64.store align=1 + i64.const 15 + i32.const 16453 + i32.store16 align=1 + i64.const 9 + f64.load align=1 + ) + (func (;2;) (type 2) (param $i i32) (result i32) + i64.const 8 + local.get $i + i32.store8 + i64.const 8 + i32.load8_s + ) + (func (;3;) (type 2) (param $i i32) (result i32) + i64.const 8 + local.get $i + i32.store8 + i64.const 8 + i32.load8_u + ) + (func (;4;) (type 2) (param $i i32) (result i32) + i64.const 8 + local.get $i + i32.store16 + i64.const 8 + i32.load16_s + ) + (func (;5;) (type 2) (param $i i32) (result i32) + i64.const 8 + local.get $i + i32.store16 + i64.const 8 + i32.load16_u + ) + (func (;6;) (type 3) (param $i i64) (result i64) + i64.const 8 + local.get $i + i64.store8 + i64.const 8 + i64.load8_s + ) + (func (;7;) (type 3) (param $i i64) (result i64) + i64.const 8 + local.get $i + i64.store8 + i64.const 8 + i64.load8_u + ) + (func (;8;) (type 3) (param $i i64) (result i64) + i64.const 8 + local.get $i + i64.store16 + i64.const 8 + i64.load16_s + ) + (func (;9;) (type 3) (param $i i64) (result i64) + i64.const 8 + local.get $i + i64.store16 + i64.const 8 + i64.load16_u + ) + (func (;10;) (type 3) (param $i i64) (result i64) + i64.const 8 + local.get $i + i64.store32 + i64.const 8 + i64.load32_s + ) + (func (;11;) (type 3) (param $i i64) (result i64) + i64.const 8 + local.get $i + i64.store32 + i64.const 8 + i64.load32_u + ) + (memory (;0;) i64 1) + (export "data" (func 0)) + (export "cast" (func 1)) + (export "i32_load8_s" (func 2)) + (export "i32_load8_u" (func 3)) + (export "i32_load16_s" (func 4)) + (export "i32_load16_u" (func 5)) + (export "i64_load8_s" (func 6)) + (export "i64_load8_u" (func 7)) + (export "i64_load16_s" (func 8)) + (export "i64_load16_u" (func 9)) + (export "i64_load32_s" (func 10)) + (export "i64_load32_u" (func 11)) + (data (;0;) (i64.const 0) "ABC\a7D") + (data (;1;) (i64.const 20) "WASM") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory64.wast/3.print b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/3.print new file mode 100644 index 0000000000..3a0b90128a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/3.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) i64 0 65536) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory64.wast/6.print b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/6.print new file mode 100644 index 0000000000..aa6eac1e0f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/6.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i64))) + (func (;0;) (type 0) (result i64) + memory.size + ) + (memory (;0;) i64 0 0) + (export "memsize" (func 0)) + (data (;0;) (i64.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory64.wast/8.print b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/8.print new file mode 100644 index 0000000000..aa6eac1e0f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory64.wast/8.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i64))) + (func (;0;) (type 0) (result i64) + memory.size + ) + (memory (;0;) i64 0 0) + (export "memsize" (func 0)) + (data (;0;) (i64.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/0.print new file mode 100644 index 0000000000..56fd9a9966 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/0.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i64) (result i64))) + (type (;3;) (func (result i64))) + (func (;0;) (type 0) (result i32) + i64.const 0 + i32.load + ) + (func (;1;) (type 1) + i64.const 0 + i32.const 2 + i32.store + ) + (func (;2;) (type 0) (result i32) + i64.const 65536 + i32.load + ) + (func (;3;) (type 1) + i64.const 65536 + i32.const 3 + i32.store + ) + (func (;4;) (type 2) (param $sz i64) (result i64) + local.get $sz + memory.grow + ) + (func (;5;) (type 3) (result i64) + memory.size + ) + (memory (;0;) i64 0) + (export "load_at_zero" (func 0)) + (export "store_at_zero" (func 1)) + (export "load_at_page_size" (func 2)) + (export "store_at_page_size" (func 3)) + (export "grow" (func 4)) + (export "size" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/21.print b/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/21.print new file mode 100644 index 0000000000..972b607a48 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/21.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param i64) (result i64) + local.get 0 + memory.grow + ) + (memory (;0;) i64 0) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/28.print b/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/28.print new file mode 100644 index 0000000000..d77c87cc63 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/28.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (func (;0;) (type 0) (param i64) (result i64) + local.get 0 + memory.grow + ) + (memory (;0;) i64 0 10) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/37.print b/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/37.print new file mode 100644 index 0000000000..3ff0c4fd65 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory_grow64.wast/37.print @@ -0,0 +1,40 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (type (;1;) (func (param i64 i64) (result i32))) + (func (;0;) (type 0) (param i64) (result i64) + local.get 0 + memory.grow + ) + (func (;1;) (type 1) (param i64 i64) (result i32) + (local i32) + i32.const 1 + local.set 2 + block ;; label = @1 + loop ;; label = @2 + local.get 0 + i32.load8_u + local.set 2 + local.get 2 + i32.const 0 + i32.ne + br_if 1 (;@1;) + local.get 0 + local.get 1 + i64.ge_u + br_if 1 (;@1;) + local.get 0 + i64.const 1 + i64.add + local.set 0 + local.get 0 + local.get 1 + i64.le_u + br_if 0 (;@2;) + end + end + local.get 2 + ) + (memory (;0;) i64 1) + (export "grow" (func 0)) + (export "check-memory-zero" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory_redundancy64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/memory_redundancy64.wast/0.print new file mode 100644 index 0000000000..a1e3728137 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory_redundancy64.wast/0.print @@ -0,0 +1,85 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (result f32))) + (type (;3;) (func (param i64) (result i64))) + (func (;0;) (type 0) + i64.const 0 + i32.const 0 + i32.store + i64.const 4 + i32.const 0 + i32.store + i64.const 8 + i32.const 0 + i32.store + i64.const 12 + i32.const 0 + i32.store + ) + (func (;1;) (type 1) (result i32) + i64.const 8 + i32.const 0 + i32.store + i64.const 5 + f32.const -0x0p+0 (;=-0;) + f32.store + i64.const 8 + i32.load + ) + (func (;2;) (type 1) (result i32) + (local $t i32) (local $s i32) + i64.const 8 + i32.load + local.set $t + i64.const 5 + i32.const -2147483648 + i32.store + i64.const 8 + i32.load + local.set $s + local.get $t + local.get $s + i32.add + ) + (func (;3;) (type 2) (result f32) + (local $t f32) + i64.const 8 + i32.const 589505315 + i32.store + i64.const 11 + f32.load + local.set $t + i64.const 8 + i32.const 0 + i32.store + local.get $t + ) + (func $malloc (;4;) (type 3) (param $size i64) (result i64) + i64.const 16 + ) + (func (;5;) (type 1) (result i32) + (local $x i64) (local $y i64) + i64.const 4 + call $malloc + local.set $x + i64.const 4 + call $malloc + local.set $y + local.get $x + i32.const 42 + i32.store + local.get $y + i32.const 43 + i32.store + local.get $x + i32.load + ) + (memory (;0;) i64 1 1) + (export "zero_everything" (func 0)) + (export "test_store_to_load" (func 1)) + (export "test_redundant_load" (func 2)) + (export "test_dead_store" (func 3)) + (export "malloc" (func $malloc)) + (export "malloc_aliasing" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory_trap64.wast/0.print b/tests/snapshots/testsuite/proposals/memory64/memory_trap64.wast/0.print new file mode 100644 index 0000000000..8feb9a189b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory_trap64.wast/0.print @@ -0,0 +1,32 @@ +(module + (type (;0;) (func (result i64))) + (type (;1;) (func (param i64 i32))) + (type (;2;) (func (param i64) (result i32))) + (type (;3;) (func (param i64) (result i64))) + (func $addr_limit (;0;) (type 0) (result i64) + memory.size + i64.const 65536 + i64.mul + ) + (func (;1;) (type 1) (param $i i64) (param $v i32) + call $addr_limit + local.get $i + i64.add + local.get $v + i32.store + ) + (func (;2;) (type 2) (param $i i64) (result i32) + call $addr_limit + local.get $i + i64.add + i32.load + ) + (func (;3;) (type 3) (param i64) (result i64) + local.get 0 + memory.grow + ) + (memory (;0;) i64 1) + (export "store" (func 1)) + (export "load" (func 2)) + (export "memory.grow" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/memory64/memory_trap64.wast/13.print b/tests/snapshots/testsuite/proposals/memory64/memory_trap64.wast/13.print new file mode 100644 index 0000000000..ba74f0a88b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/memory64/memory_trap64.wast/13.print @@ -0,0 +1,137 @@ +(module + (type (;0;) (func (param i64) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (type (;2;) (func (param i64) (result f32))) + (type (;3;) (func (param i64) (result f64))) + (type (;4;) (func (param i64 i32))) + (type (;5;) (func (param i64 i64))) + (type (;6;) (func (param i64 f32))) + (type (;7;) (func (param i64 f64))) + (func (;0;) (type 0) (param $a i64) (result i32) + local.get $a + i32.load + ) + (func (;1;) (type 1) (param $a i64) (result i64) + local.get $a + i64.load + ) + (func (;2;) (type 2) (param $a i64) (result f32) + local.get $a + f32.load + ) + (func (;3;) (type 3) (param $a i64) (result f64) + local.get $a + f64.load + ) + (func (;4;) (type 0) (param $a i64) (result i32) + local.get $a + i32.load8_s + ) + (func (;5;) (type 0) (param $a i64) (result i32) + local.get $a + i32.load8_u + ) + (func (;6;) (type 0) (param $a i64) (result i32) + local.get $a + i32.load16_s + ) + (func (;7;) (type 0) (param $a i64) (result i32) + local.get $a + i32.load16_u + ) + (func (;8;) (type 1) (param $a i64) (result i64) + local.get $a + i64.load8_s + ) + (func (;9;) (type 1) (param $a i64) (result i64) + local.get $a + i64.load8_u + ) + (func (;10;) (type 1) (param $a i64) (result i64) + local.get $a + i64.load16_s + ) + (func (;11;) (type 1) (param $a i64) (result i64) + local.get $a + i64.load16_u + ) + (func (;12;) (type 1) (param $a i64) (result i64) + local.get $a + i64.load32_s + ) + (func (;13;) (type 1) (param $a i64) (result i64) + local.get $a + i64.load32_u + ) + (func (;14;) (type 4) (param $a i64) (param $v i32) + local.get $a + local.get $v + i32.store + ) + (func (;15;) (type 5) (param $a i64) (param $v i64) + local.get $a + local.get $v + i64.store + ) + (func (;16;) (type 6) (param $a i64) (param $v f32) + local.get $a + local.get $v + f32.store + ) + (func (;17;) (type 7) (param $a i64) (param $v f64) + local.get $a + local.get $v + f64.store + ) + (func (;18;) (type 4) (param $a i64) (param $v i32) + local.get $a + local.get $v + i32.store8 + ) + (func (;19;) (type 4) (param $a i64) (param $v i32) + local.get $a + local.get $v + i32.store16 + ) + (func (;20;) (type 5) (param $a i64) (param $v i64) + local.get $a + local.get $v + i64.store8 + ) + (func (;21;) (type 5) (param $a i64) (param $v i64) + local.get $a + local.get $v + i64.store16 + ) + (func (;22;) (type 5) (param $a i64) (param $v i64) + local.get $a + local.get $v + i64.store32 + ) + (memory (;0;) i64 1) + (export "i32.load" (func 0)) + (export "i64.load" (func 1)) + (export "f32.load" (func 2)) + (export "f64.load" (func 3)) + (export "i32.load8_s" (func 4)) + (export "i32.load8_u" (func 5)) + (export "i32.load16_s" (func 6)) + (export "i32.load16_u" (func 7)) + (export "i64.load8_s" (func 8)) + (export "i64.load8_u" (func 9)) + (export "i64.load16_s" (func 10)) + (export "i64.load16_u" (func 11)) + (export "i64.load32_s" (func 12)) + (export "i64.load32_u" (func 13)) + (export "i32.store" (func 14)) + (export "i64.store" (func 15)) + (export "f32.store" (func 16)) + (export "f64.store" (func 17)) + (export "i32.store8" (func 18)) + (export "i32.store16" (func 19)) + (export "i64.store8" (func 20)) + (export "i64.store16" (func 21)) + (export "i64.store32" (func 22)) + (data (;0;) (i64.const 0) "abcdefgh") + (data (;1;) (i64.const 65528) "abcdefgh") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/address0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/address0.wast/0.print new file mode 100644 index 0000000000..6018e788b8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/address0.wast/0.print @@ -0,0 +1,162 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u $mem1 + ) + (func (;1;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u $mem1 + ) + (func (;2;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u $mem1 offset=1 + ) + (func (;3;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u $mem1 offset=2 + ) + (func (;4;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_u $mem1 offset=25 + ) + (func (;5;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s $mem1 + ) + (func (;6;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s $mem1 + ) + (func (;7;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s $mem1 offset=1 + ) + (func (;8;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s $mem1 offset=2 + ) + (func (;9;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load8_s $mem1 offset=25 + ) + (func (;10;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u $mem1 + ) + (func (;11;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u $mem1 align=1 + ) + (func (;12;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u $mem1 offset=1 align=1 + ) + (func (;13;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u $mem1 offset=2 + ) + (func (;14;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_u $mem1 offset=25 + ) + (func (;15;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s $mem1 + ) + (func (;16;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s $mem1 align=1 + ) + (func (;17;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s $mem1 offset=1 align=1 + ) + (func (;18;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s $mem1 offset=2 + ) + (func (;19;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load16_s $mem1 offset=25 + ) + (func (;20;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load $mem1 + ) + (func (;21;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load $mem1 align=1 + ) + (func (;22;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load $mem1 offset=1 align=1 + ) + (func (;23;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load $mem1 offset=2 align=2 + ) + (func (;24;) (type 0) (param $i i32) (result i32) + local.get $i + i32.load $mem1 offset=25 + ) + (func (;25;) (type 1) (param $i i32) + local.get $i + i32.load8_u $mem1 offset=4294967295 + drop + ) + (func (;26;) (type 1) (param $i i32) + local.get $i + i32.load8_s $mem1 offset=4294967295 + drop + ) + (func (;27;) (type 1) (param $i i32) + local.get $i + i32.load16_u $mem1 offset=4294967295 + drop + ) + (func (;28;) (type 1) (param $i i32) + local.get $i + i32.load16_s $mem1 offset=4294967295 + drop + ) + (func (;29;) (type 1) (param $i i32) + local.get $i + i32.load $mem1 offset=4294967295 + drop + ) + (memory $mem0 (;0;) 0) + (memory $mem1 (;1;) 1) + (export "8u_good1" (func 0)) + (export "8u_good2" (func 1)) + (export "8u_good3" (func 2)) + (export "8u_good4" (func 3)) + (export "8u_good5" (func 4)) + (export "8s_good1" (func 5)) + (export "8s_good2" (func 6)) + (export "8s_good3" (func 7)) + (export "8s_good4" (func 8)) + (export "8s_good5" (func 9)) + (export "16u_good1" (func 10)) + (export "16u_good2" (func 11)) + (export "16u_good3" (func 12)) + (export "16u_good4" (func 13)) + (export "16u_good5" (func 14)) + (export "16s_good1" (func 15)) + (export "16s_good2" (func 16)) + (export "16s_good3" (func 17)) + (export "16s_good4" (func 18)) + (export "16s_good5" (func 19)) + (export "32_good1" (func 20)) + (export "32_good2" (func 21)) + (export "32_good3" (func 22)) + (export "32_good4" (func 23)) + (export "32_good5" (func 24)) + (export "8u_bad" (func 25)) + (export "8s_bad" (func 26)) + (export "16u_bad" (func 27)) + (export "16s_bad" (func 28)) + (export "32_bad" (func 29)) + (data (;0;) (memory $mem1) (i32.const 0) "abcdefghijklmnopqrstuvwxyz") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/address1.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/address1.wast/0.print new file mode 100644 index 0000000000..2acc6b8441 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/address1.wast/0.print @@ -0,0 +1,227 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u $mem4 + ) + (func (;1;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u $mem4 + ) + (func (;2;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u $mem4 offset=1 + ) + (func (;3;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u $mem4 offset=2 + ) + (func (;4;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_u $mem4 offset=25 + ) + (func (;5;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s $mem4 + ) + (func (;6;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s $mem4 + ) + (func (;7;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s $mem4 offset=1 + ) + (func (;8;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s $mem4 offset=2 + ) + (func (;9;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load8_s $mem4 offset=25 + ) + (func (;10;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u $mem4 + ) + (func (;11;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u $mem4 align=1 + ) + (func (;12;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u $mem4 offset=1 align=1 + ) + (func (;13;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u $mem4 offset=2 + ) + (func (;14;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_u $mem4 offset=25 + ) + (func (;15;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s $mem4 + ) + (func (;16;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s $mem4 align=1 + ) + (func (;17;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s $mem4 offset=1 align=1 + ) + (func (;18;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s $mem4 offset=2 + ) + (func (;19;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load16_s $mem4 offset=25 + ) + (func (;20;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u $mem4 + ) + (func (;21;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u $mem4 align=1 + ) + (func (;22;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u $mem4 offset=1 align=1 + ) + (func (;23;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u $mem4 offset=2 align=2 + ) + (func (;24;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_u $mem4 offset=25 + ) + (func (;25;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s $mem4 + ) + (func (;26;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s $mem4 align=1 + ) + (func (;27;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s $mem4 offset=1 align=1 + ) + (func (;28;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s $mem4 offset=2 align=2 + ) + (func (;29;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load32_s $mem4 offset=25 + ) + (func (;30;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load $mem4 + ) + (func (;31;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load $mem4 align=1 + ) + (func (;32;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load $mem4 offset=1 align=1 + ) + (func (;33;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load $mem4 offset=2 align=2 + ) + (func (;34;) (type 0) (param $i i32) (result i64) + local.get $i + i64.load $mem4 offset=25 + ) + (func (;35;) (type 1) (param $i i32) + local.get $i + i64.load8_u $mem4 offset=4294967295 + drop + ) + (func (;36;) (type 1) (param $i i32) + local.get $i + i64.load8_s $mem4 offset=4294967295 + drop + ) + (func (;37;) (type 1) (param $i i32) + local.get $i + i64.load16_u $mem4 offset=4294967295 + drop + ) + (func (;38;) (type 1) (param $i i32) + local.get $i + i64.load16_s $mem4 offset=4294967295 + drop + ) + (func (;39;) (type 1) (param $i i32) + local.get $i + i64.load32_u $mem4 offset=4294967295 + drop + ) + (func (;40;) (type 1) (param $i i32) + local.get $i + i64.load32_s $mem4 offset=4294967295 + drop + ) + (func (;41;) (type 1) (param $i i32) + local.get $i + i64.load $mem4 offset=4294967295 + drop + ) + (memory $mem0 (;0;) 0) + (memory $mem1 (;1;) 0) + (memory $mem2 (;2;) 0) + (memory $mem3 (;3;) 0) + (memory $mem4 (;4;) 1) + (export "8u_good1" (func 0)) + (export "8u_good2" (func 1)) + (export "8u_good3" (func 2)) + (export "8u_good4" (func 3)) + (export "8u_good5" (func 4)) + (export "8s_good1" (func 5)) + (export "8s_good2" (func 6)) + (export "8s_good3" (func 7)) + (export "8s_good4" (func 8)) + (export "8s_good5" (func 9)) + (export "16u_good1" (func 10)) + (export "16u_good2" (func 11)) + (export "16u_good3" (func 12)) + (export "16u_good4" (func 13)) + (export "16u_good5" (func 14)) + (export "16s_good1" (func 15)) + (export "16s_good2" (func 16)) + (export "16s_good3" (func 17)) + (export "16s_good4" (func 18)) + (export "16s_good5" (func 19)) + (export "32u_good1" (func 20)) + (export "32u_good2" (func 21)) + (export "32u_good3" (func 22)) + (export "32u_good4" (func 23)) + (export "32u_good5" (func 24)) + (export "32s_good1" (func 25)) + (export "32s_good2" (func 26)) + (export "32s_good3" (func 27)) + (export "32s_good4" (func 28)) + (export "32s_good5" (func 29)) + (export "64_good1" (func 30)) + (export "64_good2" (func 31)) + (export "64_good3" (func 32)) + (export "64_good4" (func 33)) + (export "64_good5" (func 34)) + (export "8u_bad" (func 35)) + (export "8s_bad" (func 36)) + (export "16u_bad" (func 37)) + (export "16s_bad" (func 38)) + (export "32u_bad" (func 39)) + (export "32s_bad" (func 40)) + (export "64_bad" (func 41)) + (data (;0;) (memory $mem4) (i32.const 0) "abcdefghijklmnopqrstuvwxyz") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/align0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/align0.wast/0.print new file mode 100644 index 0000000000..2e1aa8fccf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/align0.wast/0.print @@ -0,0 +1,52 @@ +(module + (type (;0;) (func (param i32) (result f32))) + (func (;0;) (type 0) (param i32) (result f32) + (local f32 f32) + f32.const 0x1.4p+3 (;=10;) + local.set 1 + block $4 ;; label = @1 + block $2 ;; label = @2 + block $1 ;; label = @3 + block $default ;; label = @4 + block $0 ;; label = @5 + local.get 0 + br_table 0 (;@5;) 1 (;@4;) 2 (;@3;) 3 (;@2;) 4 (;@1;) + end + i32.const 0 + local.get 1 + f32.store $mem1 + i32.const 0 + f32.load $mem1 + local.set 2 + br 3 (;@1;) + end + i32.const 0 + local.get 1 + f32.store $mem1 align=1 + i32.const 0 + f32.load $mem1 align=1 + local.set 2 + br 2 (;@1;) + end + i32.const 0 + local.get 1 + f32.store $mem1 align=2 + i32.const 0 + f32.load $mem1 align=2 + local.set 2 + br 1 (;@1;) + end + i32.const 0 + local.get 1 + f32.store $mem1 + i32.const 0 + f32.load $mem1 + local.set 2 + end + local.get 2 + ) + (memory $mem0 (;0;) 0) + (memory $mem1 (;1;) 1) + (memory $mem2 (;2;) 0) + (export "f32_align_switch" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/0.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/0.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/1.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/1.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/1.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/100.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/100.print new file mode 100644 index 0000000000..a2354a64c3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/100.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (start 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/2.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/2.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/3.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/3.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/3.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/45.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/45.print new file mode 100644 index 0000000000..3171d8f4fb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/45.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local f32 f32) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/50.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/50.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/50.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/51.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/51.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/51.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/58.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/58.print new file mode 100644 index 0000000000..a72fa86b64 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/58.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/59.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/59.print new file mode 100644 index 0000000000..8a3ff91247 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/59.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 0 funcref) + (memory (;0;) 0) + (elem (;0;) funcref (ref.null func)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/60.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/60.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/60.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/63.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/63.print new file mode 100644 index 0000000000..c47d05badc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/63.print @@ -0,0 +1,3 @@ +(module + (type (;0;) (func (param i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/72.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/72.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/72.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/77.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/77.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/77.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/83.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/83.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/83.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/86.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/86.print new file mode 100644 index 0000000000..1270a74e97 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/86.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/89.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/89.print new file mode 100644 index 0000000000..a0fe812a51 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/89.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/93.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/93.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/93.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/98.print b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/98.print new file mode 100644 index 0000000000..17f0618fdf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary.wast/98.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 1 + if ;; label = @2 + i32.const 1 + br_table 2 (;@0;) + end + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/0.print new file mode 100644 index 0000000000..e2e9606d8b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/0.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 2) + (memory (;1;) 2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/1.print b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/1.print new file mode 100644 index 0000000000..9d0427ac76 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/1.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 3) + (memory (;1;) 4) + (memory (;2;) 5) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/2.print new file mode 100644 index 0000000000..2e5ac552f9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/2.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 0) + (memory (;1;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/3.print b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/3.print new file mode 100644 index 0000000000..3de8db3d06 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/3.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 0) + (memory (;1;) 1) + (data (;0;) (memory 1) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/4.print b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/4.print new file mode 100644 index 0000000000..3de8db3d06 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/binary0.wast/4.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 0) + (memory (;1;) 1) + (data (;0;) (memory 1) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/0.print new file mode 100644 index 0000000000..76dcc35a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/0.print @@ -0,0 +1,27 @@ +(module + (memory $m (;0;) 1) + (data (;0;) (i32.const 0) "") + (data (;1;) (i32.const 1) "abcd") + (data (;2;) (i32.const 0) "") + (data (;3;) (i32.const 0) "abc") + (data (;4;) (i32.const 0) "") + (data (;5;) (i32.const 1) "abcd") + (data (;6;) (i32.const 0) "") + (data (;7;) (i32.const 0) "abc") + (data (;8;) (i32.const 0) "") + (data (;9;) (i32.const 1) "abcd") + (data (;10;) (i32.const 0) "") + (data (;11;) (i32.const 0) "abc") + (data $d1 (;12;) (i32.const 0) "") + (data $d2 (;13;) (i32.const 1) "abcd") + (data $d3 (;14;) (i32.const 0) "") + (data $d4 (;15;) (i32.const 0) "abc") + (data $d5 (;16;) (i32.const 0) "") + (data $d6 (;17;) (i32.const 1) "abcd") + (data $d7 (;18;) (i32.const 0) "") + (data $d8 (;19;) (i32.const 0) "abc") + (data $d9 (;20;) (i32.const 0) "") + (data $d10 (;21;) (i32.const 1) "abcd") + (data $d11 (;22;) (i32.const 0) "") + (data $d12 (;23;) (i32.const 0) "abc") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/1.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/1.print new file mode 100644 index 0000000000..cc1e75fe22 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/1.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/11.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/11.print new file mode 100644 index 0000000000..0474fc6565 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/11.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 65535) "b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/12.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/12.print new file mode 100644 index 0000000000..c7cfbb07bb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/12.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 65535) "b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/13.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/13.print new file mode 100644 index 0000000000..0d6dc72126 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/13.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 2) + (data (;0;) (i32.const 131071) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/14.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/14.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/14.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/15.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/15.print new file mode 100644 index 0000000000..bb79a2b2e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/15.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/16.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/16.print new file mode 100644 index 0000000000..70d5011af0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/16.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/17.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/17.print new file mode 100644 index 0000000000..2f4c3a8d18 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/17.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 65536) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/18.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/18.print new file mode 100644 index 0000000000..1303df0853 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/18.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/19.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/19.print new file mode 100644 index 0000000000..bb79a2b2e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/19.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/2.print new file mode 100644 index 0000000000..481aec56e8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/2.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/20.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/20.print new file mode 100644 index 0000000000..70d5011af0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/20.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 0) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/21.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/21.print new file mode 100644 index 0000000000..4e08a2a6d1 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/21.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/22.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/22.print new file mode 100644 index 0000000000..376eeb676a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/22.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/23.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/23.print new file mode 100644 index 0000000000..18183a143f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/23.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/24.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/24.print new file mode 100644 index 0000000000..86be16f707 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/24.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/25.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/25.print new file mode 100644 index 0000000000..6cb38d0981 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/25.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) + (data (;0;) (i32.const 1) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/26.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/26.print new file mode 100644 index 0000000000..42df962f09 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/26.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) + (data (;0;) (i32.const 1) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/3.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/3.print new file mode 100644 index 0000000000..fbef21b722 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/3.print @@ -0,0 +1,8 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 3) "b") + (data (;2;) (i32.const 100) "cde") + (data (;3;) (i32.const 5) "x") + (data (;4;) (i32.const 3) "c") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/4.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/4.print new file mode 100644 index 0000000000..bb6a67d9e3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/4.print @@ -0,0 +1,9 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (i32.const 1) "b") + (data (;2;) (i32.const 2) "cde") + (data (;3;) (i32.const 3) "f") + (data (;4;) (i32.const 2) "g") + (data (;5;) (i32.const 1) "h") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/5.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/5.print new file mode 100644 index 0000000000..ee7a8e6fe9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/5.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/6.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/6.print new file mode 100644 index 0000000000..55a464f093 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/6.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/7.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/7.print new file mode 100644 index 0000000000..cc48f688bf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/7.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data.wast/8.print b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/8.print new file mode 100644 index 0000000000..9baa7ce142 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data.wast/8.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/0.print new file mode 100644 index 0000000000..a642ef0387 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/0.print @@ -0,0 +1,29 @@ +(module + (memory $mem0 (;0;) 1) + (memory $mem1 (;1;) 1) + (memory $mem2 (;2;) 1) + (data (;0;) (i32.const 0) "") + (data (;1;) (i32.const 1) "abcd") + (data (;2;) (i32.const 0) "") + (data (;3;) (i32.const 0) "abc") + (data (;4;) (i32.const 0) "") + (data (;5;) (i32.const 1) "abcd") + (data (;6;) (i32.const 0) "") + (data (;7;) (i32.const 0) "abc") + (data (;8;) (i32.const 0) "") + (data (;9;) (memory $mem1) (i32.const 1) "abcd") + (data (;10;) (memory $mem2) (i32.const 0) "") + (data (;11;) (i32.const 0) "abc") + (data $d1 (;12;) (i32.const 0) "") + (data $d2 (;13;) (i32.const 1) "abcd") + (data $d3 (;14;) (i32.const 0) "") + (data $d4 (;15;) (i32.const 0) "abc") + (data $d5 (;16;) (i32.const 0) "") + (data $d6 (;17;) (i32.const 1) "abcd") + (data $d7 (;18;) (i32.const 0) "") + (data $d8 (;19;) (i32.const 0) "abc") + (data $d9 (;20;) (i32.const 0) "") + (data $d10 (;21;) (memory $mem1) (i32.const 1) "abcd") + (data $d11 (;22;) (memory $mem2) (i32.const 0) "") + (data $d12 (;23;) (i32.const 0) "abc") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/1.print b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/1.print new file mode 100644 index 0000000000..cc1e75fe22 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/1.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/2.print new file mode 100644 index 0000000000..33bc61c0ac --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/2.print @@ -0,0 +1,8 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (import "spectest" "memory" (memory (;1;) 1)) + (import "spectest" "memory" (memory (;2;) 1)) + (data (;0;) (i32.const 0) "a") + (data (;1;) (memory 1) (i32.const 0) "a") + (data (;2;) (memory 2) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/3.print b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/3.print new file mode 100644 index 0000000000..ee7a8e6fe9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/3.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/4.print b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/4.print new file mode 100644 index 0000000000..55a464f093 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/4.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/5.print b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/5.print new file mode 100644 index 0000000000..cc48f688bf --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/5.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (memory (;0;) 1) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/6.print b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/6.print new file mode 100644 index 0000000000..9baa7ce142 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data0.wast/6.print @@ -0,0 +1,5 @@ +(module + (import "spectest" "global_i32" (global $g (;0;) i32)) + (import "spectest" "memory" (memory (;0;) 1)) + (data (;0;) (global.get $g) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/data_drop0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/data_drop0.wast/0.print new file mode 100644 index 0000000000..bb88ef8063 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/data_drop0.wast/0.print @@ -0,0 +1,31 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) + data.drop $p + ) + (func (;1;) (type 1) (param $len i32) + i32.const 0 + i32.const 0 + local.get $len + memory.init $mem1 $p + ) + (func (;2;) (type 0) + data.drop $a + ) + (func (;3;) (type 1) (param $len i32) + i32.const 0 + i32.const 0 + local.get $len + memory.init $mem1 $a + ) + (memory $mem0 (;0;) 0) + (memory $mem1 (;1;) 1) + (memory $mem2 (;2;) 0) + (export "drop_passive" (func 0)) + (export "init_passive" (func 1)) + (export "drop_active" (func 2)) + (export "init_active" (func 3)) + (data $p (;0;) "x") + (data $a (;1;) (memory $mem1) (i32.const 0) "x") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/0.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/0.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/1.print b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/1.print new file mode 100644 index 0000000000..277573bf82 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/1.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) + (export "b" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/2.print new file mode 100644 index 0000000000..5c133a4371 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/2.print @@ -0,0 +1,6 @@ +(module + (memory (;0;) 0) + (memory (;1;) 0) + (export "a" (memory 0)) + (export "b" (memory 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/3.print b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/3.print new file mode 100644 index 0000000000..ef6ad53912 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/3.print @@ -0,0 +1,23 @@ +(module + (memory $mem0 (;0;) 0) + (memory $mem1 (;1;) 0) + (memory $mem2 (;2;) 0) + (memory $mem3 (;3;) 0) + (memory $mem4 (;4;) 0) + (memory $mem5 (;5;) 0) + (memory $mem6 (;6;) 0) + (export "a" (memory $mem0)) + (export "b" (memory $mem1)) + (export "ac" (memory $mem2)) + (export "bc" (memory $mem3)) + (export "ad" (memory $mem4)) + (export "bd" (memory $mem5)) + (export "be" (memory $mem6)) + (export "za" (memory $mem0)) + (export "zb" (memory $mem1)) + (export "zac" (memory $mem2)) + (export "zbc" (memory $mem3)) + (export "zad" (memory $mem4)) + (export "zbd" (memory $mem5)) + (export "zbe" (memory $mem6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/4.print b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/4.print new file mode 100644 index 0000000000..f532a7060e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/4.print @@ -0,0 +1,6 @@ +(module + (memory (;0;) 6) + (memory (;1;) 3) + (export "a" (memory 0)) + (export "b" (memory 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/5.print b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/5.print new file mode 100644 index 0000000000..d13014424d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/5.print @@ -0,0 +1,8 @@ +(module + (memory (;0;) 0 1) + (memory (;1;) 0 1) + (memory (;2;) 0 1) + (memory (;3;) 0 1) + (export "a" (memory 0)) + (export "b" (memory 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/6.print b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/6.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/6.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/7.print b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/7.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/exports0.wast/7.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/float_exprs0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/float_exprs0.wast/0.print new file mode 100644 index 0000000000..57c38f4da8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/float_exprs0.wast/0.print @@ -0,0 +1,40 @@ +(module + (type (;0;) (func (param i32 f64))) + (type (;1;) (func (param i32) (result f64))) + (func (;0;) (type 0) (param $i i32) (param $x f64) + local.get $i + local.get $x + f64.store $m + ) + (func (;1;) (type 0) (param $n i32) (param $z f64) + (local $i i32) + block $exit ;; label = @1 + loop $cont ;; label = @2 + local.get $i + local.get $i + f64.load $m + local.get $z + f64.div + f64.store $m + local.get $i + i32.const 8 + i32.add + local.set $i + local.get $i + local.get $n + i32.lt_u + br_if 0 (;@2;) + end + end + ) + (func (;2;) (type 1) (param $i i32) (result f64) + local.get $i + f64.load $m + ) + (memory (;0;) 0 0) + (memory $m (;1;) 1 1) + (memory (;2;) 0 0) + (export "init" (func 0)) + (export "run" (func 1)) + (export "check" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/float_exprs1.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/float_exprs1.wast/0.print new file mode 100644 index 0000000000..628c7e3c4c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/float_exprs1.wast/0.print @@ -0,0 +1,70 @@ +(module + (type (;0;) (func (param i32 i32) (result f32))) + (func (;0;) (type 0) (param $p i32) (param $n i32) (result f32) + (local $sum f32) (local $c f32) (local $t f32) + block $exit ;; label = @1 + loop $top ;; label = @2 + local.get $c + local.get $p + f32.load $m + local.get $t + f32.sub + local.tee $t + f32.add + local.tee $sum + local.get $c + f32.sub + local.get $t + f32.sub + local.set $t + local.get $p + i32.const 4 + i32.add + local.set $p + local.get $sum + local.set $c + local.get $n + i32.const -1 + i32.add + local.tee $n + br_if 0 (;@2;) + end + end + local.get $sum + ) + (func (;1;) (type 0) (param $p i32) (param $n i32) (result f32) + (local $sum f32) + block $exit ;; label = @1 + loop $top ;; label = @2 + local.get $sum + local.get $p + f32.load $m + f32.add + local.set $sum + local.get $p + i32.const 4 + i32.add + local.set $p + local.get $n + i32.const -1 + i32.add + local.set $n + local.get $n + br_if 0 (;@2;) + end + end + local.get $sum + ) + (memory (;0;) 0 0) + (memory (;1;) 0 0) + (memory (;2;) 0 0) + (memory (;3;) 0 0) + (memory (;4;) 0 0) + (memory $m (;5;) 1 1) + (memory (;6;) 0 0) + (memory (;7;) 0 0) + (memory (;8;) 0 0) + (export "f32.kahan_sum" (func 0)) + (export "f32.plain_sum" (func 1)) + (data (;0;) (memory $m) (i32.const 0) "\c4\c5W$\a5\84\c8\0bm\b8K.\f2v\17\1c\caJV\1e\1bnq\22]\17\1en\bf\cd\14\5c\c7!UQ9\9c\1f\b2Q\f0\a3\93\d7\c1,\ae~\a8(:\01!\f4\0aX\93\f8Bw\9f\839j_\ba\f7\0a\d8Qj4\ca\ad\c64\0e\d8&\dcL3\1c\ed)\90\a8x\0f\d1\cev1#\83\b85\e8\f2D\b0\d3\a1\fc\bb2\e1\b0\baiD\09\d6\d9}\ff.\c0Z6\143\14>\a9\fa\87m\8b\bc\ce\9d\a7\fd\c4\e9\85?\dd\d7\e1\18\a6P&rn?s\0f\f8\12\93#4av\12H\c0\9b\05\93\eb\ac\86\de\94>U\e8\8c\e8\dd\e4\fc\95G\beV\03! L\e6\bf{\f6\7f\d5\bas\1c\c1\14\8f\c4'\96\b3\bd3\ffxA_\c0Z\ce\f6gns\9a\17fp\03\f8\ce'\a3R\b2\9f;\bf\fb\ae\ed\d3Z\f87W\f0\f5n\ef\b1Mp=T\a7\01\9a\85\08H\91\f5\9d\0c`\87[\d9T\1eQm\88\8e\08\8c\a5q:V\08gF\8f\8f\13*,\ec,\1f\b4b+oA\0a\c4eB\a21k,}>\bbu\ac\86\970\d9H\cd\9a\1fV\c4\c6\e4\12\c0\9d\fb\ee\02\8c\ce\1c\f2\1e\a1x#\db\c4\1eI\03\d3q\cc\08P\c5\d8\5c\ed\d5\b5e\ac\b5\c9!\d2\c9)v\de\f00\1a[<\f2;\db:9\82:\16\08o\a8\f1\beii\99q\a6\05\d3\14\93*\16\f2/\11\c7~ \bb\91D\ee\f8\e4\01S\c0\b9\7f\f0\bf\f0\03\9cm\b1\df\a2D\01mkq+\5c\b3!\19F^\8f\db\91\d3|xk\b7\12\00\8f\eb\bd\8a\f5\d4.\c4\c1\1e\dfscYGI\03\0a\b7\cf$\cf\9c\0eDz\9e\14\fbB\bf\9d90\9e\a0\ab/\d1\ae\9ej\83C\e3U}\85\bfc\8a\f8\96\10\1f\fem\e7\22\1b\e1iF\8aD\c8\c8\f9\0c+\19\07\a5\02>\f20\10\9a\85\8a_\ef\81E\a0w\b1\03\10sK\ae\98\9dG\bf\9a-:\d5\0f\03f\e3=S\d9@\ce\1fo2/!+#!lb\d4\a7>\a8\ce(1-\00=g^\af\a0\cf.\d2\b9k\84\ebi\08\ad\bc\0b\c0A\c4P\b6\e3P1\e8\ce\e2\96eU\9c\16F\e6\b0-:\e8\81\05\b0\bf4\f7\bc\10\1c\fb\cc<\f1\85\97B\9f\eb\14\8d<\bf\d7\17\88I\9d\8b+\b2:\83\d1O\04\9e\a1\0f\ad\08\9dT\af\d1\82\c3\ec2/\02\8f\05!-\a2\b7\e4\f4o.\81+\0b\9c\fc\cb\fet\02\f9\db\f4\f3\ea\00\a8\ec\d1\99t&\dd\d64\d5%\b1F\dd\9c\aaq\f5`\b0\88\c8\e0\0bYZ%O)f\f9\e3.\fe\e9\da\e5\18O'b\f4\ce\a4!\95t\c7Wd'\9aL\fdT}a\ce\c3\ac\87F\9c\fa\ff\09\cay\97g$t\ca\d4!\83&%\19\127d\19\e5e\e0tu\8e\dd\c8\eft\c7\d8!+y\04QFe`\03]\fa\d8\f4e\a4\9e]#\da\d7\8a\92\80\a4\dex<\f1WBm\cd\c9/\d5\a4\9e\ab@\f4\cb\1b\d7\a3\ca\fc\eb\a7\01\b2\9aiNF\9b\18N\ddy\a7\aa\a6R9\1e\ef0\cc\9b\bd[\eeL!m0\00r\b0F_\08\cf\c5\b9\e0>\c2\b3\0c\dc\8ed\de\19By\cfC\eaC]\8e\88\f7\ab\15\dc?\c8g \db\b8d\b1G\1f\de\f2\cb?Y\9f\d8F\90\dc\ae/\22\f9\e21\89\d9\9c\1cL\d3\a9JW\84\9c\9f\ea,<\ae<\c3\1e\8b\e5N\17\01%\db4F_\15\ea\05\0c|\d9E\8c\19\d0s\8a\96\16\ddD\f9\05\b7[q\b0\e6!6_u\89\91su\ab}\ae\d3s\ec7\c6\eaUu\ef\ea\ab\8b{\11\dcm\1a\b2j\c4%\cf\aa\e3\9fII\89\cb7\9b\0a\a7\01`p\dc\b7\c8\83\e1B\f5\be\adb\94\ad\8d\a1") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/float_memory0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/float_memory0.wast/0.print new file mode 100644 index 0000000000..00d1f68af3 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/float_memory0.wast/0.print @@ -0,0 +1,40 @@ +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f32) + i32.const 0 + f32.load $m + ) + (func (;1;) (type 1) (result i32) + i32.const 0 + i32.load $m + ) + (func (;2;) (type 2) + i32.const 0 + f32.const nan:0x200000 (;=NaN;) + f32.store $m + ) + (func (;3;) (type 2) + i32.const 0 + i32.const 2141192192 + i32.store $m + ) + (func (;4;) (type 2) + i32.const 0 + i32.const 0 + i32.store $m + ) + (memory (;0;) 0 0) + (memory (;1;) 0 0) + (memory (;2;) 0 0) + (memory $m (;3;) 1 1) + (memory (;4;) 0 0) + (memory (;5;) 0 0) + (export "f32.load" (func 0)) + (export "i32.load" (func 1)) + (export "f32.store" (func 2)) + (export "i32.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (memory $m) (i32.const 0) "\00\00\a0\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/float_memory0.wast/15.print b/tests/snapshots/testsuite/proposals/multi-memory/float_memory0.wast/15.print new file mode 100644 index 0000000000..8ab3989684 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/float_memory0.wast/15.print @@ -0,0 +1,36 @@ +(module + (type (;0;) (func (result f64))) + (type (;1;) (func (result i64))) + (type (;2;) (func)) + (func (;0;) (type 0) (result f64) + i32.const 0 + f64.load $m + ) + (func (;1;) (type 1) (result i64) + i32.const 0 + i64.load $m + ) + (func (;2;) (type 2) + i32.const 0 + f64.const nan:0x4000000000000 (;=NaN;) + f64.store $m + ) + (func (;3;) (type 2) + i32.const 0 + i64.const 9219994337134247936 + i64.store $m + ) + (func (;4;) (type 2) + i32.const 0 + i64.const 0 + i64.store $m + ) + (memory (;0;) 0 0) + (memory $m (;1;) 1 1) + (export "f64.load" (func 0)) + (export "i64.load" (func 1)) + (export "f64.store" (func 2)) + (export "i64.store" (func 3)) + (export "reset" (func 4)) + (data (;0;) (memory $m) (i32.const 0) "\00\00\00\00\00\00\f4\7f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/0.print new file mode 100644 index 0000000000..08ee68f308 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/0.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (result i32))) + (type (;4;) (func (result f32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i64) (result i64))) + (func (;0;) (type 0)) + (func (;1;) (type 1) (param i32)) + (func (;2;) (type 2) (param f32)) + (func (;3;) (type 3) (result i32) + i32.const 22 + ) + (func (;4;) (type 4) (result f32) + f32.const 0x1.6p+3 (;=11;) + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;6;) (type 6) (param i64) (result i64) + local.get 0 + ) + (table (;0;) 10 funcref) + (table (;1;) 10 20 funcref) + (memory (;0;) 2) + (global (;0;) i32 i32.const 55) + (global (;1;) f32 f32.const 0x1.6p+5 (;=44;)) + (global (;2;) (mut i64) i64.const 66) + (export "func" (func 0)) + (export "func-i32" (func 1)) + (export "func-f32" (func 2)) + (export "func->i32" (func 3)) + (export "func->f32" (func 4)) + (export "func-i32->i32" (func 5)) + (export "func-i64->i64" (func 6)) + (export "global-i32" (global 0)) + (export "global-f32" (global 1)) + (export "global-mut-i64" (global 2)) + (export "table-10-inf" (table 0)) + (export "table-10-20" (table 1)) + (export "memory-2-inf" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/10.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/10.print new file mode 100644 index 0000000000..22a02a9053 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/10.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (import "test" "func" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/100.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/100.print new file mode 100644 index 0000000000..9c95837f51 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/100.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/101.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/101.print new file mode 100644 index 0000000000..45fc077841 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/101.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/11.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/11.print new file mode 100644 index 0000000000..782997f244 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/11.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "test" "func-i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/114.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/114.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/114.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/119.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/119.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/119.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/12.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/12.print new file mode 100644 index 0000000000..ace1d7c959 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/12.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param f32))) + (import "test" "func-f32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/124.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/124.print new file mode 100644 index 0000000000..1aad2d0f8d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/124.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/125.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/125.print new file mode 100644 index 0000000000..546d8eaedc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/125.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/126.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/126.print new file mode 100644 index 0000000000..e40926e430 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/126.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/127.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/127.print new file mode 100644 index 0000000000..3c97146026 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/127.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/128.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/128.print new file mode 100644 index 0000000000..83efcab834 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/128.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/129.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/129.print new file mode 100644 index 0000000000..404698c724 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/129.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/13.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/13.print new file mode 100644 index 0000000000..0744a46fba --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/13.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (result i32))) + (import "test" "func->i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/130.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/130.print new file mode 100644 index 0000000000..39db875587 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/130.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/131.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/131.print new file mode 100644 index 0000000000..897e9b716b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/131.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/132.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/132.print new file mode 100644 index 0000000000..c0d28c6be7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/132.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/14.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/14.print new file mode 100644 index 0000000000..3b07b2a04c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/14.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (result f32))) + (import "test" "func->f32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/147.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/147.print new file mode 100644 index 0000000000..73ee1fb50c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/147.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 0 3)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/15.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/15.print new file mode 100644 index 0000000000..e6ddafe344 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/15.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "test" "func-i32->i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/153.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/153.print new file mode 100644 index 0000000000..7efe25f1d8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/153.print @@ -0,0 +1,10 @@ +(module $Mgm + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + memory.grow + ) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/156.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/156.print new file mode 100644 index 0000000000..477ca763be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/156.print @@ -0,0 +1,10 @@ +(module $Mgim1 + (type (;0;) (func (result i32))) + (import "grown-memory" "memory" (memory (;0;) 2)) + (func (;0;) (type 0) (result i32) + i32.const 1 + memory.grow + ) + (export "memory" (memory 0)) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/159.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/159.print new file mode 100644 index 0000000000..80793cacec --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/159.print @@ -0,0 +1,8 @@ +(module $Mgim2 + (type (;0;) (func (result i32))) + (import "grown-imported-memory" "memory" (memory (;0;) 3)) + (func (;0;) (type 0) (result i32) + memory.size + ) + (export "size" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/16.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/16.print new file mode 100644 index 0000000000..c5ca6af197 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/16.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (import "test" "func-i64->i64" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/177.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/177.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/177.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/2.print new file mode 100644 index 0000000000..2387bf04da --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/2.print @@ -0,0 +1,83 @@ +(module + (type $func_i32 (;0;) (func (param i32))) + (type $func_i64 (;1;) (func (param i64))) + (type $func_f32 (;2;) (func (param f32))) + (type $func_f64 (;3;) (func (param f64))) + (type $forward (;4;) (func (param i32))) + (type (;5;) (func (param i32 f32))) + (type (;6;) (func (param f64 f64))) + (type (;7;) (func (param i64) (result i64))) + (import "spectest" "print_i32" (func (;0;) (type $func_i32))) + (import "spectest" "print_i64" (func (;1;) (type $func_i64))) + (import "spectest" "print_i32" (func $print_i32 (;2;) (type $func_i32))) + (import "spectest" "print_i64" (func $print_i64 (;3;) (type $func_i64))) + (import "spectest" "print_f32" (func $print_f32 (;4;) (type $func_f32))) + (import "spectest" "print_f64" (func $print_f64 (;5;) (type $func_f64))) + (import "spectest" "print_i32_f32" (func $print_i32_f32 (;6;) (type 5))) + (import "spectest" "print_f64_f64" (func $print_f64_f64 (;7;) (type 6))) + (import "spectest" "print_i32" (func $print_i32-2 (;8;) (type $func_i32))) + (import "spectest" "print_f64" (func $print_f64-2 (;9;) (type $func_f64))) + (import "test" "func-i64->i64" (func $i64->i64 (;10;) (type 7))) + (import "spectest" "print_i32" (func (;11;) (type $func_i32))) + (import "spectest" "print_i32" (func $p (;12;) (type $func_i32))) + (import "spectest" "print_i32" (func (;13;) (type $func_i32))) + (import "spectest" "print_i32" (func (;14;) (type $func_i32))) + (import "spectest" "print_i32" (func (;15;) (type $func_i32))) + (import "spectest" "print_i32" (func (;16;) (type $forward))) + (import "spectest" "print_i32" (func (;17;) (type $forward))) + (func (;18;) (type $func_i32) (param $i i32) + (local $x f32) + local.get $i + f32.convert_i32_s + local.set $x + local.get $i + call 0 + local.get $i + i32.const 1 + i32.add + f32.const 0x1.5p+5 (;=42;) + call $print_i32_f32 + local.get $i + call $print_i32 + local.get $i + call $print_i32-2 + local.get $x + call $print_f32 + local.get $i + i32.const 0 + call_indirect (type $func_i32) + ) + (func (;19;) (type $func_i64) (param $i i64) + (local $x f64) + local.get $i + call $i64->i64 + f64.convert_i64_s + local.set $x + local.get $i + call 1 + local.get $x + f64.const 0x1p+0 (;=1;) + f64.add + f64.const 0x1.a8p+5 (;=53;) + call $print_f64_f64 + local.get $i + call $print_i64 + local.get $x + call $print_f64 + local.get $x + call $print_f64-2 + local.get $x + i32.const 1 + call_indirect (type $func_f64) + ) + (table (;0;) 2 2 funcref) + (export "p1" (func 11)) + (export "p2" (func $p)) + (export "p3" (func 13)) + (export "p4" (func 13)) + (export "p5" (func 14)) + (export "p6" (func 15)) + (export "print32" (func 18)) + (export "print64" (func 19)) + (elem (;0;) (i32.const 0) func $print_i32 $print_f64) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/41.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/41.print new file mode 100644 index 0000000000..0693cbec34 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/41.print @@ -0,0 +1,26 @@ +(module + (type (;0;) (func (result i32))) + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "global_i32" (global (;1;) i32)) + (import "spectest" "global_i32" (global $x (;2;) i32)) + (import "spectest" "global_i32" (global $y (;3;) i32)) + (import "spectest" "global_i64" (global (;4;) i64)) + (import "spectest" "global_f32" (global (;5;) f32)) + (import "spectest" "global_f64" (global (;6;) f64)) + (func (;0;) (type 0) (result i32) + global.get 0 + ) + (func (;1;) (type 0) (result i32) + global.get 1 + ) + (func (;2;) (type 0) (result i32) + global.get $x + ) + (func (;3;) (type 0) (result i32) + global.get $y + ) + (export "get-0" (func 0)) + (export "get-1" (func 1)) + (export "get-x" (func 2)) + (export "get-y" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/46.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/46.print new file mode 100644 index 0000000000..1b1739a096 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/46.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-i32" (global (;0;) i32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/47.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/47.print new file mode 100644 index 0000000000..eae7b7643b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/47.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-f32" (global (;0;) f32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/48.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/48.print new file mode 100644 index 0000000000..8cff34a430 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/48.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-mut-i64" (global (;0;) (mut i64))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/6.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/6.print new file mode 100644 index 0000000000..63910ab9f5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/6.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32))) + (import "spectest" "print_i32" (func $imported_print (;0;) (type 0))) + (func (;1;) (type 0) (param $i i32) + local.get $i + call $imported_print + ) + (export "print_i32" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/69.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/69.print new file mode 100644 index 0000000000..d06f6c7555 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/69.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "spectest" "table" (table $tab (;0;) 10 20 funcref)) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func $f (;1;) (type 0) (result i32) + i32.const 11 + ) + (func $g (;2;) (type 0) (result i32) + i32.const 22 + ) + (export "call" (func 0)) + (elem (;0;) (i32.const 1) func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/75.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/75.print new file mode 100644 index 0000000000..d06f6c7555 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/75.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "spectest" "table" (table $tab (;0;) 10 20 funcref)) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func $f (;1;) (type 0) (result i32) + i32.const 11 + ) + (func $g (;2;) (type 0) (result i32) + i32.const 22 + ) + (export "call" (func 0)) + (elem (;0;) (i32.const 1) func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/8.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/8.print new file mode 100644 index 0000000000..a93289d203 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/8.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (import "spectest" "print_i32" (func $imported_print (;0;) (type 0))) + (func (;1;) (type 1) (param $i i32) (param $j i32) (result i32) + local.get $i + local.get $j + i32.add + ) + (export "print_i32" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/81.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/81.print new file mode 100644 index 0000000000..9dfcbda865 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/81.print @@ -0,0 +1,6 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (import "spectest" "table" (table (;1;) 0 funcref)) + (table (;2;) 10 funcref) + (table (;3;) 10 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/82.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/82.print new file mode 100644 index 0000000000..72f38c2e80 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/82.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/83.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/83.print new file mode 100644 index 0000000000..475c251b6e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/83.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/84.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/84.print new file mode 100644 index 0000000000..c8997038cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/84.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/85.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/85.print new file mode 100644 index 0000000000..f1e8559446 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/85.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/86.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/86.print new file mode 100644 index 0000000000..4eca2099fe --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/86.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/87.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/87.print new file mode 100644 index 0000000000..18937c5d00 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/87.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/88.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/88.print new file mode 100644 index 0000000000..affb91adc7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/88.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/89.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/89.print new file mode 100644 index 0000000000..b27d0a1814 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/89.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/90.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/90.print new file mode 100644 index 0000000000..d40ae2d3a4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/90.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/91.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/91.print new file mode 100644 index 0000000000..eea2b23b56 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/91.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 10 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/92.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/92.print new file mode 100644 index 0000000000..339f1e02ed --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/92.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 5 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/93.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/93.print new file mode 100644 index 0000000000..5c845b5cc2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/93.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-20" (table (;0;) 0 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/94.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/94.print new file mode 100644 index 0000000000..64a52acf28 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/94.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/95.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/95.print new file mode 100644 index 0000000000..218d7d9bdc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/95.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/96.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/96.print new file mode 100644 index 0000000000..2a0fa834a7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/96.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/97.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/97.print new file mode 100644 index 0000000000..03446a5f52 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/97.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/98.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/98.print new file mode 100644 index 0000000000..d1cff0037a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/98.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/99.print b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/99.print new file mode 100644 index 0000000000..65ae983998 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports.wast/99.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 0 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/imports0.wast/0.print new file mode 100644 index 0000000000..924032c699 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports0.wast/0.print @@ -0,0 +1,45 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (result i32))) + (type (;4;) (func (result f32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i64) (result i64))) + (func (;0;) (type 0)) + (func (;1;) (type 1) (param i32)) + (func (;2;) (type 2) (param f32)) + (func (;3;) (type 3) (result i32) + i32.const 22 + ) + (func (;4;) (type 4) (result f32) + f32.const 0x1.6p+3 (;=11;) + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;6;) (type 6) (param i64) (result i64) + local.get 0 + ) + (table (;0;) 10 funcref) + (table (;1;) 10 20 funcref) + (memory (;0;) 2) + (memory (;1;) 2 4) + (global (;0;) i32 i32.const 55) + (global (;1;) f32 f32.const 0x1.6p+5 (;=44;)) + (global (;2;) (mut i64) i64.const 66) + (export "func" (func 0)) + (export "func-i32" (func 1)) + (export "func-f32" (func 2)) + (export "func->i32" (func 3)) + (export "func->f32" (func 4)) + (export "func-i32->i32" (func 5)) + (export "func-i64->i64" (func 6)) + (export "global-i32" (global 0)) + (export "global-f32" (global 1)) + (export "global-mut-i64" (global 2)) + (export "table-10-inf" (table 0)) + (export "table-10-20" (table 1)) + (export "memory-2-inf" (memory 0)) + (export "memory-2-4" (memory 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports1.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/imports1.wast/0.print new file mode 100644 index 0000000000..2eee0d71fa --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports1.wast/0.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (import "spectest" "memory" (memory (;1;) 1 2)) + (import "spectest" "memory" (memory $m (;2;) 1 2)) + (import "spectest" "memory" (memory (;3;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load $m + ) + (export "load" (func 0)) + (data (;0;) (memory $m) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/0.print new file mode 100644 index 0000000000..730f127cf9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/0.print @@ -0,0 +1,8 @@ +(module + (memory (;0;) 0 0) + (memory (;1;) 2) + (memory (;2;) 2 4) + (export "z" (memory 0)) + (export "memory-2-inf" (memory 1)) + (export "memory-2-4" (memory 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/12.print b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/12.print new file mode 100644 index 0000000000..2f0e536416 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/12.print @@ -0,0 +1,5 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 2)) + (import "test" "memory-2-inf" (memory (;1;) 1)) + (import "test" "memory-2-inf" (memory (;2;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/13.print b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/13.print new file mode 100644 index 0000000000..c1e435b1a5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/13.print @@ -0,0 +1,8 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) + (import "spectest" "memory" (memory (;1;) 0)) + (import "spectest" "memory" (memory (;2;) 1 2)) + (import "spectest" "memory" (memory (;3;) 0 2)) + (import "spectest" "memory" (memory (;4;) 1 3)) + (import "spectest" "memory" (memory (;5;) 0 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/2.print new file mode 100644 index 0000000000..beeffcc97b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/2.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "test" "z" (memory (;0;) 0)) + (import "spectest" "memory" (memory $m (;1;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load $m + ) + (export "load" (func 0)) + (data (;0;) (memory $m) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/7.print b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/7.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports2.wast/7.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports3.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/imports3.wast/0.print new file mode 100644 index 0000000000..924032c699 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports3.wast/0.print @@ -0,0 +1,45 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (result i32))) + (type (;4;) (func (result f32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i64) (result i64))) + (func (;0;) (type 0)) + (func (;1;) (type 1) (param i32)) + (func (;2;) (type 2) (param f32)) + (func (;3;) (type 3) (result i32) + i32.const 22 + ) + (func (;4;) (type 4) (result f32) + f32.const 0x1.6p+3 (;=11;) + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;6;) (type 6) (param i64) (result i64) + local.get 0 + ) + (table (;0;) 10 funcref) + (table (;1;) 10 20 funcref) + (memory (;0;) 2) + (memory (;1;) 2 4) + (global (;0;) i32 i32.const 55) + (global (;1;) f32 f32.const 0x1.6p+5 (;=44;)) + (global (;2;) (mut i64) i64.const 66) + (export "func" (func 0)) + (export "func-i32" (func 1)) + (export "func-f32" (func 2)) + (export "func->i32" (func 3)) + (export "func->f32" (func 4)) + (export "func-i32->i32" (func 5)) + (export "func-i64->i64" (func 6)) + (export "global-i32" (global 0)) + (export "global-f32" (global 1)) + (export "global-mut-i64" (global 2)) + (export "table-10-inf" (table 0)) + (export "table-10-20" (table 1)) + (export "memory-2-inf" (memory 0)) + (export "memory-2-4" (memory 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/0.print new file mode 100644 index 0000000000..a918fb4c92 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/0.print @@ -0,0 +1,6 @@ +(module + (memory (;0;) 2) + (memory (;1;) 2 4) + (export "memory-2-inf" (memory 0)) + (export "memory-2-4" (memory 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/11.print b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/11.print new file mode 100644 index 0000000000..e98ebff09c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/11.print @@ -0,0 +1,13 @@ +(module $Mgim1 + (type (;0;) (func (result i32))) + (import "test" "memory-2-4" (memory (;0;) 1)) + (import "grown-memory" "memory" (memory $m (;1;) 2)) + (func (;0;) (type 0) (result i32) + i32.const 1 + memory.grow $m + ) + (memory (;2;) 0) + (memory (;3;) 0) + (export "memory" (memory $m)) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/14.print b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/14.print new file mode 100644 index 0000000000..e67acd6ffa --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/14.print @@ -0,0 +1,11 @@ +(module $Mgim2 + (type (;0;) (func (result i32))) + (import "test" "memory-2-4" (memory (;0;) 1)) + (import "grown-imported-memory" "memory" (memory $m (;1;) 3)) + (func (;0;) (type 0) (result i32) + memory.size $m + ) + (memory (;2;) 0) + (memory (;3;) 0) + (export "size" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/2.print new file mode 100644 index 0000000000..7171cd7166 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/2.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "test" "memory-2-4" (memory (;0;) 1)) + (import "spectest" "memory" (memory $m (;1;) 0 3)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow $m + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/8.print b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/8.print new file mode 100644 index 0000000000..1194b98a48 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/imports4.wast/8.print @@ -0,0 +1,12 @@ +(module $Mgm + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + memory.grow $m + ) + (memory (;0;) 0) + (memory (;1;) 0) + (memory $m (;2;) 1) + (export "memory" (memory $m)) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/linking0.wast/0.print new file mode 100644 index 0000000000..045b7e0e24 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking0.wast/0.print @@ -0,0 +1,20 @@ +(module $Mt + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (func $g (;0;) (type 0) (result i32) + i32.const 4 + ) + (func (;1;) (type 0) (result i32) + i32.const -4 + ) + (func (;2;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table (;0;) 10 funcref) + (export "tab" (table 0)) + (export "h" (func 1)) + (export "call" (func 2)) + (elem (;0;) (i32.const 2) func $g $g $g $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/0.print new file mode 100644 index 0000000000..d3b6f54441 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/0.print @@ -0,0 +1,15 @@ +(module $Mm + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u $mem1 + ) + (memory $mem0 (;0;) 0 0) + (memory $mem1 (;1;) 1 5) + (memory $mem2 (;2;) 0 0) + (export "mem0" (memory $mem0)) + (export "mem1" (memory $mem1)) + (export "mem2" (memory $mem2)) + (export "load" (func 0)) + (data (;0;) (memory $mem1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/11.print b/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/11.print new file mode 100644 index 0000000000..352ee00f15 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/11.print @@ -0,0 +1,4 @@ +(module + (import "Mm" "mem1" (memory (;0;) 0)) + (data (;0;) (i32.const 65535) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/2.print new file mode 100644 index 0000000000..85decd5bc0 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/2.print @@ -0,0 +1,13 @@ +(module $Nm + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "load" (func $loadM (;0;) (type 0))) + (import "Mm" "mem0" (memory (;0;) 0)) + (func (;1;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u $m + ) + (memory $m (;1;) 1) + (export "Mm.load" (func $loadM)) + (export "load" (func 1)) + (data (;0;) (memory $m) (i32.const 10) "\f0\f1\f2\f3\f4\f5") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/6.print b/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/6.print new file mode 100644 index 0000000000..2077142cbd --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking1.wast/6.print @@ -0,0 +1,10 @@ +(module $Om + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "mem1" (memory (;0;) 1)) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u + ) + (export "load" (func 0)) + (data (;0;) (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking2.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/linking2.wast/0.print new file mode 100644 index 0000000000..d3b6f54441 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking2.wast/0.print @@ -0,0 +1,15 @@ +(module $Mm + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u $mem1 + ) + (memory $mem0 (;0;) 0 0) + (memory $mem1 (;1;) 1 5) + (memory $mem2 (;2;) 0 0) + (export "mem0" (memory $mem0)) + (export "mem1" (memory $mem1)) + (export "mem2" (memory $mem2)) + (export "load" (func 0)) + (data (;0;) (memory $mem1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking2.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/linking2.wast/2.print new file mode 100644 index 0000000000..af8adcb8eb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking2.wast/2.print @@ -0,0 +1,9 @@ +(module $Pm + (type (;0;) (func (param i32) (result i32))) + (import "Mm" "mem1" (memory (;0;) 1 8)) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + memory.grow + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking3.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/linking3.wast/0.print new file mode 100644 index 0000000000..eb825bb9ca --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking3.wast/0.print @@ -0,0 +1,15 @@ +(module $Mm + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u $mem1 + ) + (memory $mem0 (;0;) 0 0) + (memory $mem1 (;1;) 5 5) + (memory $mem2 (;2;) 0 0) + (export "mem0" (memory $mem0)) + (export "mem1" (memory $mem1)) + (export "mem2" (memory $mem2)) + (export "load" (func 0)) + (data (;0;) (memory $mem1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/linking3.wast/9.print b/tests/snapshots/testsuite/proposals/multi-memory/linking3.wast/9.print new file mode 100644 index 0000000000..24a36bdfab --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/linking3.wast/9.print @@ -0,0 +1,17 @@ +(module $Ms + (type $t (;0;) (func (result i32))) + (func (;0;) (type $t) (result i32) + i32.const 0 + i32.load8_u + ) + (func (;1;) (type $t) (result i32) + i32.const 0 + call_indirect (type $t) + ) + (table (;0;) 1 funcref) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "table" (table 0)) + (export "get memory[0]" (func 0)) + (export "get table[0]" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/load.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/load.wast/0.print new file mode 100644 index 0000000000..acba3b3f83 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/load.wast/0.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 0) (param i32) (result i64) + local.get 0 + i64.load $mem2 + ) + (memory $mem1 (;0;) 1) + (memory $mem2 (;1;) 1) + (export "load1" (func 0)) + (export "load2" (func 1)) + (data (;0;) (i32.const 0) "\01") + (data (;1;) (memory $mem2) (i32.const 0) "\02") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/load.wast/21.print b/tests/snapshots/testsuite/proposals/multi-memory/load.wast/21.print new file mode 100644 index 0000000000..d513949b27 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/load.wast/21.print @@ -0,0 +1,306 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (type (;3;) (func (param i32 i32) (result i32))) + (func (;0;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load + br 0 (;@1;) + end + ) + (func (;1;) (type 2) + block ;; label = @1 + i32.const 0 + i32.load + br_if 0 (;@1;) + end + ) + (func (;2;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;3;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + i32.load + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;4;) (type 2) + block ;; label = @1 + i32.const 0 + i32.load + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;5;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;6;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + i32.load + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;7;) (type 1) (result i32) + i32.const 0 + i32.load + return + ) + (func (;8;) (type 1) (result i32) + i32.const 0 + i32.load + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;9;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 0 + i32.load + else + i32.const 0 + end + ) + (func (;10;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 0 + i32.load + end + ) + (func (;11;) (type 3) (param i32 i32) (result i32) + i32.const 0 + i32.load + local.get 0 + local.get 1 + select + ) + (func (;12;) (type 3) (param i32 i32) (result i32) + local.get 0 + i32.const 0 + i32.load + local.get 1 + select + ) + (func (;13;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i32.const 0 + i32.load + select + ) + (func $f (;14;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;15;) (type 1) (result i32) + i32.const 0 + i32.load + i32.const 2 + i32.const 3 + call $f + ) + (func (;16;) (type 1) (result i32) + i32.const 1 + i32.const 0 + i32.load + i32.const 3 + call $f + ) + (func (;17;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + i32.load + call $f + ) + (func (;18;) (type 1) (result i32) + i32.const 0 + i32.load + i32.const 2 + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;19;) (type 1) (result i32) + i32.const 1 + i32.const 0 + i32.load + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;20;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + i32.load + i32.const 0 + call_indirect (type $sig) + ) + (func (;21;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 0 + i32.load + call_indirect (type $sig) + ) + (func (;22;) (type 2) + (local i32) + i32.const 0 + i32.load + local.set 0 + ) + (func (;23;) (type 1) (result i32) + (local i32) + i32.const 0 + i32.load + local.tee 0 + ) + (func (;24;) (type 2) + (local i32) + i32.const 0 + i32.load + global.set $g + ) + (func (;25;) (type 1) (result i32) + i32.const 0 + i32.load + i32.load + ) + (func (;26;) (type 1) (result i32) + i32.const 0 + i32.load + i32.load8_s + ) + (func (;27;) (type 2) + i32.const 0 + i32.load + i32.const 7 + i32.store + ) + (func (;28;) (type 2) + i32.const 2 + i32.const 0 + i32.load + i32.store + ) + (func (;29;) (type 2) + i32.const 0 + i32.load8_s + i32.const 7 + i32.store8 + ) + (func (;30;) (type 2) + i32.const 2 + i32.const 0 + i32.load + i32.store16 + ) + (func (;31;) (type 1) (result i32) + i32.const 100 + i32.load + i32.clz + ) + (func (;32;) (type 1) (result i32) + i32.const 100 + i32.load + i32.const 10 + i32.add + ) + (func (;33;) (type 1) (result i32) + i32.const 10 + i32.const 100 + i32.load + i32.sub + ) + (func (;34;) (type 1) (result i32) + i32.const 100 + i32.load + i32.eqz + ) + (func (;35;) (type 1) (result i32) + i32.const 100 + i32.load + i32.const 10 + i32.le_s + ) + (func (;36;) (type 1) (result i32) + i32.const 10 + i32.const 100 + i32.load + i32.ne + ) + (func (;37;) (type 1) (result i32) + i32.const 100 + i32.load + memory.grow + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $g (;0;) (mut i32) i32.const 0) + (export "as-br-value" (func 0)) + (export "as-br_if-cond" (func 1)) + (export "as-br_if-value" (func 2)) + (export "as-br_if-value-cond" (func 3)) + (export "as-br_table-index" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-br_table-value-index" (func 6)) + (export "as-return-value" (func 7)) + (export "as-if-cond" (func 8)) + (export "as-if-then" (func 9)) + (export "as-if-else" (func 10)) + (export "as-select-first" (func 11)) + (export "as-select-second" (func 12)) + (export "as-select-cond" (func 13)) + (export "as-call-first" (func 15)) + (export "as-call-mid" (func 16)) + (export "as-call-last" (func 17)) + (export "as-call_indirect-first" (func 18)) + (export "as-call_indirect-mid" (func 19)) + (export "as-call_indirect-last" (func 20)) + (export "as-call_indirect-index" (func 21)) + (export "as-local.set-value" (func 22)) + (export "as-local.tee-value" (func 23)) + (export "as-global.set-value" (func 24)) + (export "as-load-address" (func 25)) + (export "as-loadN-address" (func 26)) + (export "as-store-address" (func 27)) + (export "as-store-value" (func 28)) + (export "as-storeN-address" (func 29)) + (export "as-storeN-value" (func 30)) + (export "as-unary-operand" (func 31)) + (export "as-binary-left" (func 32)) + (export "as-binary-right" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-left" (func 35)) + (export "as-compare-right" (func 36)) + (export "as-memory.grow-size" (func 37)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/load.wast/3.print b/tests/snapshots/testsuite/proposals/multi-memory/load.wast/3.print new file mode 100644 index 0000000000..7893bd6915 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/load.wast/3.print @@ -0,0 +1,10 @@ +(module $M + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 2) + (export "mem" (memory 0)) + (export "read" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/load.wast/5.print b/tests/snapshots/testsuite/proposals/multi-memory/load.wast/5.print new file mode 100644 index 0000000000..626b02e8f4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/load.wast/5.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "M" "mem" (memory $mem1 (;0;) 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (func (;1;) (type 0) (param i32) (result i32) + local.get 0 + i32.load8_u $mem2 + ) + (memory $mem2 (;1;) 3) + (export "read1" (func 0)) + (export "read2" (func 1)) + (data (;0;) (i32.const 20) "\01\02\03\04\05") + (data (;1;) (memory $mem2) (i32.const 50) "\0a\0b\0c\0d\0e") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/load0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/load0.wast/0.print new file mode 100644 index 0000000000..acba3b3f83 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/load0.wast/0.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 0) (param i32) (result i64) + local.get 0 + i64.load $mem2 + ) + (memory $mem1 (;0;) 1) + (memory $mem2 (;1;) 1) + (export "load1" (func 0)) + (export "load2" (func 1)) + (data (;0;) (i32.const 0) "\01") + (data (;1;) (memory $mem2) (i32.const 0) "\02") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/load1.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/load1.wast/0.print new file mode 100644 index 0000000000..7893bd6915 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/load1.wast/0.print @@ -0,0 +1,10 @@ +(module $M + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (memory (;0;) 2) + (export "mem" (memory 0)) + (export "read" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/load1.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/load1.wast/2.print new file mode 100644 index 0000000000..626b02e8f4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/load1.wast/2.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "M" "mem" (memory $mem1 (;0;) 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (func (;1;) (type 0) (param i32) (result i32) + local.get 0 + i32.load8_u $mem2 + ) + (memory $mem2 (;1;) 3) + (export "read1" (func 0)) + (export "read2" (func 1)) + (data (;0;) (i32.const 20) "\01\02\03\04\05") + (data (;1;) (memory $mem2) (i32.const 50) "\0a\0b\0c\0d\0e") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/load2.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/load2.wast/0.print new file mode 100644 index 0000000000..057cb76a20 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/load2.wast/0.print @@ -0,0 +1,309 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (type (;3;) (func (param i32 i32) (result i32))) + (func (;0;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load $m + br 0 (;@1;) + end + ) + (func (;1;) (type 2) + block ;; label = @1 + i32.const 0 + i32.load $m + br_if 0 (;@1;) + end + ) + (func (;2;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load $m + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;3;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + i32.load $m + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;4;) (type 2) + block ;; label = @1 + i32.const 0 + i32.load $m + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;5;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.load $m + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;6;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + i32.load $m + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;7;) (type 1) (result i32) + i32.const 0 + i32.load $m + return + ) + (func (;8;) (type 1) (result i32) + i32.const 0 + i32.load $m + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;9;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 0 + i32.load $m + else + i32.const 0 + end + ) + (func (;10;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 0 + i32.load $m + end + ) + (func (;11;) (type 3) (param i32 i32) (result i32) + i32.const 0 + i32.load $m + local.get 0 + local.get 1 + select + ) + (func (;12;) (type 3) (param i32 i32) (result i32) + local.get 0 + i32.const 0 + i32.load $m + local.get 1 + select + ) + (func (;13;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i32.const 0 + i32.load $m + select + ) + (func $f (;14;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;15;) (type 1) (result i32) + i32.const 0 + i32.load $m + i32.const 2 + i32.const 3 + call $f + ) + (func (;16;) (type 1) (result i32) + i32.const 1 + i32.const 0 + i32.load $m + i32.const 3 + call $f + ) + (func (;17;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + i32.load $m + call $f + ) + (func (;18;) (type 1) (result i32) + i32.const 0 + i32.load $m + i32.const 2 + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;19;) (type 1) (result i32) + i32.const 1 + i32.const 0 + i32.load $m + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;20;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + i32.load $m + i32.const 0 + call_indirect (type $sig) + ) + (func (;21;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 0 + i32.load $m + call_indirect (type $sig) + ) + (func (;22;) (type 2) + (local i32) + i32.const 0 + i32.load $m + local.set 0 + ) + (func (;23;) (type 1) (result i32) + (local i32) + i32.const 0 + i32.load $m + local.tee 0 + ) + (func (;24;) (type 2) + (local i32) + i32.const 0 + i32.load $m + global.set $g + ) + (func (;25;) (type 1) (result i32) + i32.const 0 + i32.load $m + i32.load $m + ) + (func (;26;) (type 1) (result i32) + i32.const 0 + i32.load $m + i32.load8_s $m + ) + (func (;27;) (type 2) + i32.const 0 + i32.load $m + i32.const 7 + i32.store $m + ) + (func (;28;) (type 2) + i32.const 2 + i32.const 0 + i32.load $m + i32.store $m + ) + (func (;29;) (type 2) + i32.const 0 + i32.load8_s $m + i32.const 7 + i32.store8 $m + ) + (func (;30;) (type 2) + i32.const 2 + i32.const 0 + i32.load $m + i32.store16 $m + ) + (func (;31;) (type 1) (result i32) + i32.const 100 + i32.load $m + i32.clz + ) + (func (;32;) (type 1) (result i32) + i32.const 100 + i32.load $m + i32.const 10 + i32.add + ) + (func (;33;) (type 1) (result i32) + i32.const 10 + i32.const 100 + i32.load $m + i32.sub + ) + (func (;34;) (type 1) (result i32) + i32.const 100 + i32.load $m + i32.eqz + ) + (func (;35;) (type 1) (result i32) + i32.const 100 + i32.load $m + i32.const 10 + i32.le_s + ) + (func (;36;) (type 1) (result i32) + i32.const 10 + i32.const 100 + i32.load $m + i32.ne + ) + (func (;37;) (type 1) (result i32) + i32.const 100 + i32.load $m + memory.grow $m + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 0) + (memory (;1;) 0) + (memory (;2;) 0) + (memory $m (;3;) 1) + (global $g (;0;) (mut i32) i32.const 0) + (export "as-br-value" (func 0)) + (export "as-br_if-cond" (func 1)) + (export "as-br_if-value" (func 2)) + (export "as-br_if-value-cond" (func 3)) + (export "as-br_table-index" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-br_table-value-index" (func 6)) + (export "as-return-value" (func 7)) + (export "as-if-cond" (func 8)) + (export "as-if-then" (func 9)) + (export "as-if-else" (func 10)) + (export "as-select-first" (func 11)) + (export "as-select-second" (func 12)) + (export "as-select-cond" (func 13)) + (export "as-call-first" (func 15)) + (export "as-call-mid" (func 16)) + (export "as-call-last" (func 17)) + (export "as-call_indirect-first" (func 18)) + (export "as-call_indirect-mid" (func 19)) + (export "as-call_indirect-last" (func 20)) + (export "as-call_indirect-index" (func 21)) + (export "as-local.set-value" (func 22)) + (export "as-local.tee-value" (func 23)) + (export "as-global.set-value" (func 24)) + (export "as-load-address" (func 25)) + (export "as-loadN-address" (func 26)) + (export "as-store-address" (func 27)) + (export "as-store-value" (func 28)) + (export "as-storeN-address" (func 29)) + (export "as-storeN-value" (func 30)) + (export "as-unary-operand" (func 31)) + (export "as-binary-left" (func 32)) + (export "as-binary-right" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-left" (func 35)) + (export "as-compare-right" (func 36)) + (export "as-memory.grow-size" (func 37)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory-multi.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory-multi.wast/0.print new file mode 100644 index 0000000000..717fbf003d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory-multi.wast/0.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + i32.const 0 + i32.const 4 + memory.init $d + i32.const 1 + i32.load + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + i32.const 4 + i32.const 4 + memory.init $mem2 $d + i32.const 1 + i32.load $mem2 + ) + (memory $mem1 (;0;) 1) + (memory $mem2 (;1;) 1) + (export "init1" (func 0)) + (export "init2" (func 1)) + (data $d (;0;) "\01\00\00\00\02\00\00\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory-multi.wast/3.print b/tests/snapshots/testsuite/proposals/multi-memory/memory-multi.wast/3.print new file mode 100644 index 0000000000..cce6ea75e5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory-multi.wast/3.print @@ -0,0 +1,23 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 1 + i32.const 1 + i32.const 4 + memory.fill + i32.const 1 + i32.load + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + i32.const 2 + i32.const 2 + memory.fill $mem2 + i32.const 1 + i32.load $mem2 + ) + (memory $mem1 (;0;) 1) + (memory $mem2 (;1;) 1) + (export "fill1" (func 0)) + (export "fill2" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/0.print new file mode 100644 index 0000000000..36938759b9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/0.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/1.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/1.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/1.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/10.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/10.print new file mode 100644 index 0000000000..94e698954c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/10.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 1 1) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "x") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/2.print new file mode 100644 index 0000000000..d76aa6a0fa --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/2.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/3.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/3.print new file mode 100644 index 0000000000..0f5c3ea229 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/3.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/31.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/31.print new file mode 100644 index 0000000000..1dc6026a7b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/31.print @@ -0,0 +1,154 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result f64))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i64) (result i64))) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.load8_u + i32.const 65 + i32.eq + i32.const 3 + i32.load8_u + i32.const 167 + i32.eq + i32.and + i32.const 6 + i32.load8_u + i32.const 0 + i32.eq + i32.const 19 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.const 20 + i32.load8_u + i32.const 87 + i32.eq + i32.const 23 + i32.load8_u + i32.const 77 + i32.eq + i32.and + i32.const 24 + i32.load8_u + i32.const 0 + i32.eq + i32.const 1023 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.and + ) + (func (;1;) (type 1) (result f64) + i32.const 8 + i64.const -12345 + i64.store + i32.const 8 + f64.load + i64.const -12345 + f64.reinterpret_i64 + f64.eq + if ;; label = @1 + f64.const 0x0p+0 (;=0;) + return + end + i32.const 9 + i64.const 0 + i64.store align=1 + i32.const 15 + i32.const 16453 + i32.store16 align=1 + i32.const 9 + f64.load align=1 + ) + (func (;2;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store8 + i32.const 8 + i32.load8_s + ) + (func (;3;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store8 + i32.const 8 + i32.load8_u + ) + (func (;4;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store16 + i32.const 8 + i32.load16_s + ) + (func (;5;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store16 + i32.const 8 + i32.load16_u + ) + (func (;6;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store8 + i32.const 8 + i64.load8_s + ) + (func (;7;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store8 + i32.const 8 + i64.load8_u + ) + (func (;8;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store16 + i32.const 8 + i64.load16_s + ) + (func (;9;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store16 + i32.const 8 + i64.load16_u + ) + (func (;10;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store32 + i32.const 8 + i64.load32_s + ) + (func (;11;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store32 + i32.const 8 + i64.load32_u + ) + (memory (;0;) 1) + (export "data" (func 0)) + (export "cast" (func 1)) + (export "i32_load8_s" (func 2)) + (export "i32_load8_u" (func 3)) + (export "i32_load16_s" (func 4)) + (export "i32_load16_u" (func 5)) + (export "i64_load8_s" (func 6)) + (export "i64_load8_u" (func 7)) + (export "i64_load16_s" (func 8)) + (export "i64_load16_u" (func 9)) + (export "i64_load32_s" (func 10)) + (export "i64_load32_u" (func 11)) + (data (;0;) (i32.const 0) "ABC\a7D") + (data (;1;) (i32.const 20) "WASM") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/4.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/4.print new file mode 100644 index 0000000000..d280c1e33b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/4.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1 256) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/5.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/5.print new file mode 100644 index 0000000000..21d5f6b5c9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/5.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 65536) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/6.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/6.print new file mode 100644 index 0000000000..0cdda46d31 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/6.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0 0) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/8.print b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/8.print new file mode 100644 index 0000000000..0cdda46d31 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory.wast/8.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0 0) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_copy0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_copy0.wast/0.print new file mode 100644 index 0000000000..7d6b138ab2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_copy0.wast/0.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + memory.copy $mem3 $mem3 + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u $mem3 + ) + (memory $mem0 (;0;) 1 1) + (memory $mem1 (;1;) 1 1) + (memory $mem2 (;2;) 1 1) + (memory $mem3 (;3;) 1 1) + (export "copy" (func 0)) + (export "load8_u" (func 1)) + (data (;0;) (i32.const 0) "\ff\11D\ee") + (data (;1;) (memory $mem1) (i32.const 0) "\ee\22U\ff") + (data (;2;) (memory $mem2) (i32.const 0) "\dd3f\00") + (data (;3;) (memory $mem3) (i32.const 0) "\aa\bb\cc\dd") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_fill0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_fill0.wast/0.print new file mode 100644 index 0000000000..aef73759ec --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_fill0.wast/0.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + memory.fill $mem2 + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u $mem2 + ) + (memory $mem0 (;0;) 0) + (memory $mem1 (;1;) 0) + (memory $mem2 (;2;) 1) + (export "fill" (func 0)) + (export "load8_u" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/0.print new file mode 100644 index 0000000000..39585bdbd5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/0.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (memory (;0;) 0) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/132.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/132.print new file mode 100644 index 0000000000..40879089b9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/132.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (func (;1;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow $mem2 + ) + (func (;2;) (type 1) (result i32) + memory.size + ) + (func (;3;) (type 1) (result i32) + memory.size $mem2 + ) + (memory $mem1 (;0;) 1) + (memory $mem2 (;1;) 2) + (export "grow1" (func 0)) + (export "grow2" (func 1)) + (export "size1" (func 2)) + (export "size2" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/18.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/18.print new file mode 100644 index 0000000000..00eb748955 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/18.print @@ -0,0 +1,40 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (func (;1;) (type 1) (param i32 i32) (result i32) + (local i32) + i32.const 1 + local.set 2 + block ;; label = @1 + loop ;; label = @2 + local.get 0 + i32.load8_u + local.set 2 + local.get 2 + i32.const 0 + i32.ne + br_if 1 (;@1;) + local.get 0 + local.get 1 + i32.ge_u + br_if 1 (;@1;) + local.get 0 + i32.const 1 + i32.add + local.set 0 + local.get 0 + local.get 1 + i32.le_u + br_if 0 (;@2;) + end + end + local.get 2 + ) + (memory (;0;) 1) + (export "grow" (func 0)) + (export "check-memory-zero" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/30.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/30.print new file mode 100644 index 0000000000..6701d29d6c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/30.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.load + ) + (func (;1;) (type 1) + i32.const 0 + i32.const 2 + i32.store + ) + (func (;2;) (type 0) (result i32) + i32.const 65536 + i32.load + ) + (func (;3;) (type 1) + i32.const 65536 + i32.const 3 + i32.store + ) + (func (;4;) (type 2) (param i32) (result i32) + local.get 0 + memory.grow + ) + (func (;5;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0) + (export "load_at_zero" (func 0)) + (export "store_at_zero" (func 1)) + (export "load_at_page_size" (func 2)) + (export "store_at_page_size" (func 3)) + (export "grow" (func 4)) + (export "size" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/51.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/51.print new file mode 100644 index 0000000000..99adbda788 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/51.print @@ -0,0 +1,6 @@ +(module + (memory (;0;) 2 5) + (memory (;1;) 0) + (export "mem1" (memory 0)) + (export "mem2" (memory 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/53.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/53.print new file mode 100644 index 0000000000..d5002e1a41 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/53.print @@ -0,0 +1,44 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "M" "mem1" (memory $mem1 (;0;) 1 6)) + (import "M" "mem2" (memory $mem2 (;1;) 0)) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 0) (result i32) + memory.size $mem2 + ) + (func (;2;) (type 0) (result i32) + memory.size $mem3 + ) + (func (;3;) (type 0) (result i32) + memory.size $mem4 + ) + (func (;4;) (type 1) (param i32) (result i32) + local.get 0 + memory.grow + ) + (func (;5;) (type 1) (param i32) (result i32) + local.get 0 + memory.grow $mem2 + ) + (func (;6;) (type 1) (param i32) (result i32) + local.get 0 + memory.grow $mem3 + ) + (func (;7;) (type 1) (param i32) (result i32) + local.get 0 + memory.grow $mem4 + ) + (memory $mem3 (;2;) 3) + (memory $mem4 (;3;) 4 5) + (export "size1" (func 0)) + (export "size2" (func 1)) + (export "size3" (func 2)) + (export "size4" (func 3)) + (export "grow1" (func 4)) + (export "grow2" (func 5)) + (export "grow3" (func 6)) + (export "grow4" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/9.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/9.print new file mode 100644 index 0000000000..1795e0039b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/9.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (memory (;0;) 0 10) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/94.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/94.print new file mode 100644 index 0000000000..bb9880c31a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_grow.wast/94.print @@ -0,0 +1,306 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (type (;3;) (func (param i32 i32) (result i32))) + (func (;0;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + memory.grow + br 0 (;@1;) + end + ) + (func (;1;) (type 2) + block ;; label = @1 + i32.const 0 + memory.grow + br_if 0 (;@1;) + end + ) + (func (;2;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + memory.grow + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;3;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + memory.grow + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;4;) (type 2) + block ;; label = @1 + i32.const 0 + memory.grow + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;5;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + memory.grow + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;6;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 0 + memory.grow + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;7;) (type 1) (result i32) + i32.const 0 + memory.grow + return + ) + (func (;8;) (type 1) (result i32) + i32.const 0 + memory.grow + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;9;) (type 1) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 0 + memory.grow + else + i32.const 0 + end + ) + (func (;10;) (type 1) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 0 + memory.grow + end + ) + (func (;11;) (type 3) (param i32 i32) (result i32) + i32.const 0 + memory.grow + local.get 0 + local.get 1 + select + ) + (func (;12;) (type 3) (param i32 i32) (result i32) + local.get 0 + i32.const 0 + memory.grow + local.get 1 + select + ) + (func (;13;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i32.const 0 + memory.grow + select + ) + (func $f (;14;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;15;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.const 2 + i32.const 3 + call $f + ) + (func (;16;) (type 1) (result i32) + i32.const 1 + i32.const 0 + memory.grow + i32.const 3 + call $f + ) + (func (;17;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + memory.grow + call $f + ) + (func (;18;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.const 2 + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;19;) (type 1) (result i32) + i32.const 1 + i32.const 0 + memory.grow + i32.const 3 + i32.const 0 + call_indirect (type $sig) + ) + (func (;20;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 0 + memory.grow + i32.const 0 + call_indirect (type $sig) + ) + (func (;21;) (type 1) (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 0 + memory.grow + call_indirect (type $sig) + ) + (func (;22;) (type 2) + (local i32) + i32.const 0 + memory.grow + local.set 0 + ) + (func (;23;) (type 1) (result i32) + (local i32) + i32.const 0 + memory.grow + local.tee 0 + ) + (func (;24;) (type 2) + (local i32) + i32.const 0 + memory.grow + global.set $g + ) + (func (;25;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.load + ) + (func (;26;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.load8_s + ) + (func (;27;) (type 2) + i32.const 0 + memory.grow + i32.const 7 + i32.store + ) + (func (;28;) (type 2) + i32.const 2 + i32.const 0 + memory.grow + i32.store + ) + (func (;29;) (type 2) + i32.const 0 + memory.grow + i32.const 7 + i32.store8 + ) + (func (;30;) (type 2) + i32.const 2 + i32.const 0 + memory.grow + i32.store16 + ) + (func (;31;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.clz + ) + (func (;32;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.const 10 + i32.add + ) + (func (;33;) (type 1) (result i32) + i32.const 10 + i32.const 0 + memory.grow + i32.sub + ) + (func (;34;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.eqz + ) + (func (;35;) (type 1) (result i32) + i32.const 0 + memory.grow + i32.const 10 + i32.le_s + ) + (func (;36;) (type 1) (result i32) + i32.const 10 + i32.const 0 + memory.grow + i32.ne + ) + (func (;37;) (type 1) (result i32) + i32.const 0 + memory.grow + memory.grow + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $g (;0;) (mut i32) i32.const 0) + (export "as-br-value" (func 0)) + (export "as-br_if-cond" (func 1)) + (export "as-br_if-value" (func 2)) + (export "as-br_if-value-cond" (func 3)) + (export "as-br_table-index" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-br_table-value-index" (func 6)) + (export "as-return-value" (func 7)) + (export "as-if-cond" (func 8)) + (export "as-if-then" (func 9)) + (export "as-if-else" (func 10)) + (export "as-select-first" (func 11)) + (export "as-select-second" (func 12)) + (export "as-select-cond" (func 13)) + (export "as-call-first" (func 15)) + (export "as-call-mid" (func 16)) + (export "as-call-last" (func 17)) + (export "as-call_indirect-first" (func 18)) + (export "as-call_indirect-mid" (func 19)) + (export "as-call_indirect-last" (func 20)) + (export "as-call_indirect-index" (func 21)) + (export "as-local.set-value" (func 22)) + (export "as-local.tee-value" (func 23)) + (export "as-global.set-value" (func 24)) + (export "as-load-address" (func 25)) + (export "as-loadN-address" (func 26)) + (export "as-store-address" (func 27)) + (export "as-store-value" (func 28)) + (export "as-storeN-address" (func 29)) + (export "as-storeN-value" (func 30)) + (export "as-unary-operand" (func 31)) + (export "as-binary-left" (func 32)) + (export "as-binary-right" (func 33)) + (export "as-test-operand" (func 34)) + (export "as-compare-left" (func 35)) + (export "as-compare-right" (func 36)) + (export "as-memory.grow-size" (func 37)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_init0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_init0.wast/0.print new file mode 100644 index 0000000000..955f2d4045 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_init0.wast/0.print @@ -0,0 +1,21 @@ +(module + (type (;0;) (func (param i32 i32 i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + memory.init $mem2 $mem2 + ) + (func (;1;) (type 1) (param i32) (result i32) + local.get 0 + i32.load8_u $mem2 + ) + (memory $mem0 (;0;) 0) + (memory $mem1 (;1;) 0) + (memory $mem2 (;2;) 1) + (memory $mem3 (;3;) 0) + (export "init" (func 0)) + (export "load8_u" (func 1)) + (data $mem2 (;0;) "\aa\bb\cc\dd") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/0.print new file mode 100644 index 0000000000..068665a77c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/0.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow + drop + ) + (memory (;0;) 0) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/16.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/16.print new file mode 100644 index 0000000000..a1f80fc2a2 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/16.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow + drop + ) + (memory (;0;) 0 2) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/28.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/28.print new file mode 100644 index 0000000000..de54b63489 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/28.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow + drop + ) + (memory (;0;) 3 8) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/40.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/40.print new file mode 100644 index 0000000000..5ade7dbf15 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/40.print @@ -0,0 +1,6 @@ +(module + (memory (;0;) 2 4) + (memory (;1;) 0) + (export "mem1" (memory 0)) + (export "mem2" (memory 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/42.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/42.print new file mode 100644 index 0000000000..7a109b6ceb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/42.print @@ -0,0 +1,23 @@ +(module + (type (;0;) (func (result i32))) + (import "M" "mem1" (memory $mem1 (;0;) 1 5)) + (import "M" "mem2" (memory $mem2 (;1;) 0)) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 0) (result i32) + memory.size $mem2 + ) + (func (;2;) (type 0) (result i32) + memory.size $mem3 + ) + (func (;3;) (type 0) (result i32) + memory.size $mem4 + ) + (memory $mem3 (;2;) 3) + (memory $mem4 (;3;) 4 5) + (export "size1" (func 0)) + (export "size2" (func 1)) + (export "size3" (func 2)) + (export "size4" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/8.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/8.print new file mode 100644 index 0000000000..bbaf0511e4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size.wast/8.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow + drop + ) + (memory (;0;) 1) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size0.wast/0.print new file mode 100644 index 0000000000..c5a1828fae --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size0.wast/0.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size $m + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow $m + drop + ) + (memory (;0;) 0) + (memory (;1;) 0) + (memory (;2;) 0) + (memory (;3;) 0) + (memory $m (;4;) 0) + (export "size" (func 0)) + (export "grow" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size1.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size1.wast/0.print new file mode 100644 index 0000000000..94bbe84ac7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size1.wast/0.print @@ -0,0 +1,29 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size $m + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow $m + drop + ) + (func (;2;) (type 0) (result i32) + memory.size $n + ) + (func (;3;) (type 1) (param $sz i32) + local.get $sz + memory.grow $n + drop + ) + (memory (;0;) 0) + (memory (;1;) 0) + (memory $n (;2;) 0) + (memory (;3;) 0) + (memory $m (;4;) 0) + (export "size" (func 0)) + (export "grow" (func 1)) + (export "sizen" (func 2)) + (export "grown" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_size2.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_size2.wast/0.print new file mode 100644 index 0000000000..02dc8700cc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_size2.wast/0.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + memory.size $m + ) + (func (;1;) (type 1) (param $sz i32) + local.get $sz + memory.grow $m + drop + ) + (func (;2;) (type 0) (result i32) + memory.size $n + ) + (func (;3;) (type 1) (param $sz i32) + local.get $sz + memory.grow $n + drop + ) + (memory (;0;) 0 0) + (memory (;1;) 0 0) + (memory $n (;2;) 0 0) + (memory $m (;3;) 0 2) + (export "size" (func 0)) + (export "grow" (func 1)) + (export "sizen" (func 2)) + (export "grown" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_trap0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_trap0.wast/0.print new file mode 100644 index 0000000000..f38a09aa88 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_trap0.wast/0.print @@ -0,0 +1,33 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32 i32))) + (type (;2;) (func (param i32) (result i32))) + (func $addr_limit (;0;) (type 0) (result i32) + memory.size $m + i32.const 65536 + i32.mul + ) + (func (;1;) (type 1) (param $i i32) (param $v i32) + call $addr_limit + local.get $i + i32.add + local.get $v + i32.store $m + ) + (func (;2;) (type 2) (param $i i32) (result i32) + call $addr_limit + local.get $i + i32.add + i32.load $m + ) + (func (;3;) (type 2) (param i32) (result i32) + local.get 0 + memory.grow $m + ) + (memory (;0;) 0) + (memory (;1;) 0) + (memory $m (;2;) 1) + (export "store" (func 1)) + (export "load" (func 2)) + (export "memory.grow" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/memory_trap1.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/memory_trap1.wast/0.print new file mode 100644 index 0000000000..993b268b72 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/memory_trap1.wast/0.print @@ -0,0 +1,139 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32) (result i64))) + (type (;2;) (func (param i32) (result f32))) + (type (;3;) (func (param i32) (result f64))) + (type (;4;) (func (param i32 i32))) + (type (;5;) (func (param i32 i64))) + (type (;6;) (func (param i32 f32))) + (type (;7;) (func (param i32 f64))) + (func (;0;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load $m + ) + (func (;1;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load $m + ) + (func (;2;) (type 2) (param $a i32) (result f32) + local.get $a + f32.load $m + ) + (func (;3;) (type 3) (param $a i32) (result f64) + local.get $a + f64.load $m + ) + (func (;4;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_s $m + ) + (func (;5;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load8_u $m + ) + (func (;6;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load16_s $m + ) + (func (;7;) (type 0) (param $a i32) (result i32) + local.get $a + i32.load16_u $m + ) + (func (;8;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load8_s $m + ) + (func (;9;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load8_u $m + ) + (func (;10;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load16_s $m + ) + (func (;11;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load16_u $m + ) + (func (;12;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load32_s $m + ) + (func (;13;) (type 1) (param $a i32) (result i64) + local.get $a + i64.load32_u $m + ) + (func (;14;) (type 4) (param $a i32) (param $v i32) + local.get $a + local.get $v + i32.store $m + ) + (func (;15;) (type 5) (param $a i32) (param $v i64) + local.get $a + local.get $v + i64.store $m + ) + (func (;16;) (type 6) (param $a i32) (param $v f32) + local.get $a + local.get $v + f32.store $m + ) + (func (;17;) (type 7) (param $a i32) (param $v f64) + local.get $a + local.get $v + f64.store $m + ) + (func (;18;) (type 4) (param $a i32) (param $v i32) + local.get $a + local.get $v + i32.store8 $m + ) + (func (;19;) (type 4) (param $a i32) (param $v i32) + local.get $a + local.get $v + i32.store16 $m + ) + (func (;20;) (type 5) (param $a i32) (param $v i64) + local.get $a + local.get $v + i64.store8 $m + ) + (func (;21;) (type 5) (param $a i32) (param $v i64) + local.get $a + local.get $v + i64.store16 $m + ) + (func (;22;) (type 5) (param $a i32) (param $v i64) + local.get $a + local.get $v + i64.store32 $m + ) + (memory (;0;) 0) + (memory (;1;) 0) + (memory $m (;2;) 1) + (export "i32.load" (func 0)) + (export "i64.load" (func 1)) + (export "f32.load" (func 2)) + (export "f64.load" (func 3)) + (export "i32.load8_s" (func 4)) + (export "i32.load8_u" (func 5)) + (export "i32.load16_s" (func 6)) + (export "i32.load16_u" (func 7)) + (export "i64.load8_s" (func 8)) + (export "i64.load8_u" (func 9)) + (export "i64.load16_s" (func 10)) + (export "i64.load16_u" (func 11)) + (export "i64.load32_s" (func 12)) + (export "i64.load32_u" (func 13)) + (export "i32.store" (func 14)) + (export "i64.store" (func 15)) + (export "f32.store" (func 16)) + (export "f64.store" (func 17)) + (export "i32.store8" (func 18)) + (export "i32.store16" (func 19)) + (export "i64.store8" (func 20)) + (export "i64.store16" (func 21)) + (export "i64.store32" (func 22)) + (data (;0;) (memory $m) (i32.const 0) "abcdefgh") + (data (;1;) (memory $m) (i32.const 65528) "abcdefgh") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/simd_memory-multi.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/simd_memory-multi.wast/0.print new file mode 100644 index 0000000000..a5e337ce75 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/simd_memory-multi.wast/0.print @@ -0,0 +1,92 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + (local $v v128) + i32.const 0 + local.get $v + v128.load8_lane 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.load8_lane $m 1 + drop + i32.const 0 + local.get $v + v128.store8_lane 1 + i32.const 0 + local.get $v + v128.store8_lane 1 + i32.const 0 + local.get $v + v128.store8_lane 1 + i32.const 0 + local.get $v + v128.store8_lane 1 + i32.const 0 + local.get $v + v128.store8_lane $m 1 + i32.const 0 + local.get $v + v128.store8_lane $m 1 + i32.const 0 + local.get $v + v128.store8_lane $m 1 + i32.const 0 + local.get $v + v128.store8_lane $m 1 + i32.const 0 + local.get $v + v128.store8_lane $m 1 + i32.const 0 + local.get $v + v128.store8_lane $m 1 + i32.const 0 + local.get $v + v128.store8_lane $m 1 + i32.const 0 + local.get $v + v128.store8_lane $m 1 + ) + (memory (;0;) 1) + (memory $m (;1;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/start0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/start0.wast/0.print new file mode 100644 index 0000000000..9c3de268a7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/start0.wast/0.print @@ -0,0 +1,35 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (func $inc (;0;) (type 0) + i32.const 0 + i32.const 0 + i32.load8_u $m + i32.const 1 + i32.add + i32.store8 $m + ) + (func $get (;1;) (type 1) (result i32) + i32.const 0 + i32.load8_u $m + return + ) + (func $getn (;2;) (type 1) (result i32) + i32.const 0 + i32.load8_u $n + return + ) + (func $main (;3;) (type 0) + call $inc + call $inc + call $inc + ) + (memory (;0;) 0) + (memory $m (;1;) 1 1) + (memory $n (;2;) 1) + (export "inc" (func $inc)) + (export "get" (func $get)) + (export "getn" (func $getn)) + (start $main) + (data (;0;) (memory $m) (i32.const 0) "A") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/0.print new file mode 100644 index 0000000000..10a65d1187 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/0.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32 i64))) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 0) (param i32) (result i64) + local.get 0 + i64.load $mem2 + ) + (func (;2;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store + ) + (func (;3;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store $mem2 + ) + (memory $mem1 (;0;) 1) + (memory $mem2 (;1;) 1) + (export "load1" (func 0)) + (export "load2" (func 1)) + (export "store1" (func 2)) + (export "store2" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store.wast/13.print b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/13.print new file mode 100644 index 0000000000..d1afd2536b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/13.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32 i64))) + (import "M1" "mem" (memory $mem1 (;0;) 1)) + (import "M2" "mem" (memory $mem2 (;1;) 1)) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 0) (param i32) (result i64) + local.get 0 + i64.load $mem2 + ) + (func (;2;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store + ) + (func (;3;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store $mem2 + ) + (export "load1" (func 0)) + (export "load2" (func 1)) + (export "store1" (func 2)) + (export "store2" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store.wast/18.print b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/18.print new file mode 100644 index 0000000000..24e2465218 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/18.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 2) + (export "mem" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store.wast/20.print b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/20.print new file mode 100644 index 0000000000..3622345ce8 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/20.print @@ -0,0 +1,60 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func)) + (import "M" "mem" (memory $mem1 (;0;) 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load8_u + ) + (func (;1;) (type 0) (param i32) (result i32) + local.get 0 + i32.load8_u $mem2 + ) + (func (;2;) (type 1) + (local $i i32) + i32.const 20 + local.set $i + loop $cont ;; label = @1 + local.get $i + i32.const 23 + i32.eq + br_if 1 (;@0;) + local.get $i + local.get $i + i32.load8_u + i32.store8 $mem2 + local.get $i + i32.const 1 + i32.add + local.set $i + br 0 (;@1;) + end + ) + (func (;3;) (type 1) + (local $i i32) + i32.const 50 + local.set $i + loop $cont ;; label = @1 + local.get $i + i32.const 54 + i32.eq + br_if 1 (;@0;) + local.get $i + local.get $i + i32.load8_u $mem2 + i32.store8 + local.get $i + i32.const 1 + i32.add + local.set $i + br 0 (;@1;) + end + ) + (memory $mem2 (;1;) 3) + (export "read1" (func 0)) + (export "read2" (func 1)) + (export "copy-1-to-2" (func 2)) + (export "copy-2-to-1" (func 3)) + (data (;0;) (i32.const 20) "\01\02\03\04\05") + (data (;1;) (memory $mem2) (i32.const 50) "\0a\0b\0c\0d\0e") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store.wast/43.print b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/43.print new file mode 100644 index 0000000000..188d319f07 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/43.print @@ -0,0 +1,85 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + end + ) + (func (;1;) (type 0) + loop ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + end + ) + (func (;2;) (type 0) + block ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + br 0 (;@1;) + end + ) + (func (;3;) (type 0) + block ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;4;) (type 0) + block ;; label = @1 + i32.const 6 + i32.const 0 + i32.const 1 + i32.store + br_if 0 (;@1;) + end + ) + (func (;5;) (type 0) + block ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + i32.const 1 + br_table 0 (;@1;) + end + ) + (func (;6;) (type 0) + i32.const 0 + i32.const 1 + i32.store + return + ) + (func (;7;) (type 0) + i32.const 1 + if ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + end + ) + (func (;8;) (type 0) + i32.const 0 + if ;; label = @1 + else + i32.const 0 + i32.const 1 + i32.store + end + ) + (memory (;0;) 1) + (export "as-block-value" (func 0)) + (export "as-loop-value" (func 1)) + (export "as-br-value" (func 2)) + (export "as-br_if-value" (func 3)) + (export "as-br_if-value-cond" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-return-value" (func 6)) + (export "as-if-then" (func 7)) + (export "as-if-else" (func 8)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store.wast/5.print b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/5.print new file mode 100644 index 0000000000..368264fdee --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/5.print @@ -0,0 +1,17 @@ +(module $M1 + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32 i64))) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store + ) + (memory (;0;) 1) + (export "mem" (memory 0)) + (export "load" (func 0)) + (export "store" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store.wast/7.print b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/7.print new file mode 100644 index 0000000000..3746a00c97 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store.wast/7.print @@ -0,0 +1,17 @@ +(module $M2 + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32 i64))) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store + ) + (memory (;0;) 1) + (export "mem" (memory 0)) + (export "load" (func 0)) + (export "store" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/store0.wast/0.print new file mode 100644 index 0000000000..10a65d1187 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store0.wast/0.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32 i64))) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 0) (param i32) (result i64) + local.get 0 + i64.load $mem2 + ) + (func (;2;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store + ) + (func (;3;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store $mem2 + ) + (memory $mem1 (;0;) 1) + (memory $mem2 (;1;) 1) + (export "load1" (func 0)) + (export "load2" (func 1)) + (export "store1" (func 2)) + (export "store2" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/0.print new file mode 100644 index 0000000000..368264fdee --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/0.print @@ -0,0 +1,17 @@ +(module $M1 + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32 i64))) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store + ) + (memory (;0;) 1) + (export "mem" (memory 0)) + (export "load" (func 0)) + (export "store" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/2.print b/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/2.print new file mode 100644 index 0000000000..3746a00c97 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/2.print @@ -0,0 +1,17 @@ +(module $M2 + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32 i64))) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store + ) + (memory (;0;) 1) + (export "mem" (memory 0)) + (export "load" (func 0)) + (export "store" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/8.print b/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/8.print new file mode 100644 index 0000000000..d1afd2536b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/store1.wast/8.print @@ -0,0 +1,28 @@ +(module + (type (;0;) (func (param i32) (result i64))) + (type (;1;) (func (param i32 i64))) + (import "M1" "mem" (memory $mem1 (;0;) 1)) + (import "M2" "mem" (memory $mem2 (;1;) 1)) + (func (;0;) (type 0) (param i32) (result i64) + local.get 0 + i64.load + ) + (func (;1;) (type 0) (param i32) (result i64) + local.get 0 + i64.load $mem2 + ) + (func (;2;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store + ) + (func (;3;) (type 1) (param i32 i64) + local.get 0 + local.get 1 + i64.store $mem2 + ) + (export "load1" (func 0)) + (export "load2" (func 1)) + (export "store1" (func 2)) + (export "store2" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/multi-memory/traps0.wast/0.print b/tests/snapshots/testsuite/proposals/multi-memory/traps0.wast/0.print new file mode 100644 index 0000000000..b0cc854d08 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/multi-memory/traps0.wast/0.print @@ -0,0 +1,90 @@ +(module + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) + local.get $i + i32.load $mem1 + drop + ) + (func (;1;) (type 0) (param $i i32) + local.get $i + i32.load16_s $mem1 + drop + ) + (func (;2;) (type 0) (param $i i32) + local.get $i + i32.load16_u $mem1 + drop + ) + (func (;3;) (type 0) (param $i i32) + local.get $i + i32.load8_s $mem1 + drop + ) + (func (;4;) (type 0) (param $i i32) + local.get $i + i32.load8_u $mem1 + drop + ) + (func (;5;) (type 0) (param $i i32) + local.get $i + i64.load $mem1 + drop + ) + (func (;6;) (type 0) (param $i i32) + local.get $i + i64.load32_s $mem1 + drop + ) + (func (;7;) (type 0) (param $i i32) + local.get $i + i64.load32_u $mem2 + drop + ) + (func (;8;) (type 0) (param $i i32) + local.get $i + i64.load16_s $mem2 + drop + ) + (func (;9;) (type 0) (param $i i32) + local.get $i + i64.load16_u $mem2 + drop + ) + (func (;10;) (type 0) (param $i i32) + local.get $i + i64.load8_s $mem2 + drop + ) + (func (;11;) (type 0) (param $i i32) + local.get $i + i64.load8_u $mem2 + drop + ) + (func (;12;) (type 0) (param $i i32) + local.get $i + f32.load $mem2 + drop + ) + (func (;13;) (type 0) (param $i i32) + local.get $i + f64.load $mem2 + drop + ) + (memory $mem0 (;0;) 1) + (memory $mem1 (;1;) 1) + (memory $mem2 (;2;) 1) + (export "no_dce.i32.load" (func 0)) + (export "no_dce.i32.load16_s" (func 1)) + (export "no_dce.i32.load16_u" (func 2)) + (export "no_dce.i32.load8_s" (func 3)) + (export "no_dce.i32.load8_u" (func 4)) + (export "no_dce.i64.load" (func 5)) + (export "no_dce.i64.load32_s" (func 6)) + (export "no_dce.i64.load32_u" (func 7)) + (export "no_dce.i64.load16_s" (func 8)) + (export "no_dce.i64.load16_u" (func 9)) + (export "no_dce.i64.load8_s" (func 10)) + (export "no_dce.i64.load8_u" (func 11)) + (export "no_dce.f32.load" (func 12)) + (export "no_dce.f64.load" (func 13)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/relaxed-simd/i16x8_relaxed_q15mulr_s.wast/0.print b/tests/snapshots/testsuite/proposals/relaxed-simd/i16x8_relaxed_q15mulr_s.wast/0.print new file mode 100644 index 0000000000..4880c281c9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/relaxed-simd/i16x8_relaxed_q15mulr_s.wast/0.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.relaxed_q15mulr_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.relaxed_q15mulr_s + local.get 0 + local.get 1 + i16x8.relaxed_q15mulr_s + i16x8.eq + ) + (export "i16x8.relaxed_q15mulr_s" (func 0)) + (export "i16x8.relaxed_q15mulr_s_cmp" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/relaxed-simd/i32x4_relaxed_trunc.wast/0.print b/tests/snapshots/testsuite/proposals/relaxed-simd/i32x4_relaxed_trunc.wast/0.print new file mode 100644 index 0000000000..31918d5abb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/relaxed-simd/i32x4_relaxed_trunc.wast/0.print @@ -0,0 +1,55 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f32x4_s + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f32x4_u + ) + (func (;2;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f64x2_s_zero + ) + (func (;3;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f64x2_u_zero + ) + (func (;4;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f32x4_s + local.get 0 + i32x4.relaxed_trunc_f32x4_s + i32x4.eq + ) + (func (;5;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f32x4_u + local.get 0 + i32x4.relaxed_trunc_f32x4_u + i32x4.eq + ) + (func (;6;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f64x2_s_zero + local.get 0 + i32x4.relaxed_trunc_f64x2_s_zero + i32x4.eq + ) + (func (;7;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.relaxed_trunc_f64x2_u_zero + local.get 0 + i32x4.relaxed_trunc_f64x2_u_zero + i32x4.eq + ) + (export "i32x4.relaxed_trunc_f32x4_s" (func 0)) + (export "i32x4.relaxed_trunc_f32x4_u" (func 1)) + (export "i32x4.relaxed_trunc_f64x2_s_zero" (func 2)) + (export "i32x4.relaxed_trunc_f64x2_u_zero" (func 3)) + (export "i32x4.relaxed_trunc_f32x4_s_cmp" (func 4)) + (export "i32x4.relaxed_trunc_f32x4_u_cmp" (func 5)) + (export "i32x4.relaxed_trunc_f64x2_s_zero_cmp" (func 6)) + (export "i32x4.relaxed_trunc_f64x2_u_zero_cmp" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/relaxed-simd/i8x16_relaxed_swizzle.wast/0.print b/tests/snapshots/testsuite/proposals/relaxed-simd/i8x16_relaxed_swizzle.wast/0.print new file mode 100644 index 0000000000..2a156a041f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/relaxed-simd/i8x16_relaxed_swizzle.wast/0.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.relaxed_swizzle + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.relaxed_swizzle + local.get 0 + local.get 1 + i8x16.relaxed_swizzle + i8x16.eq + ) + (export "i8x16.relaxed_swizzle" (func 0)) + (export "i8x16.relaxed_swizzle_cmp" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_dot_product.wast/0.print b/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_dot_product.wast/0.print new file mode 100644 index 0000000000..72a9e2641c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_dot_product.wast/0.print @@ -0,0 +1,39 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128 v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.relaxed_dot_i8x16_i7x16_s + ) + (func (;1;) (type 1) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_dot_i8x16_i7x16_add_s + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.relaxed_dot_i8x16_i7x16_s + local.get 0 + local.get 1 + i16x8.relaxed_dot_i8x16_i7x16_s + i16x8.eq + ) + (func (;3;) (type 1) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_dot_i8x16_i7x16_add_s + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_dot_i8x16_i7x16_add_s + i16x8.eq + ) + (export "i16x8.relaxed_dot_i8x16_i7x16_s" (func 0)) + (export "i32x4.relaxed_dot_i8x16_i7x16_add_s" (func 1)) + (export "i16x8.relaxed_dot_i8x16_i7x16_s_cmp" (func 2)) + (export "i32x4.relaxed_dot_i8x16_i7x16_add_s_cmp" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_laneselect.wast/0.print b/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_laneselect.wast/0.print new file mode 100644 index 0000000000..e24515e35a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_laneselect.wast/0.print @@ -0,0 +1,79 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i8x16.relaxed_laneselect + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i16x8.relaxed_laneselect + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_laneselect + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i64x2.relaxed_laneselect + ) + (func (;4;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i8x16.relaxed_laneselect + local.get 0 + local.get 1 + local.get 2 + i8x16.relaxed_laneselect + i8x16.eq + ) + (func (;5;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i16x8.relaxed_laneselect + local.get 0 + local.get 1 + local.get 2 + i16x8.relaxed_laneselect + i16x8.eq + ) + (func (;6;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_laneselect + local.get 0 + local.get 1 + local.get 2 + i32x4.relaxed_laneselect + i32x4.eq + ) + (func (;7;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + i64x2.relaxed_laneselect + local.get 0 + local.get 1 + local.get 2 + i64x2.relaxed_laneselect + i64x2.eq + ) + (export "i8x16.relaxed_laneselect" (func 0)) + (export "i16x8.relaxed_laneselect" (func 1)) + (export "i32x4.relaxed_laneselect" (func 2)) + (export "i64x2.relaxed_laneselect" (func 3)) + (export "i8x16.relaxed_laneselect_cmp" (func 4)) + (export "i16x8.relaxed_laneselect_cmp" (func 5)) + (export "i32x4.relaxed_laneselect_cmp" (func 6)) + (export "i64x2.relaxed_laneselect_cmp" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_madd_nmadd.wast/0.print b/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_madd_nmadd.wast/0.print new file mode 100644 index 0000000000..906eeb4222 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_madd_nmadd.wast/0.print @@ -0,0 +1,79 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f32x4.relaxed_madd + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f32x4.relaxed_nmadd + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f64x2.relaxed_nmadd + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f64x2.relaxed_madd + ) + (func (;4;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f32x4.relaxed_madd + local.get 0 + local.get 1 + local.get 2 + f32x4.relaxed_madd + f32x4.eq + ) + (func (;5;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f32x4.relaxed_nmadd + local.get 0 + local.get 1 + local.get 2 + f32x4.relaxed_nmadd + f32x4.eq + ) + (func (;6;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f64x2.relaxed_nmadd + local.get 0 + local.get 1 + local.get 2 + f64x2.relaxed_nmadd + f64x2.eq + ) + (func (;7;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + local.get 2 + f64x2.relaxed_madd + local.get 0 + local.get 1 + local.get 2 + f64x2.relaxed_madd + f64x2.eq + ) + (export "f32x4.relaxed_madd" (func 0)) + (export "f32x4.relaxed_nmadd" (func 1)) + (export "f64x2.relaxed_nmadd" (func 2)) + (export "f64x2.relaxed_madd" (func 3)) + (export "f32x4.relaxed_madd_cmp" (func 4)) + (export "f32x4.relaxed_nmadd_cmp" (func 5)) + (export "f64x2.relaxed_nmadd_cmp" (func 6)) + (export "f64x2.relaxed_madd_cmp" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_min_max.wast/0.print b/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_min_max.wast/0.print new file mode 100644 index 0000000000..25efa2998b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/relaxed-simd/relaxed_min_max.wast/0.print @@ -0,0 +1,67 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.relaxed_min + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.relaxed_max + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.relaxed_min + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.relaxed_max + ) + (func (;4;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.relaxed_min + local.get 0 + local.get 1 + f32x4.relaxed_min + i32x4.eq + ) + (func (;5;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.relaxed_max + local.get 0 + local.get 1 + f32x4.relaxed_max + i32x4.eq + ) + (func (;6;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.relaxed_min + local.get 0 + local.get 1 + f64x2.relaxed_min + i64x2.eq + ) + (func (;7;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.relaxed_max + local.get 0 + local.get 1 + f64x2.relaxed_max + i64x2.eq + ) + (export "f32x4.relaxed_min" (func 0)) + (export "f32x4.relaxed_max" (func 1)) + (export "f64x2.relaxed_min" (func 2)) + (export "f64x2.relaxed_max" (func 3)) + (export "f32x4.relaxed_min_cmp" (func 4)) + (export "f32x4.relaxed_max_cmp" (func 5)) + (export "f64x2.relaxed_min_cmp" (func 6)) + (export "f64x2.relaxed_max_cmp" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/0.print b/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/0.print new file mode 100644 index 0000000000..8deaba4d9b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/0.print @@ -0,0 +1,167 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result i64))) + (type (;2;) (func (result f32))) + (type (;3;) (func (result f64))) + (type (;4;) (func (param i32) (result i32))) + (type (;5;) (func (param i64) (result i64))) + (type (;6;) (func (param f32) (result f32))) + (type (;7;) (func (param f64) (result f64))) + (type (;8;) (func (param f32 i32) (result i32))) + (type (;9;) (func (param i32 i64) (result i64))) + (type (;10;) (func (param f64 f32) (result f32))) + (type (;11;) (func (param i64 f64) (result f64))) + (type (;12;) (func (param i64 i64) (result i64))) + (type (;13;) (func (param i64) (result i32))) + (func $const-i32 (;0;) (type 0) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type 1) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type 2) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type 3) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type 4) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type 5) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type 6) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type 7) (param f64) (result f64) + local.get 0 + ) + (func $f32-i32 (;8;) (type 8) (param f32 i32) (result i32) + local.get 1 + ) + (func $i32-i64 (;9;) (type 9) (param i32 i64) (result i64) + local.get 1 + ) + (func $f64-f32 (;10;) (type 10) (param f64 f32) (result f32) + local.get 1 + ) + (func $i64-f64 (;11;) (type 11) (param i64 f64) (result f64) + local.get 1 + ) + (func (;12;) (type 0) (result i32) + return_call $const-i32 + ) + (func (;13;) (type 1) (result i64) + return_call $const-i64 + ) + (func (;14;) (type 2) (result f32) + return_call $const-f32 + ) + (func (;15;) (type 3) (result f64) + return_call $const-f64 + ) + (func (;16;) (type 0) (result i32) + i32.const 32 + return_call $id-i32 + ) + (func (;17;) (type 1) (result i64) + i64.const 64 + return_call $id-i64 + ) + (func (;18;) (type 2) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + return_call $id-f32 + ) + (func (;19;) (type 3) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + return_call $id-f64 + ) + (func (;20;) (type 0) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + return_call $f32-i32 + ) + (func (;21;) (type 1) (result i64) + i32.const 32 + i64.const 64 + return_call $i32-i64 + ) + (func (;22;) (type 2) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + return_call $f64-f32 + ) + (func (;23;) (type 3) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + return_call $i64-f64 + ) + (func $fac-acc (;24;) (type 12) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + return_call $fac-acc + end + ) + (func $count (;25;) (type 5) (param i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 0 + else + local.get 0 + i64.const 1 + i64.sub + return_call $count + end + ) + (func $even (;26;) (type 13) (param i64) (result i32) + local.get 0 + i64.eqz + if (result i32) ;; label = @1 + i32.const 44 + else + local.get 0 + i64.const 1 + i64.sub + return_call $odd + end + ) + (func $odd (;27;) (type 13) (param i64) (result i32) + local.get 0 + i64.eqz + if (result i32) ;; label = @1 + i32.const 99 + else + local.get 0 + i64.const 1 + i64.sub + return_call $even + end + ) + (export "type-i32" (func 12)) + (export "type-i64" (func 13)) + (export "type-f32" (func 14)) + (export "type-f64" (func 15)) + (export "type-first-i32" (func 16)) + (export "type-first-i64" (func 17)) + (export "type-first-f32" (func 18)) + (export "type-first-f64" (func 19)) + (export "type-second-i32" (func 20)) + (export "type-second-i64" (func 21)) + (export "type-second-f32" (func 22)) + (export "type-second-f64" (func 23)) + (export "fac-acc" (func $fac-acc)) + (export "count" (func $count)) + (export "even" (func $even)) + (export "odd" (func $odd)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/36.print b/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/36.print new file mode 100644 index 0000000000..cd55a24384 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/36.print @@ -0,0 +1,8 @@ +(module + (type (;0;) (func)) + (func $arity-1-vs-0 (;0;) (type 0) + i32.const 1 + return_call 1 + ) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/37.print b/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/37.print new file mode 100644 index 0000000000..d4be01c6e9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/tail-call/return_call.wast/37.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func $arity-2-vs-0 (;0;) (type 0) + f64.const 0x1p+1 (;=2;) + i32.const 1 + return_call 1 + ) + (func (;1;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/0.print b/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/0.print new file mode 100644 index 0000000000..c8356e64ea --- /dev/null +++ b/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/0.print @@ -0,0 +1,286 @@ +(module + (type $proc (;0;) (func)) + (type $out-i32 (;1;) (func (result i32))) + (type $out-i64 (;2;) (func (result i64))) + (type $out-f32 (;3;) (func (result f32))) + (type $out-f64 (;4;) (func (result f64))) + (type $over-i32 (;5;) (func (param i32) (result i32))) + (type $over-i64 (;6;) (func (param i64) (result i64))) + (type $over-f32 (;7;) (func (param f32) (result f32))) + (type $over-f64 (;8;) (func (param f64) (result f64))) + (type $f32-i32 (;9;) (func (param f32 i32) (result i32))) + (type $i32-i64 (;10;) (func (param i32 i64) (result i64))) + (type $f64-f32 (;11;) (func (param f64 f32) (result f32))) + (type $i64-f64 (;12;) (func (param i64 f64) (result f64))) + (type $over-i32-duplicate (;13;) (func (param i32) (result i32))) + (type $over-i64-duplicate (;14;) (func (param i64) (result i64))) + (type $over-f32-duplicate (;15;) (func (param f32) (result f32))) + (type $over-f64-duplicate (;16;) (func (param f64) (result f64))) + (type (;17;) (func (param i64))) + (type (;18;) (func (param i64 f64 i32 i64))) + (type (;19;) (func (param i64) (result i32))) + (type (;20;) (func (param i64 f64 i32 i64) (result i32))) + (type (;21;) (func (param i32) (result i64))) + (type (;22;) (func (param i64 i64) (result i64))) + (func $const-i32 (;0;) (type $out-i32) (result i32) + i32.const 306 + ) + (func $const-i64 (;1;) (type $out-i64) (result i64) + i64.const 356 + ) + (func $const-f32 (;2;) (type $out-f32) (result f32) + f32.const 0x1.e64p+11 (;=3890;) + ) + (func $const-f64 (;3;) (type $out-f64) (result f64) + f64.const 0x1.ec8p+11 (;=3940;) + ) + (func $id-i32 (;4;) (type $over-i32) (param i32) (result i32) + local.get 0 + ) + (func $id-i64 (;5;) (type $over-i64) (param i64) (result i64) + local.get 0 + ) + (func $id-f32 (;6;) (type $over-f32) (param f32) (result f32) + local.get 0 + ) + (func $id-f64 (;7;) (type $over-f64) (param f64) (result f64) + local.get 0 + ) + (func $i32-i64 (;8;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + ) + (func $i64-f64 (;9;) (type $i64-f64) (param i64 f64) (result f64) + local.get 1 + ) + (func $f32-i32 (;10;) (type $f32-i32) (param f32 i32) (result i32) + local.get 1 + ) + (func $f64-f32 (;11;) (type $f64-f32) (param f64 f32) (result f32) + local.get 1 + ) + (func $over-i32-duplicate (;12;) (type $over-i32-duplicate) (param i32) (result i32) + local.get 0 + ) + (func $over-i64-duplicate (;13;) (type $over-i64-duplicate) (param i64) (result i64) + local.get 0 + ) + (func $over-f32-duplicate (;14;) (type $over-f32-duplicate) (param f32) (result f32) + local.get 0 + ) + (func $over-f64-duplicate (;15;) (type $over-f64-duplicate) (param f64) (result f64) + local.get 0 + ) + (func (;16;) (type $proc) + i32.const 0 + return_call_indirect (type $proc) + i64.const 0 + i32.const 0 + return_call_indirect (type 17) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i32.const 0 + return_call_indirect (type 18) + i32.const 0 + return_call_indirect (type $proc) + ) + (func (;17;) (type $out-i32) (result i32) + i32.const 0 + return_call_indirect (type $out-i32) + i32.const 0 + return_call_indirect (type $out-i32) + i64.const 0 + i32.const 0 + return_call_indirect (type 19) + i64.const 0 + f64.const 0x0p+0 (;=0;) + i32.const 0 + i64.const 0 + i32.const 0 + return_call_indirect (type 20) + ) + (func (;18;) (type $out-i64) (result i64) + i64.const 0 + i32.const 0 + return_call_indirect (type $over-i64) + ) + (func (;19;) (type $out-i32) (result i32) + i32.const 0 + return_call_indirect (type $out-i32) + ) + (func (;20;) (type $out-i64) (result i64) + i32.const 1 + return_call_indirect (type $out-i64) + ) + (func (;21;) (type $out-f32) (result f32) + i32.const 2 + return_call_indirect (type $out-f32) + ) + (func (;22;) (type $out-f64) (result f64) + i32.const 3 + return_call_indirect (type $out-f64) + ) + (func (;23;) (type $out-i64) (result i64) + i64.const 100 + i32.const 5 + return_call_indirect (type $over-i64) + ) + (func (;24;) (type $out-i32) (result i32) + i32.const 32 + i32.const 4 + return_call_indirect (type $over-i32) + ) + (func (;25;) (type $out-i64) (result i64) + i64.const 64 + i32.const 5 + return_call_indirect (type $over-i64) + ) + (func (;26;) (type $out-f32) (result f32) + f32.const 0x1.51eb86p+0 (;=1.32;) + i32.const 6 + return_call_indirect (type $over-f32) + ) + (func (;27;) (type $out-f64) (result f64) + f64.const 0x1.a3d70a3d70a3dp+0 (;=1.64;) + i32.const 7 + return_call_indirect (type $over-f64) + ) + (func (;28;) (type $out-i32) (result i32) + f32.const 0x1.00ccccp+5 (;=32.1;) + i32.const 32 + i32.const 8 + return_call_indirect (type $f32-i32) + ) + (func (;29;) (type $out-i64) (result i64) + i32.const 32 + i64.const 64 + i32.const 9 + return_call_indirect (type $i32-i64) + ) + (func (;30;) (type $out-f32) (result f32) + f64.const 0x1p+6 (;=64;) + f32.const 0x1p+5 (;=32;) + i32.const 10 + return_call_indirect (type $f64-f32) + ) + (func (;31;) (type $out-f64) (result f64) + i64.const 64 + f64.const 0x1.0066666666666p+6 (;=64.1;) + i32.const 11 + return_call_indirect (type $i64-f64) + ) + (func (;32;) (type $i32-i64) (param i32 i64) (result i64) + local.get 1 + local.get 0 + return_call_indirect (type $over-i64) + ) + (func (;33;) (type 21) (param i32) (result i64) + i64.const 9 + local.get 0 + return_call_indirect (type $over-i64-duplicate) + ) + (func $tab-f1 (;34;) (type $out-i32) (result i32) + i32.const 307 + ) + (func $tab-f2 (;35;) (type $out-i32) (result i32) + i32.const 308 + ) + (func (;36;) (type $over-i32) (param $i i32) (result i32) + local.get $i + i32.const 0 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect (type $out-i32) + end + local.get $i + i32.const 1 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect $tab2 (type $out-i32) + end + local.get $i + i32.const 2 + i32.eq + if ;; label = @1 + i32.const 0 + return_call_indirect $tab3 (type $out-i32) + end + i32.const 0 + ) + (func $fac (;37;) (type $over-i64) (param i64) (result i64) + local.get 0 + i64.const 1 + i32.const 13 + return_call_indirect (type 22) + ) + (func $fac-acc (;38;) (type 22) (param i64 i64) (result i64) + local.get 0 + i64.eqz + if (result i64) ;; label = @1 + local.get 1 + else + local.get 0 + i64.const 1 + i64.sub + local.get 0 + local.get 1 + i64.mul + i32.const 13 + return_call_indirect (type 22) + end + ) + (func $even (;39;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 44 + else + local.get 0 + i32.const 1 + i32.sub + i32.const 15 + return_call_indirect (type $over-i32) + end + ) + (func $odd (;40;) (type $over-i32) (param i32) (result i32) + local.get 0 + i32.eqz + if (result i32) ;; label = @1 + i32.const 99 + else + local.get 0 + i32.const 1 + i32.sub + i32.const 14 + return_call_indirect (type $over-i32) + end + ) + (table (;0;) 20 20 funcref) + (table $tab2 (;1;) 1 1 funcref) + (table $tab3 (;2;) 1 1 funcref) + (export "type-i32" (func 19)) + (export "type-i64" (func 20)) + (export "type-f32" (func 21)) + (export "type-f64" (func 22)) + (export "type-index" (func 23)) + (export "type-first-i32" (func 24)) + (export "type-first-i64" (func 25)) + (export "type-first-f32" (func 26)) + (export "type-first-f64" (func 27)) + (export "type-second-i32" (func 28)) + (export "type-second-i64" (func 29)) + (export "type-second-f32" (func 30)) + (export "type-second-f64" (func 31)) + (export "dispatch" (func 32)) + (export "dispatch-structural" (func 33)) + (export "call-tab" (func 36)) + (export "fac" (func $fac)) + (export "even" (func $even)) + (export "odd" (func $odd)) + (elem (;0;) (i32.const 0) 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 $fac $fac-acc $even $odd $over-i32-duplicate $over-i64-duplicate $over-f32-duplicate $over-f64-duplicate) + (elem (;1;) (table $tab2) (i32.const 0) func $tab-f1) + (elem (;2;) (table $tab3) (i32.const 0) func $tab-f2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/64.print b/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/64.print new file mode 100644 index 0000000000..21d17b3e23 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/64.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func $arity-1-vs-0 (;0;) (type 0) + i32.const 1 + i32.const 0 + return_call_indirect (type 0) + ) + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/65.print b/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/65.print new file mode 100644 index 0000000000..c1f5719022 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/tail-call/return_call_indirect.wast/65.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func $arity-2-vs-0 (;0;) (type 0) + f64.const 0x1p+1 (;=2;) + i32.const 1 + i32.const 0 + return_call_indirect (type 0) + ) + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/atomic.wast/0.print b/tests/snapshots/testsuite/proposals/threads/atomic.wast/0.print new file mode 100644 index 0000000000..7663c13db5 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/atomic.wast/0.print @@ -0,0 +1,396 @@ +(module + (type (;0;) (func (param i64))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32) (result i64))) + (type (;3;) (func (param i32 i32))) + (type (;4;) (func (param i32 i64))) + (type (;5;) (func (param i32 i32) (result i32))) + (type (;6;) (func (param i32 i64) (result i64))) + (type (;7;) (func (param i32 i32 i32) (result i32))) + (type (;8;) (func (param i32 i64 i64) (result i64))) + (func (;0;) (type 0) (param $value i64) + i32.const 0 + local.get $value + i64.store + ) + (func (;1;) (type 1) (param $addr i32) (result i32) + local.get $addr + i32.atomic.load + ) + (func (;2;) (type 2) (param $addr i32) (result i64) + local.get $addr + i64.atomic.load + ) + (func (;3;) (type 1) (param $addr i32) (result i32) + local.get $addr + i32.atomic.load8_u + ) + (func (;4;) (type 1) (param $addr i32) (result i32) + local.get $addr + i32.atomic.load16_u + ) + (func (;5;) (type 2) (param $addr i32) (result i64) + local.get $addr + i64.atomic.load8_u + ) + (func (;6;) (type 2) (param $addr i32) (result i64) + local.get $addr + i64.atomic.load16_u + ) + (func (;7;) (type 2) (param $addr i32) (result i64) + local.get $addr + i64.atomic.load32_u + ) + (func (;8;) (type 3) (param $addr i32) (param $value i32) + local.get $addr + local.get $value + i32.atomic.store + ) + (func (;9;) (type 4) (param $addr i32) (param $value i64) + local.get $addr + local.get $value + i64.atomic.store + ) + (func (;10;) (type 3) (param $addr i32) (param $value i32) + local.get $addr + local.get $value + i32.atomic.store8 + ) + (func (;11;) (type 3) (param $addr i32) (param $value i32) + local.get $addr + local.get $value + i32.atomic.store16 + ) + (func (;12;) (type 4) (param $addr i32) (param $value i64) + local.get $addr + local.get $value + i64.atomic.store8 + ) + (func (;13;) (type 4) (param $addr i32) (param $value i64) + local.get $addr + local.get $value + i64.atomic.store16 + ) + (func (;14;) (type 4) (param $addr i32) (param $value i64) + local.get $addr + local.get $value + i64.atomic.store32 + ) + (func (;15;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw.add + ) + (func (;16;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw.add + ) + (func (;17;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw8.add_u + ) + (func (;18;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw16.add_u + ) + (func (;19;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw8.add_u + ) + (func (;20;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw16.add_u + ) + (func (;21;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw32.add_u + ) + (func (;22;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw.sub + ) + (func (;23;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw.sub + ) + (func (;24;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw8.sub_u + ) + (func (;25;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw16.sub_u + ) + (func (;26;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw8.sub_u + ) + (func (;27;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw16.sub_u + ) + (func (;28;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw32.sub_u + ) + (func (;29;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw.and + ) + (func (;30;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw.and + ) + (func (;31;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw8.and_u + ) + (func (;32;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw16.and_u + ) + (func (;33;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw8.and_u + ) + (func (;34;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw16.and_u + ) + (func (;35;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw32.and_u + ) + (func (;36;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw.or + ) + (func (;37;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw.or + ) + (func (;38;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw8.or_u + ) + (func (;39;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw16.or_u + ) + (func (;40;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw8.or_u + ) + (func (;41;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw16.or_u + ) + (func (;42;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw32.or_u + ) + (func (;43;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw.xor + ) + (func (;44;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw.xor + ) + (func (;45;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw8.xor_u + ) + (func (;46;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw16.xor_u + ) + (func (;47;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw8.xor_u + ) + (func (;48;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw16.xor_u + ) + (func (;49;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw32.xor_u + ) + (func (;50;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw.xchg + ) + (func (;51;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw.xchg + ) + (func (;52;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw8.xchg_u + ) + (func (;53;) (type 5) (param $addr i32) (param $value i32) (result i32) + local.get $addr + local.get $value + i32.atomic.rmw16.xchg_u + ) + (func (;54;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw8.xchg_u + ) + (func (;55;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw16.xchg_u + ) + (func (;56;) (type 6) (param $addr i32) (param $value i64) (result i64) + local.get $addr + local.get $value + i64.atomic.rmw32.xchg_u + ) + (func (;57;) (type 7) (param $addr i32) (param $expected i32) (param $value i32) (result i32) + local.get $addr + local.get $expected + local.get $value + i32.atomic.rmw.cmpxchg + ) + (func (;58;) (type 8) (param $addr i32) (param $expected i64) (param $value i64) (result i64) + local.get $addr + local.get $expected + local.get $value + i64.atomic.rmw.cmpxchg + ) + (func (;59;) (type 7) (param $addr i32) (param $expected i32) (param $value i32) (result i32) + local.get $addr + local.get $expected + local.get $value + i32.atomic.rmw8.cmpxchg_u + ) + (func (;60;) (type 7) (param $addr i32) (param $expected i32) (param $value i32) (result i32) + local.get $addr + local.get $expected + local.get $value + i32.atomic.rmw16.cmpxchg_u + ) + (func (;61;) (type 8) (param $addr i32) (param $expected i64) (param $value i64) (result i64) + local.get $addr + local.get $expected + local.get $value + i64.atomic.rmw8.cmpxchg_u + ) + (func (;62;) (type 8) (param $addr i32) (param $expected i64) (param $value i64) (result i64) + local.get $addr + local.get $expected + local.get $value + i64.atomic.rmw16.cmpxchg_u + ) + (func (;63;) (type 8) (param $addr i32) (param $expected i64) (param $value i64) (result i64) + local.get $addr + local.get $expected + local.get $value + i64.atomic.rmw32.cmpxchg_u + ) + (memory (;0;) 1 1 shared) + (export "init" (func 0)) + (export "i32.atomic.load" (func 1)) + (export "i64.atomic.load" (func 2)) + (export "i32.atomic.load8_u" (func 3)) + (export "i32.atomic.load16_u" (func 4)) + (export "i64.atomic.load8_u" (func 5)) + (export "i64.atomic.load16_u" (func 6)) + (export "i64.atomic.load32_u" (func 7)) + (export "i32.atomic.store" (func 8)) + (export "i64.atomic.store" (func 9)) + (export "i32.atomic.store8" (func 10)) + (export "i32.atomic.store16" (func 11)) + (export "i64.atomic.store8" (func 12)) + (export "i64.atomic.store16" (func 13)) + (export "i64.atomic.store32" (func 14)) + (export "i32.atomic.rmw.add" (func 15)) + (export "i64.atomic.rmw.add" (func 16)) + (export "i32.atomic.rmw8.add_u" (func 17)) + (export "i32.atomic.rmw16.add_u" (func 18)) + (export "i64.atomic.rmw8.add_u" (func 19)) + (export "i64.atomic.rmw16.add_u" (func 20)) + (export "i64.atomic.rmw32.add_u" (func 21)) + (export "i32.atomic.rmw.sub" (func 22)) + (export "i64.atomic.rmw.sub" (func 23)) + (export "i32.atomic.rmw8.sub_u" (func 24)) + (export "i32.atomic.rmw16.sub_u" (func 25)) + (export "i64.atomic.rmw8.sub_u" (func 26)) + (export "i64.atomic.rmw16.sub_u" (func 27)) + (export "i64.atomic.rmw32.sub_u" (func 28)) + (export "i32.atomic.rmw.and" (func 29)) + (export "i64.atomic.rmw.and" (func 30)) + (export "i32.atomic.rmw8.and_u" (func 31)) + (export "i32.atomic.rmw16.and_u" (func 32)) + (export "i64.atomic.rmw8.and_u" (func 33)) + (export "i64.atomic.rmw16.and_u" (func 34)) + (export "i64.atomic.rmw32.and_u" (func 35)) + (export "i32.atomic.rmw.or" (func 36)) + (export "i64.atomic.rmw.or" (func 37)) + (export "i32.atomic.rmw8.or_u" (func 38)) + (export "i32.atomic.rmw16.or_u" (func 39)) + (export "i64.atomic.rmw8.or_u" (func 40)) + (export "i64.atomic.rmw16.or_u" (func 41)) + (export "i64.atomic.rmw32.or_u" (func 42)) + (export "i32.atomic.rmw.xor" (func 43)) + (export "i64.atomic.rmw.xor" (func 44)) + (export "i32.atomic.rmw8.xor_u" (func 45)) + (export "i32.atomic.rmw16.xor_u" (func 46)) + (export "i64.atomic.rmw8.xor_u" (func 47)) + (export "i64.atomic.rmw16.xor_u" (func 48)) + (export "i64.atomic.rmw32.xor_u" (func 49)) + (export "i32.atomic.rmw.xchg" (func 50)) + (export "i64.atomic.rmw.xchg" (func 51)) + (export "i32.atomic.rmw8.xchg_u" (func 52)) + (export "i32.atomic.rmw16.xchg_u" (func 53)) + (export "i64.atomic.rmw8.xchg_u" (func 54)) + (export "i64.atomic.rmw16.xchg_u" (func 55)) + (export "i64.atomic.rmw32.xchg_u" (func 56)) + (export "i32.atomic.rmw.cmpxchg" (func 57)) + (export "i64.atomic.rmw.cmpxchg" (func 58)) + (export "i32.atomic.rmw8.cmpxchg_u" (func 59)) + (export "i32.atomic.rmw16.cmpxchg_u" (func 60)) + (export "i64.atomic.rmw8.cmpxchg_u" (func 61)) + (export "i64.atomic.rmw16.cmpxchg_u" (func 62)) + (export "i64.atomic.rmw32.cmpxchg_u" (func 63)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/atomic.wast/243.print b/tests/snapshots/testsuite/proposals/threads/atomic.wast/243.print new file mode 100644 index 0000000000..f36887b8b7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/atomic.wast/243.print @@ -0,0 +1,33 @@ +(module + (type (;0;) (func (param i64))) + (type (;1;) (func (param i32 i32) (result i32))) + (type (;2;) (func (param i32 i32 i64) (result i32))) + (type (;3;) (func (param i32 i64 i64) (result i32))) + (func (;0;) (type 0) (param $value i64) + i32.const 0 + local.get $value + i64.store + ) + (func (;1;) (type 1) (param $addr i32) (param $count i32) (result i32) + local.get $addr + local.get $count + memory.atomic.notify + ) + (func (;2;) (type 2) (param $addr i32) (param $expected i32) (param $timeout i64) (result i32) + local.get $addr + local.get $expected + local.get $timeout + memory.atomic.wait32 + ) + (func (;3;) (type 3) (param $addr i32) (param $expected i64) (param $timeout i64) (result i32) + local.get $addr + local.get $expected + local.get $timeout + memory.atomic.wait64 + ) + (memory (;0;) 1 1 shared) + (export "init" (func 0)) + (export "memory.atomic.notify" (func 1)) + (export "memory.atomic.wait32" (func 2)) + (export "memory.atomic.wait64" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/atomic.wast/248.print b/tests/snapshots/testsuite/proposals/threads/atomic.wast/248.print new file mode 100644 index 0000000000..205fc7e823 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/atomic.wast/248.print @@ -0,0 +1,289 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.const 0 + memory.atomic.notify + drop + ) + (func (;1;) (type 0) + i32.const 0 + i32.const 0 + i64.const 0 + memory.atomic.wait32 + drop + ) + (func (;2;) (type 0) + i32.const 0 + i64.const 0 + i64.const 0 + memory.atomic.wait64 + drop + ) + (func (;3;) (type 0) + i32.const 0 + i32.atomic.load + drop + ) + (func (;4;) (type 0) + i32.const 0 + i64.atomic.load + drop + ) + (func (;5;) (type 0) + i32.const 0 + i32.atomic.load16_u + drop + ) + (func (;6;) (type 0) + i32.const 0 + i64.atomic.load16_u + drop + ) + (func (;7;) (type 0) + i32.const 0 + i64.atomic.load32_u + drop + ) + (func (;8;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.store + ) + (func (;9;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.store + ) + (func (;10;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.store16 + ) + (func (;11;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.store16 + ) + (func (;12;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.store32 + ) + (func (;13;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw.add + drop + ) + (func (;14;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw.add + drop + ) + (func (;15;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw16.add_u + drop + ) + (func (;16;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw16.add_u + drop + ) + (func (;17;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw32.add_u + drop + ) + (func (;18;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw.sub + drop + ) + (func (;19;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw.sub + drop + ) + (func (;20;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw16.sub_u + drop + ) + (func (;21;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw16.sub_u + drop + ) + (func (;22;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw32.sub_u + drop + ) + (func (;23;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw.and + drop + ) + (func (;24;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw.and + drop + ) + (func (;25;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw16.and_u + drop + ) + (func (;26;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw16.and_u + drop + ) + (func (;27;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw32.and_u + drop + ) + (func (;28;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw.or + drop + ) + (func (;29;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw.or + drop + ) + (func (;30;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw16.or_u + drop + ) + (func (;31;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw16.or_u + drop + ) + (func (;32;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw32.or_u + drop + ) + (func (;33;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw.xor + drop + ) + (func (;34;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw.xor + drop + ) + (func (;35;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw16.xor_u + drop + ) + (func (;36;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw16.xor_u + drop + ) + (func (;37;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw32.xor_u + drop + ) + (func (;38;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw.xchg + drop + ) + (func (;39;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw.xchg + drop + ) + (func (;40;) (type 0) + i32.const 0 + i32.const 0 + i32.atomic.rmw16.xchg_u + drop + ) + (func (;41;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw16.xchg_u + drop + ) + (func (;42;) (type 0) + i32.const 0 + i64.const 0 + i64.atomic.rmw32.xchg_u + drop + ) + (func (;43;) (type 0) + i32.const 0 + i32.const 0 + i32.const 0 + i32.atomic.rmw.cmpxchg + drop + ) + (func (;44;) (type 0) + i32.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw.cmpxchg + drop + ) + (func (;45;) (type 0) + i32.const 0 + i32.const 0 + i32.const 0 + i32.atomic.rmw16.cmpxchg_u + drop + ) + (func (;46;) (type 0) + i32.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw16.cmpxchg_u + drop + ) + (func (;47;) (type 0) + i32.const 0 + i64.const 0 + i64.const 0 + i64.atomic.rmw32.cmpxchg_u + drop + ) + (memory (;0;) 1 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/0.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/0.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/0.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/1.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/1.print new file mode 100644 index 0000000000..e7a58f9dc9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/1.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) + (export "b" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/10.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/10.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/10.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/11.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/11.print new file mode 100644 index 0000000000..c34519993c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/11.print @@ -0,0 +1,10 @@ +(module $Func + (type (;0;) (func (param i32) (result i32))) + (func $f (;0;) (type 0) (param $n i32) (result i32) + local.get $n + i32.const 1 + i32.add + return + ) + (export "e" (func $f)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/14.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/14.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/14.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/15.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/15.print new file mode 100644 index 0000000000..5d29297e1f --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/15.print @@ -0,0 +1 @@ +(module $Other1) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/2.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/2.print new file mode 100644 index 0000000000..92bc234966 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/2.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (func (;1;) (type 0)) + (export "a" (func 0)) + (export "b" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/23.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/23.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/23.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/24.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/24.print new file mode 100644 index 0000000000..cb29da92eb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/24.print @@ -0,0 +1,5 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) + (export "b" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/25.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/25.print new file mode 100644 index 0000000000..ce572cc593 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/25.print @@ -0,0 +1,6 @@ +(module + (global (;0;) i32 i32.const 0) + (global (;1;) i32 i32.const 0) + (export "a" (global 0)) + (export "b" (global 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/26.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/26.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/26.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/27.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/27.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/27.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/28.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/28.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/28.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/29.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/29.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/29.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/3.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/3.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/3.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/30.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/30.print new file mode 100644 index 0000000000..50555c846d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/30.print @@ -0,0 +1,4 @@ +(module + (global (;0;) i32 i32.const 0) + (export "a" (global 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/31.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/31.print new file mode 100644 index 0000000000..02ac823f65 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/31.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) i32 i32.const 0) + (export "a" (global $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/32.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/32.print new file mode 100644 index 0000000000..ce0c9c5233 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/32.print @@ -0,0 +1,4 @@ +(module $Global + (global $g (;0;) i32 i32.const 42) + (export "e" (global $g)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/35.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/35.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/35.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/36.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/36.print new file mode 100644 index 0000000000..95a91d8cad --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/36.print @@ -0,0 +1 @@ +(module $Other2) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/4.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/4.print new file mode 100644 index 0000000000..1e92fbc9f7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/4.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) + (export "b" (func 0)) + (export "c" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/44.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/44.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/44.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/45.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/45.print new file mode 100644 index 0000000000..eadf450224 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/45.print @@ -0,0 +1,5 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) + (export "b" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/46.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/46.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/46.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/47.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/47.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/47.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/48.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/48.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/48.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/49.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/49.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/49.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/5.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/5.print new file mode 100644 index 0000000000..786bbc30b4 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/5.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param i32)) + (export "a" (func 0)) + (export "b" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/50.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/50.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/50.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/51.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/51.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/51.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/52.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/52.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/52.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/53.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/53.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/53.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/54.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/54.print new file mode 100644 index 0000000000..1942c290db --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/54.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/55.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/55.print new file mode 100644 index 0000000000..331b629377 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/55.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 1 funcref) + (export "a" (table 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/56.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/56.print new file mode 100644 index 0000000000..ccf821ad75 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/56.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/57.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/57.print new file mode 100644 index 0000000000..33bd4eff33 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/57.print @@ -0,0 +1,4 @@ +(module + (table $a (;0;) 0 1 funcref) + (export "a" (table $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/6.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/6.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/6.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/63.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/63.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/63.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/64.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/64.print new file mode 100644 index 0000000000..277573bf82 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/64.print @@ -0,0 +1,5 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) + (export "b" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/65.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/65.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/65.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/66.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/66.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/66.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/67.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/67.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/67.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/68.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/68.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/68.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/69.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/69.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/69.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/7.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/7.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/7.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/70.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/70.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/70.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/71.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/71.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/71.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/72.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/72.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/72.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/73.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/73.print new file mode 100644 index 0000000000..b2f4c11c7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/73.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/74.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/74.print new file mode 100644 index 0000000000..bb03c3a505 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/74.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/75.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/75.print new file mode 100644 index 0000000000..9bef12a108 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/75.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/76.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/76.print new file mode 100644 index 0000000000..edfb22a9cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/76.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/77.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/77.print new file mode 100644 index 0000000000..ed2dcf15ad --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/77.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1 shared) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/78.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/78.print new file mode 100644 index 0000000000..ed2dcf15ad --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/78.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1 shared) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/79.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/79.print new file mode 100644 index 0000000000..a6d28ece4c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/79.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1 shared) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/8.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/8.print new file mode 100644 index 0000000000..641a5936be --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/8.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func $a (;0;) (type 0)) + (export "a" (func $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/80.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/80.print new file mode 100644 index 0000000000..a6d28ece4c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/80.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1 shared) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/81.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/81.print new file mode 100644 index 0000000000..ed2dcf15ad --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/81.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 0 1 shared) + (export "a" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/82.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/82.print new file mode 100644 index 0000000000..a6d28ece4c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/82.print @@ -0,0 +1,4 @@ +(module + (memory $a (;0;) 0 1 shared) + (export "a" (memory $a)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/exports.wast/9.print b/tests/snapshots/testsuite/proposals/threads/exports.wast/9.print new file mode 100644 index 0000000000..9223d48871 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/exports.wast/9.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (export "a" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/0.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/0.print new file mode 100644 index 0000000000..43a044b36a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/0.print @@ -0,0 +1,39 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (result i32))) + (type (;4;) (func (result f32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i64) (result i64))) + (func (;0;) (type 0)) + (func (;1;) (type 1) (param i32)) + (func (;2;) (type 2) (param f32)) + (func (;3;) (type 3) (result i32) + i32.const 22 + ) + (func (;4;) (type 4) (result f32) + f32.const 0x1.6p+3 (;=11;) + ) + (func (;5;) (type 5) (param i32) (result i32) + local.get 0 + ) + (func (;6;) (type 6) (param i64) (result i64) + local.get 0 + ) + (table (;0;) 10 funcref) + (memory (;0;) 2) + (global (;0;) i32 i32.const 55) + (global (;1;) f32 f32.const 0x1.6p+5 (;=44;)) + (export "func" (func 0)) + (export "func-i32" (func 1)) + (export "func-f32" (func 2)) + (export "func->i32" (func 3)) + (export "func->f32" (func 4)) + (export "func-i32->i32" (func 5)) + (export "func-i64->i64" (func 6)) + (export "global-i32" (global 0)) + (export "global-f32" (global 1)) + (export "table-10-inf" (table 0)) + (export "memory-2-inf" (memory 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/10.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/10.print new file mode 100644 index 0000000000..3b07b2a04c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/10.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (result f32))) + (import "test" "func->f32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/101.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/101.print new file mode 100644 index 0000000000..1aad2d0f8d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/101.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/102.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/102.print new file mode 100644 index 0000000000..546d8eaedc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/102.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/103.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/103.print new file mode 100644 index 0000000000..e40926e430 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/103.print @@ -0,0 +1,3 @@ +(module + (import "test" "memory-2-inf" (memory (;0;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/104.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/104.print new file mode 100644 index 0000000000..3c97146026 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/104.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/105.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/105.print new file mode 100644 index 0000000000..83efcab834 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/105.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/106.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/106.print new file mode 100644 index 0000000000..404698c724 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/106.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/107.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/107.print new file mode 100644 index 0000000000..39db875587 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/107.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/108.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/108.print new file mode 100644 index 0000000000..897e9b716b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/108.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 1 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/109.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/109.print new file mode 100644 index 0000000000..c0d28c6be7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/109.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "memory" (memory (;0;) 0 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/11.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/11.print new file mode 100644 index 0000000000..e6ddafe344 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/11.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "test" "func-i32->i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/12.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/12.print new file mode 100644 index 0000000000..c5ca6af197 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/12.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (import "test" "func-i64->i64" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/124.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/124.print new file mode 100644 index 0000000000..73ee1fb50c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/124.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 0 3)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + memory.grow + ) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/130.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/130.print new file mode 100644 index 0000000000..945fa987f6 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/130.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "shared_memory" (memory (;0;) 1 2 shared)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/149.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/149.print new file mode 100644 index 0000000000..800bef5a32 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/149.print @@ -0,0 +1 @@ +(module) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/2.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/2.print new file mode 100644 index 0000000000..44e3618519 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/2.print @@ -0,0 +1,77 @@ +(module + (type $func_i32 (;0;) (func (param i32))) + (type $func_i64 (;1;) (func (param i64))) + (type $func_f32 (;2;) (func (param f32))) + (type $func_f64 (;3;) (func (param f64))) + (type $forward (;4;) (func (param i32))) + (type (;5;) (func (param i32 f32))) + (type (;6;) (func (param f64 f64))) + (type (;7;) (func (param i64) (result i64))) + (import "spectest" "print_i32" (func (;0;) (type $func_i32))) + (import "spectest" "print_i32" (func $print_i32 (;1;) (type $func_i32))) + (import "spectest" "print_f32" (func $print_f32 (;2;) (type $func_f32))) + (import "spectest" "print_f64" (func $print_f64 (;3;) (type $func_f64))) + (import "spectest" "print_i32_f32" (func $print_i32_f32 (;4;) (type 5))) + (import "spectest" "print_f64_f64" (func $print_f64_f64 (;5;) (type 6))) + (import "spectest" "print_i32" (func $print_i32-2 (;6;) (type $func_i32))) + (import "spectest" "print_f64" (func $print_f64-2 (;7;) (type $func_f64))) + (import "test" "func-i64->i64" (func $i64->i64 (;8;) (type 7))) + (import "spectest" "print_i32" (func (;9;) (type $func_i32))) + (import "spectest" "print_i32" (func $p (;10;) (type $func_i32))) + (import "spectest" "print_i32" (func (;11;) (type $func_i32))) + (import "spectest" "print_i32" (func (;12;) (type $func_i32))) + (import "spectest" "print_i32" (func (;13;) (type $func_i32))) + (import "spectest" "print_i32" (func (;14;) (type $forward))) + (import "spectest" "print_i32" (func (;15;) (type $forward))) + (func (;16;) (type $func_i32) (param $i i32) + (local $x f32) + local.get $i + f32.convert_i32_s + local.set $x + local.get $i + call 0 + local.get $i + i32.const 1 + i32.add + f32.const 0x1.5p+5 (;=42;) + call $print_i32_f32 + local.get $i + call $print_i32 + local.get $i + call $print_i32-2 + local.get $x + call $print_f32 + local.get $i + i32.const 0 + call_indirect (type $func_i32) + ) + (func (;17;) (type $func_i64) (param $i i64) + (local $x f64) + local.get $i + call $i64->i64 + f64.convert_i64_s + local.set $x + local.get $x + f64.const 0x1p+0 (;=1;) + f64.add + f64.const 0x1.a8p+5 (;=53;) + call $print_f64_f64 + local.get $x + call $print_f64 + local.get $x + call $print_f64-2 + local.get $x + i32.const 1 + call_indirect (type $func_f64) + ) + (table (;0;) 2 2 funcref) + (export "p1" (func 9)) + (export "p2" (func $p)) + (export "p3" (func 11)) + (export "p4" (func 11)) + (export "p5" (func 12)) + (export "p6" (func 13)) + (export "print32" (func 16)) + (export "print64" (func 17)) + (elem (;0;) (i32.const 0) func $print_i32 $print_f64) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/37.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/37.print new file mode 100644 index 0000000000..c9952e5b29 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/37.print @@ -0,0 +1,25 @@ +(module + (type (;0;) (func (result i32))) + (import "spectest" "global_i32" (global (;0;) i32)) + (import "spectest" "global_i32" (global (;1;) i32)) + (import "spectest" "global_i32" (global $x (;2;) i32)) + (import "spectest" "global_i32" (global $y (;3;) i32)) + (import "spectest" "global_f32" (global (;4;) f32)) + (import "spectest" "global_f64" (global (;5;) f64)) + (func (;0;) (type 0) (result i32) + global.get 0 + ) + (func (;1;) (type 0) (result i32) + global.get 1 + ) + (func (;2;) (type 0) (result i32) + global.get $x + ) + (func (;3;) (type 0) (result i32) + global.get $y + ) + (export "get-0" (func 0)) + (export "get-1" (func 1)) + (export "get-x" (func 2)) + (export "get-y" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/42.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/42.print new file mode 100644 index 0000000000..1b1739a096 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/42.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-i32" (global (;0;) i32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/43.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/43.print new file mode 100644 index 0000000000..eae7b7643b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/43.print @@ -0,0 +1,3 @@ +(module + (import "test" "global-f32" (global (;0;) f32)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/52.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/52.print new file mode 100644 index 0000000000..d4c6d1994b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/52.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "spectest" "table" (table (;0;) 10 20 funcref)) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func $f (;1;) (type 0) (result i32) + i32.const 11 + ) + (func $g (;2;) (type 0) (result i32) + i32.const 22 + ) + (export "call" (func 0)) + (elem (;0;) (i32.const 1) func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/58.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/58.print new file mode 100644 index 0000000000..d4c6d1994b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/58.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (import "spectest" "table" (table (;0;) 10 20 funcref)) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func $f (;1;) (type 0) (result i32) + i32.const 11 + ) + (func $g (;2;) (type 0) (result i32) + i32.const 22 + ) + (export "call" (func 0)) + (elem (;0;) (i32.const 1) func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/6.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/6.print new file mode 100644 index 0000000000..22a02a9053 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/6.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (import "test" "func" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/67.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/67.print new file mode 100644 index 0000000000..72f38c2e80 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/67.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/68.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/68.print new file mode 100644 index 0000000000..475c251b6e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/68.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/69.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/69.print new file mode 100644 index 0000000000..c8997038cb --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/69.print @@ -0,0 +1,3 @@ +(module + (import "test" "table-10-inf" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/7.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/7.print new file mode 100644 index 0000000000..782997f244 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/7.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param i32))) + (import "test" "func-i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/70.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/70.print new file mode 100644 index 0000000000..64a52acf28 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/70.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/71.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/71.print new file mode 100644 index 0000000000..218d7d9bdc --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/71.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/72.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/72.print new file mode 100644 index 0000000000..2a0fa834a7 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/72.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/73.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/73.print new file mode 100644 index 0000000000..03446a5f52 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/73.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/74.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/74.print new file mode 100644 index 0000000000..d1cff0037a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/74.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/75.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/75.print new file mode 100644 index 0000000000..65ae983998 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/75.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 0 20 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/76.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/76.print new file mode 100644 index 0000000000..9c95837f51 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/76.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 10 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/77.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/77.print new file mode 100644 index 0000000000..45fc077841 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/77.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table" (table (;0;) 5 25 funcref)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/8.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/8.print new file mode 100644 index 0000000000..ace1d7c959 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/8.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (param f32))) + (import "test" "func-f32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/88.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/88.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/88.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/9.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/9.print new file mode 100644 index 0000000000..0744a46fba --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/9.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func (result i32))) + (import "test" "func->i32" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/imports.wast/93.print b/tests/snapshots/testsuite/proposals/threads/imports.wast/93.print new file mode 100644 index 0000000000..be2875100b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/imports.wast/93.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (import "spectest" "memory" (memory (;0;) 1 2)) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i32.load + ) + (export "load" (func 0)) + (data (;0;) (i32.const 10) "\10") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/0.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/0.print new file mode 100644 index 0000000000..36938759b9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/0.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/1.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/1.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/1.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/11.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/11.print new file mode 100644 index 0000000000..0cdda46d31 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/11.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0 0) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/13.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/13.print new file mode 100644 index 0000000000..0cdda46d31 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/13.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 0 0) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/15.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/15.print new file mode 100644 index 0000000000..94e698954c --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/15.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + memory.size + ) + (memory (;0;) 1 1) + (export "memsize" (func 0)) + (data (;0;) (i32.const 0) "x") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/2.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/2.print new file mode 100644 index 0000000000..d76aa6a0fa --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/2.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/3.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/3.print new file mode 100644 index 0000000000..0f5c3ea229 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/3.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/36.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/36.print new file mode 100644 index 0000000000..1dc6026a7b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/36.print @@ -0,0 +1,154 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result f64))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i64) (result i64))) + (func (;0;) (type 0) (result i32) + i32.const 0 + i32.load8_u + i32.const 65 + i32.eq + i32.const 3 + i32.load8_u + i32.const 167 + i32.eq + i32.and + i32.const 6 + i32.load8_u + i32.const 0 + i32.eq + i32.const 19 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.const 20 + i32.load8_u + i32.const 87 + i32.eq + i32.const 23 + i32.load8_u + i32.const 77 + i32.eq + i32.and + i32.const 24 + i32.load8_u + i32.const 0 + i32.eq + i32.const 1023 + i32.load8_u + i32.const 0 + i32.eq + i32.and + i32.and + i32.and + ) + (func (;1;) (type 1) (result f64) + i32.const 8 + i64.const -12345 + i64.store + i32.const 8 + f64.load + i64.const -12345 + f64.reinterpret_i64 + f64.eq + if ;; label = @1 + f64.const 0x0p+0 (;=0;) + return + end + i32.const 9 + i64.const 0 + i64.store align=1 + i32.const 15 + i32.const 16453 + i32.store16 align=1 + i32.const 9 + f64.load align=1 + ) + (func (;2;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store8 + i32.const 8 + i32.load8_s + ) + (func (;3;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store8 + i32.const 8 + i32.load8_u + ) + (func (;4;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store16 + i32.const 8 + i32.load16_s + ) + (func (;5;) (type 2) (param $i i32) (result i32) + i32.const 8 + local.get $i + i32.store16 + i32.const 8 + i32.load16_u + ) + (func (;6;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store8 + i32.const 8 + i64.load8_s + ) + (func (;7;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store8 + i32.const 8 + i64.load8_u + ) + (func (;8;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store16 + i32.const 8 + i64.load16_s + ) + (func (;9;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store16 + i32.const 8 + i64.load16_u + ) + (func (;10;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store32 + i32.const 8 + i64.load32_s + ) + (func (;11;) (type 3) (param $i i64) (result i64) + i32.const 8 + local.get $i + i64.store32 + i32.const 8 + i64.load32_u + ) + (memory (;0;) 1) + (export "data" (func 0)) + (export "cast" (func 1)) + (export "i32_load8_s" (func 2)) + (export "i32_load8_u" (func 3)) + (export "i32_load16_s" (func 4)) + (export "i32_load16_u" (func 5)) + (export "i64_load8_s" (func 6)) + (export "i64_load8_u" (func 7)) + (export "i64_load16_s" (func 8)) + (export "i64_load16_u" (func 9)) + (export "i64_load32_s" (func 10)) + (export "i64_load32_u" (func 11)) + (data (;0;) (i32.const 0) "ABC\a7D") + (data (;1;) (i32.const 20) "WASM") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/4.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/4.print new file mode 100644 index 0000000000..d280c1e33b --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/4.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1 256) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/5.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/5.print new file mode 100644 index 0000000000..21d5f6b5c9 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/5.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 65536) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/6.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/6.print new file mode 100644 index 0000000000..a22945d848 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/6.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 0 0 shared) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/threads/memory.wast/7.print b/tests/snapshots/testsuite/proposals/threads/memory.wast/7.print new file mode 100644 index 0000000000..4aca8bf57e --- /dev/null +++ b/tests/snapshots/testsuite/proposals/threads/memory.wast/7.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1 2 shared) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/ref_func.wast/0.print b/tests/snapshots/testsuite/ref_func.wast/0.print new file mode 100644 index 0000000000..acffc25333 --- /dev/null +++ b/tests/snapshots/testsuite/ref_func.wast/0.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param $x i32) (result i32) + local.get $x + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/ref_func.wast/14.print b/tests/snapshots/testsuite/ref_func.wast/14.print new file mode 100644 index 0000000000..c509cd9ecf --- /dev/null +++ b/tests/snapshots/testsuite/ref_func.wast/14.print @@ -0,0 +1,25 @@ +(module + (type (;0;) (func)) + (func $f1 (;0;) (type 0)) + (func $f2 (;1;) (type 0)) + (func $f3 (;2;) (type 0)) + (func $f4 (;3;) (type 0)) + (func $f5 (;4;) (type 0)) + (func $f6 (;5;) (type 0)) + (func (;6;) (type 0) + ref.func $f1 + ref.func $f2 + ref.func $f3 + ref.func $f4 + ref.func $f5 + ref.func $f6 + return + ) + (table $t (;0;) 1 funcref) + (global (;0;) funcref ref.func $f1) + (export "f" (func $f2)) + (elem (;0;) (i32.const 0) func $f3) + (elem (;1;) (i32.const 0) funcref (ref.func $f4)) + (elem (;2;) func $f5) + (elem (;3;) funcref (ref.func $f6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/ref_func.wast/2.print b/tests/snapshots/testsuite/ref_func.wast/2.print new file mode 100644 index 0000000000..61b233dec6 --- /dev/null +++ b/tests/snapshots/testsuite/ref_func.wast/2.print @@ -0,0 +1,82 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (import "M" "f" (func $f (;0;) (type 0))) + (func $g (;1;) (type 0) (param $x i32) (result i32) + local.get $x + i32.const 1 + i32.add + ) + (func (;2;) (type 1) + ref.func $ff1 + drop + ref.func $ff2 + drop + ) + (func $gf1 (;3;) (type 1)) + (func $gf2 (;4;) (type 1)) + (func $ff1 (;5;) (type 1)) + (func $ff2 (;6;) (type 1)) + (func (;7;) (type 2) (result i32) + ref.func $f + ref.is_null + ) + (func (;8;) (type 2) (result i32) + ref.func $g + ref.is_null + ) + (func (;9;) (type 2) (result i32) + global.get $v + ref.is_null + ) + (func (;10;) (type 1) + ref.func $f + global.set $v + ) + (func (;11;) (type 1) + ref.func $g + global.set $v + ) + (func (;12;) (type 0) (param $x i32) (result i32) + i32.const 0 + ref.func $f + table.set $t + local.get $x + i32.const 0 + call_indirect (type 0) + ) + (func (;13;) (type 0) (param $x i32) (result i32) + i32.const 0 + ref.func $g + table.set $t + local.get $x + i32.const 0 + call_indirect (type 0) + ) + (func (;14;) (type 0) (param $x i32) (result i32) + i32.const 0 + global.get $v + table.set $t + local.get $x + i32.const 0 + call_indirect (type 0) + ) + (table $t (;0;) 1 funcref) + (global (;0;) funcref ref.func $f) + (global (;1;) funcref ref.func $g) + (global $v (;2;) (mut funcref) ref.func $f) + (global (;3;) funcref ref.func $gf1) + (global (;4;) funcref ref.func $gf2) + (export "is_null-f" (func 7)) + (export "is_null-g" (func 8)) + (export "is_null-v" (func 9)) + (export "set-f" (func 10)) + (export "set-g" (func 11)) + (export "call-f" (func 12)) + (export "call-g" (func 13)) + (export "call-v" (func 14)) + (elem (;0;) declare func $gf1 $ff1) + (elem (;1;) declare funcref (ref.func $gf2) (ref.func $ff2)) + (elem (;2;) declare func $f $g) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/ref_is_null.wast/0.print b/tests/snapshots/testsuite/ref_is_null.wast/0.print new file mode 100644 index 0000000000..3416282d1d --- /dev/null +++ b/tests/snapshots/testsuite/ref_is_null.wast/0.print @@ -0,0 +1,48 @@ +(module + (type (;0;) (func (param funcref) (result i32))) + (type (;1;) (func (param externref) (result i32))) + (type (;2;) (func)) + (type (;3;) (func (param externref))) + (type (;4;) (func (param i32) (result i32))) + (func $f1 (;0;) (type 0) (param $x funcref) (result i32) + local.get $x + ref.is_null + ) + (func $f2 (;1;) (type 1) (param $x externref) (result i32) + local.get $x + ref.is_null + ) + (func $dummy (;2;) (type 2)) + (func (;3;) (type 3) (param $r externref) + i32.const 1 + local.get $r + table.set $t2 + ) + (func (;4;) (type 2) + i32.const 1 + ref.null func + table.set $t1 + i32.const 1 + ref.null extern + table.set $t2 + ) + (func (;5;) (type 4) (param $x i32) (result i32) + local.get $x + table.get $t1 + call $f1 + ) + (func (;6;) (type 4) (param $x i32) (result i32) + local.get $x + table.get $t2 + call $f2 + ) + (table $t1 (;0;) 2 funcref) + (table $t2 (;1;) 2 externref) + (export "funcref" (func $f1)) + (export "externref" (func $f2)) + (export "init" (func 3)) + (export "deinit" (func 4)) + (export "funcref-elem" (func 5)) + (export "externref-elem" (func 6)) + (elem (;0;) (i32.const 1) func $dummy) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/ref_null.wast/0.print b/tests/snapshots/testsuite/ref_null.wast/0.print new file mode 100644 index 0000000000..72f8a13619 --- /dev/null +++ b/tests/snapshots/testsuite/ref_null.wast/0.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func (result externref))) + (type (;1;) (func (result funcref))) + (func (;0;) (type 0) (result externref) + ref.null extern + ) + (func (;1;) (type 1) (result funcref) + ref.null func + ) + (global (;0;) externref ref.null extern) + (global (;1;) funcref ref.null func) + (export "externref" (func 0)) + (export "funcref" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/return.wast/0.print b/tests/snapshots/testsuite/return.wast/0.print new file mode 100644 index 0000000000..312848c1a2 --- /dev/null +++ b/tests/snapshots/testsuite/return.wast/0.print @@ -0,0 +1,469 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (type (;4;) (func (result f32))) + (type (;5;) (func (result f64))) + (type (;6;) (func (param i32 i32) (result i32))) + (func $dummy (;0;) (type 1)) + (func (;1;) (type 1) + return + i32.ctz + drop + ) + (func (;2;) (type 1) + return + i64.ctz + drop + ) + (func (;3;) (type 1) + return + f32.neg + drop + ) + (func (;4;) (type 1) + return + f64.neg + drop + ) + (func (;5;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + return + i32.ctz + end + ) + (func (;6;) (type 3) (result i64) + block (result i64) ;; label = @1 + i64.const 2 + return + i64.ctz + end + ) + (func (;7;) (type 4) (result f32) + block (result f32) ;; label = @1 + f32.const 0x1.8p+1 (;=3;) + return + f32.neg + end + ) + (func (;8;) (type 5) (result f64) + block (result f64) ;; label = @1 + f64.const 0x1p+2 (;=4;) + return + f64.neg + end + ) + (func (;9;) (type 1) + return + ) + (func (;10;) (type 5) (result f64) + f64.const 0x1.8p+1 (;=3;) + return + ) + (func (;11;) (type 2) (result i32) + i32.const 1 + return + i32.const 2 + ) + (func (;12;) (type 2) (result i32) + call $dummy + i32.const 2 + return + i32.const 3 + ) + (func (;13;) (type 1) + nop + call $dummy + return + ) + (func (;14;) (type 2) (result i32) + nop + call $dummy + i32.const 3 + return + ) + (func (;15;) (type 1) + block ;; label = @1 + return + call $dummy + end + ) + (func (;16;) (type 1) + block ;; label = @1 + call $dummy + return + call $dummy + end + ) + (func (;17;) (type 1) + block ;; label = @1 + nop + call $dummy + return + end + ) + (func (;18;) (type 2) (result i32) + block (result i32) ;; label = @1 + nop + call $dummy + i32.const 2 + return + end + ) + (func (;19;) (type 2) (result i32) + loop (result i32) ;; label = @1 + i32.const 3 + return + i32.const 2 + end + ) + (func (;20;) (type 2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 4 + return + i32.const 2 + end + ) + (func (;21;) (type 2) (result i32) + loop (result i32) ;; label = @1 + nop + call $dummy + i32.const 5 + return + end + ) + (func (;22;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 9 + return + br 0 (;@1;) + end + ) + (func (;23;) (type 1) + block ;; label = @1 + return + br_if 0 (;@1;) + end + ) + (func (;24;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 8 + return + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;25;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 9 + return + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;26;) (type 3) (result i64) + block ;; label = @1 + i64.const 9 + return + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + i64.const -1 + ) + (func (;27;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 10 + return + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;28;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + i32.const 11 + return + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;29;) (type 3) (result i64) + i64.const 7 + return + return + ) + (func (;30;) (type 2) (result i32) + i32.const 2 + return + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;31;) (type 6) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + i32.const 3 + return + else + local.get 1 + end + ) + (func (;32;) (type 6) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 1 + else + i32.const 4 + return + end + ) + (func (;33;) (type 6) (param i32 i32) (result i32) + i32.const 5 + return + local.get 0 + local.get 1 + select + ) + (func (;34;) (type 6) (param i32 i32) (result i32) + local.get 0 + i32.const 6 + return + local.get 1 + select + ) + (func (;35;) (type 2) (result i32) + i32.const 0 + i32.const 1 + i32.const 7 + return + select + ) + (func $f (;36;) (type $sig) (param i32 i32 i32) (result i32) + i32.const -1 + ) + (func (;37;) (type 2) (result i32) + i32.const 12 + return + i32.const 2 + i32.const 3 + call $f + ) + (func (;38;) (type 2) (result i32) + i32.const 1 + i32.const 13 + return + i32.const 3 + call $f + ) + (func (;39;) (type 2) (result i32) + i32.const 1 + i32.const 2 + i32.const 14 + return + call $f + ) + (func (;40;) (type 2) (result i32) + i32.const 20 + return + i32.const 1 + i32.const 2 + i32.const 3 + call_indirect (type $sig) + ) + (func (;41;) (type 2) (result i32) + i32.const 0 + i32.const 21 + return + i32.const 2 + i32.const 3 + call_indirect (type $sig) + ) + (func (;42;) (type 2) (result i32) + i32.const 0 + i32.const 1 + i32.const 22 + return + i32.const 3 + call_indirect (type $sig) + ) + (func (;43;) (type 2) (result i32) + i32.const 0 + i32.const 1 + i32.const 2 + i32.const 23 + return + call_indirect (type $sig) + ) + (func (;44;) (type 2) (result i32) + (local f32) + i32.const 17 + return + local.set 0 + i32.const -1 + ) + (func (;45;) (type 2) (result i32) + (local i32) + i32.const 1 + return + local.tee 0 + ) + (func (;46;) (type 2) (result i32) + i32.const 1 + return + global.set $a + ) + (func (;47;) (type 4) (result f32) + f32.const 0x1.b33334p+0 (;=1.7;) + return + f32.load + ) + (func (;48;) (type 3) (result i64) + i64.const 30 + return + i64.load8_s + ) + (func (;49;) (type 2) (result i32) + i32.const 30 + return + f64.const 0x1.cp+2 (;=7;) + f64.store + i32.const -1 + ) + (func (;50;) (type 2) (result i32) + i32.const 2 + i32.const 31 + return + i64.store + i32.const -1 + ) + (func (;51;) (type 2) (result i32) + i32.const 32 + return + i32.const 7 + i32.store8 + i32.const -1 + ) + (func (;52;) (type 2) (result i32) + i32.const 2 + i32.const 33 + return + i64.store16 + i32.const -1 + ) + (func (;53;) (type 4) (result f32) + f32.const 0x1.b33334p+1 (;=3.4;) + return + f32.neg + ) + (func (;54;) (type 2) (result i32) + i32.const 3 + return + i32.const 10 + i32.add + ) + (func (;55;) (type 3) (result i64) + i64.const 10 + i64.const 45 + return + i64.sub + ) + (func (;56;) (type 2) (result i32) + i32.const 44 + return + i32.eqz + ) + (func (;57;) (type 2) (result i32) + i32.const 43 + return + f64.const 0x1.4p+3 (;=10;) + f64.le + ) + (func (;58;) (type 2) (result i32) + f32.const 0x1.4p+3 (;=10;) + i32.const 42 + return + f32.ne + ) + (func (;59;) (type 2) (result i32) + i32.const 41 + return + i32.wrap_i64 + ) + (func (;60;) (type 2) (result i32) + i32.const 40 + return + memory.grow + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 0) + (export "type-i32" (func 1)) + (export "type-i64" (func 2)) + (export "type-f32" (func 3)) + (export "type-f64" (func 4)) + (export "type-i32-value" (func 5)) + (export "type-i64-value" (func 6)) + (export "type-f32-value" (func 7)) + (export "type-f64-value" (func 8)) + (export "nullary" (func 9)) + (export "unary" (func 10)) + (export "as-func-first" (func 11)) + (export "as-func-mid" (func 12)) + (export "as-func-last" (func 13)) + (export "as-func-value" (func 14)) + (export "as-block-first" (func 15)) + (export "as-block-mid" (func 16)) + (export "as-block-last" (func 17)) + (export "as-block-value" (func 18)) + (export "as-loop-first" (func 19)) + (export "as-loop-mid" (func 20)) + (export "as-loop-last" (func 21)) + (export "as-br-value" (func 22)) + (export "as-br_if-cond" (func 23)) + (export "as-br_if-value" (func 24)) + (export "as-br_if-value-cond" (func 25)) + (export "as-br_table-index" (func 26)) + (export "as-br_table-value" (func 27)) + (export "as-br_table-value-index" (func 28)) + (export "as-return-value" (func 29)) + (export "as-if-cond" (func 30)) + (export "as-if-then" (func 31)) + (export "as-if-else" (func 32)) + (export "as-select-first" (func 33)) + (export "as-select-second" (func 34)) + (export "as-select-cond" (func 35)) + (export "as-call-first" (func 37)) + (export "as-call-mid" (func 38)) + (export "as-call-last" (func 39)) + (export "as-call_indirect-func" (func 40)) + (export "as-call_indirect-first" (func 41)) + (export "as-call_indirect-mid" (func 42)) + (export "as-call_indirect-last" (func 43)) + (export "as-local.set-value" (func 44)) + (export "as-local.tee-value" (func 45)) + (export "as-global.set-value" (func 46)) + (export "as-load-address" (func 47)) + (export "as-loadN-address" (func 48)) + (export "as-store-address" (func 49)) + (export "as-store-value" (func 50)) + (export "as-storeN-address" (func 51)) + (export "as-storeN-value" (func 52)) + (export "as-unary-operand" (func 53)) + (export "as-binary-left" (func 54)) + (export "as-binary-right" (func 55)) + (export "as-test-operand" (func 56)) + (export "as-compare-left" (func 57)) + (export "as-compare-right" (func 58)) + (export "as-convert-operand" (func 59)) + (export "as-memory.grow-size" (func 60)) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/select.wast/0.print b/tests/snapshots/testsuite/select.wast/0.print new file mode 100644 index 0000000000..234d931424 --- /dev/null +++ b/tests/snapshots/testsuite/select.wast/0.print @@ -0,0 +1,429 @@ +(module + (type $check (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32 i32 i32) (result i32))) + (type (;3;) (func (param i64 i64 i32) (result i64))) + (type (;4;) (func (param f32 f32 i32) (result f32))) + (type (;5;) (func (param f64 f64 i32) (result f64))) + (type (;6;) (func (param funcref funcref i32) (result funcref))) + (type (;7;) (func (param externref externref i32) (result externref))) + (type (;8;) (func (param i32) (result i32))) + (type (;9;) (func (param i32))) + (func $dummy (;0;) (type 1)) + (func (;1;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;2;) (type 3) (param i64 i64 i32) (result i64) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;3;) (type 4) (param f32 f32 i32) (result f32) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;4;) (type 5) (param f64 f64 i32) (result f64) + local.get 0 + local.get 1 + local.get 2 + select + ) + (func (;5;) (type 2) (param i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + select (result i32) + ) + (func (;6;) (type 3) (param i64 i64 i32) (result i64) + local.get 0 + local.get 1 + local.get 2 + select (result i64) + ) + (func (;7;) (type 4) (param f32 f32 i32) (result f32) + local.get 0 + local.get 1 + local.get 2 + select (result f32) + ) + (func (;8;) (type 5) (param f64 f64 i32) (result f64) + local.get 0 + local.get 1 + local.get 2 + select (result f64) + ) + (func (;9;) (type 6) (param funcref funcref i32) (result funcref) + local.get 0 + local.get 1 + local.get 2 + select (result funcref) + ) + (func (;10;) (type 7) (param externref externref i32) (result externref) + local.get 0 + local.get 1 + local.get 2 + select (result externref) + ) + (func (;11;) (type 8) (param i32) (result i32) + i32.const 0 + i32.const 1 + local.get 0 + select + i32.const 2 + i32.const 3 + select + ) + (func (;12;) (type 8) (param i32) (result i32) + i32.const 2 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.const 3 + select + ) + (func (;13;) (type 8) (param i32) (result i32) + i32.const 2 + i32.const 3 + i32.const 0 + i32.const 1 + local.get 0 + select + select + ) + (func (;14;) (type 8) (param i32) (result i32) + loop (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + call $dummy + call $dummy + end + ) + (func (;15;) (type 8) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + i32.const 2 + i32.const 3 + local.get 0 + select + call $dummy + end + ) + (func (;16;) (type 8) (param i32) (result i32) + loop (result i32) ;; label = @1 + call $dummy + call $dummy + i32.const 2 + i32.const 3 + local.get 0 + select + end + ) + (func (;17;) (type 9) (param i32) + i32.const 2 + i32.const 3 + local.get 0 + select + if ;; label = @1 + call $dummy + end + ) + (func (;18;) (type 8) (param i32) (result i32) + i32.const 1 + if (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + else + i32.const 4 + end + ) + (func (;19;) (type 8) (param i32) (result i32) + i32.const 0 + if (result i32) ;; label = @1 + i32.const 2 + else + i32.const 2 + i32.const 3 + local.get 0 + select + end + ) + (func (;20;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 4 + br_if 0 (;@1;) + end + ) + (func (;21;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 2 + i32.const 3 + local.get 0 + select + br_if 0 (;@1;) + end + ) + (func (;22;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 2 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;23;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 2 + i32.const 3 + local.get 0 + select + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func $func (;24;) (type $check) (param i32 i32) (result i32) + local.get 0 + ) + (func (;25;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 1 + i32.const 0 + call_indirect $t (type $check) + end + ) + (func (;26;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + i32.const 3 + local.get 0 + select + i32.const 0 + call_indirect $t (type $check) + end + ) + (func (;27;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 4 + i32.const 2 + i32.const 3 + local.get 0 + select + call_indirect $t (type $check) + end + ) + (func (;28;) (type 9) (param i32) + i32.const 0 + i32.const 4 + local.get 0 + select + i32.const 1 + i32.store + ) + (func (;29;) (type 9) (param i32) + i32.const 8 + i32.const 1 + i32.const 2 + local.get 0 + select + i32.store + ) + (func (;30;) (type 8) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + memory.grow + ) + (func $f (;31;) (type 8) (param i32) (result i32) + local.get 0 + ) + (func (;32;) (type 8) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + call $f + ) + (func (;33;) (type 8) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + return + ) + (func (;34;) (type 9) (param i32) + i32.const 1 + i32.const 2 + local.get 0 + select + drop + ) + (func (;35;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + local.get 0 + select + br 0 (;@1;) + end + ) + (func (;36;) (type 8) (param i32) (result i32) + (local i32) + i32.const 1 + i32.const 2 + local.get 0 + select + local.set 0 + local.get 0 + ) + (func (;37;) (type 8) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + local.tee 0 + ) + (func (;38;) (type 8) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + global.set $a + global.get $a + ) + (func (;39;) (type 8) (param i32) (result i32) + i32.const 0 + i32.const 4 + local.get 0 + select + i32.load + ) + (func (;40;) (type 8) (param i32) (result i32) + i32.const 0 + i32.const 1 + local.get 0 + select + i32.eqz + ) + (func (;41;) (type 8) (param i32) (result i32) + i32.const 1 + i32.const 2 + local.get 0 + select + i32.const 1 + i32.const 2 + local.get 0 + select + i32.mul + ) + (func (;42;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.eqz + end + ) + (func (;43;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 2 + local.get 0 + select + i32.const 1 + i32.le_s + end + ) + (func (;44;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i32.const 1 + i32.const 0 + i32.const 1 + local.get 0 + select + i32.ne + end + ) + (func (;45;) (type 8) (param i32) (result i32) + block (result i32) ;; label = @1 + i64.const 1 + i64.const 0 + local.get 0 + select + i32.wrap_i64 + end + ) + (table $tab (;0;) 1 1 funcref) + (table $t (;1;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut i32) i32.const 10) + (export "select-i32" (func 1)) + (export "select-i64" (func 2)) + (export "select-f32" (func 3)) + (export "select-f64" (func 4)) + (export "select-i32-t" (func 5)) + (export "select-i64-t" (func 6)) + (export "select-f32-t" (func 7)) + (export "select-f64-t" (func 8)) + (export "select-funcref" (func 9)) + (export "select-externref" (func 10)) + (export "as-select-first" (func 11)) + (export "as-select-mid" (func 12)) + (export "as-select-last" (func 13)) + (export "as-loop-first" (func 14)) + (export "as-loop-mid" (func 15)) + (export "as-loop-last" (func 16)) + (export "as-if-condition" (func 17)) + (export "as-if-then" (func 18)) + (export "as-if-else" (func 19)) + (export "as-br_if-first" (func 20)) + (export "as-br_if-last" (func 21)) + (export "as-br_table-first" (func 22)) + (export "as-br_table-last" (func 23)) + (export "as-call_indirect-first" (func 25)) + (export "as-call_indirect-mid" (func 26)) + (export "as-call_indirect-last" (func 27)) + (export "as-store-first" (func 28)) + (export "as-store-last" (func 29)) + (export "as-memory.grow-value" (func 30)) + (export "as-call-value" (func 32)) + (export "as-return-value" (func 33)) + (export "as-drop-operand" (func 34)) + (export "as-br-value" (func 35)) + (export "as-local.set-value" (func 36)) + (export "as-local.tee-value" (func 37)) + (export "as-global.set-value" (func 38)) + (export "as-load-operand" (func 39)) + (export "as-unary-operand" (func 40)) + (export "as-binary-operand" (func 41)) + (export "as-test-operand" (func 42)) + (export "as-compare-left" (func 43)) + (export "as-compare-right" (func 44)) + (export "as-convert-operand" (func 45)) + (elem (;0;) (i32.const 0) func $dummy) + (elem (;1;) (table $t) (i32.const 0) func $func) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/select.wast/147.print b/tests/snapshots/testsuite/select.wast/147.print new file mode 100644 index 0000000000..db37a358d8 --- /dev/null +++ b/tests/snapshots/testsuite/select.wast/147.print @@ -0,0 +1,59 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + unreachable + select + ) + (func (;1;) (type 0) (result i32) + unreachable + select + nop + ) + (func (;2;) (type 0) (result i32) + unreachable + select + select + ) + (func (;3;) (type 0) (result i32) + unreachable + select + select + ) + (func (;4;) (type 0) (result i32) + unreachable + select + select + select + ) + (func (;5;) (type 0) (result i32) + unreachable + select (result i32) + ) + (func (;6;) (type 0) (result i32) + unreachable + select (result i32) + ) + (func (;7;) (type 0) (result i32) + unreachable + select (result i32) + select + ) + (func (;8;) (type 0) (result i32) + unreachable + select (result i32) + select (result i32) + ) + (func (;9;) (type 0) (result i32) + unreachable + select + call_indirect (type 1) + ) + (func (;10;) (type 0) (result i32) + unreachable + select + call_indirect (type 1) + select + ) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_address.wast/0.print b/tests/snapshots/testsuite/simd_address.wast/0.print new file mode 100644 index 0000000000..08b300ba8f --- /dev/null +++ b/tests/snapshots/testsuite/simd_address.wast/0.print @@ -0,0 +1,87 @@ +(module + (type (;0;) (func (param i32) (result v128))) + (type (;1;) (func (result v128))) + (type (;2;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) (result v128) + local.get $i + v128.load + ) + (func (;1;) (type 0) (param $i i32) (result v128) + local.get $i + v128.load align=1 + ) + (func (;2;) (type 0) (param $i i32) (result v128) + local.get $i + v128.load offset=1 align=1 + ) + (func (;3;) (type 0) (param $i i32) (result v128) + local.get $i + v128.load offset=2 align=1 + ) + (func (;4;) (type 0) (param $i i32) (result v128) + local.get $i + v128.load offset=15 align=1 + ) + (func (;5;) (type 1) (result v128) + i32.const 0 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x40400000 + v128.store + i32.const 0 + v128.load + ) + (func (;6;) (type 1) (result v128) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store align=1 + i32.const 0 + v128.load align=1 + ) + (func (;7;) (type 1) (result v128) + i32.const 0 + v128.const i32x4 0x00010000 0x00030002 0x00050004 0x00070006 + v128.store offset=1 align=1 + i32.const 0 + v128.load offset=1 align=1 + ) + (func (;8;) (type 1) (result v128) + i32.const 0 + v128.const i32x4 0x03020100 0x07060504 0x0b0a0908 0x0f0e0d0c + v128.store offset=2 align=1 + i32.const 0 + v128.load offset=2 align=1 + ) + (func (;9;) (type 1) (result v128) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store offset=15 align=1 + i32.const 0 + v128.load offset=15 + ) + (func (;10;) (type 1) (result v128) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store offset=65520 align=1 + i32.const 0 + v128.load offset=65520 + ) + (func (;11;) (type 2) (param $i i32) + local.get $i + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store offset=1 align=1 + ) + (memory (;0;) 1) + (export "load_data_1" (func 0)) + (export "load_data_2" (func 1)) + (export "load_data_3" (func 2)) + (export "load_data_4" (func 3)) + (export "load_data_5" (func 4)) + (export "store_data_0" (func 5)) + (export "store_data_1" (func 6)) + (export "store_data_2" (func 7)) + (export "store_data_3" (func 8)) + (export "store_data_4" (func 9)) + (export "store_data_5" (func 10)) + (export "store_data_6" (func 11)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\10\11\12\13\14\15") + (data (;1;) (i32.const 65505) "\16\17\18\19 !\22#$%&'()01") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_address.wast/41.print b/tests/snapshots/testsuite/simd_address.wast/41.print new file mode 100644 index 0000000000..d483545ba1 --- /dev/null +++ b/tests/snapshots/testsuite/simd_address.wast/41.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load offset=65521 + drop + ) + (memory (;0;) 1) + (export "v128.load_offset_65521" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_address.wast/44.print b/tests/snapshots/testsuite/simd_address.wast/44.print new file mode 100644 index 0000000000..22de188031 --- /dev/null +++ b/tests/snapshots/testsuite/simd_address.wast/44.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store offset=65521 + ) + (memory (;0;) 1) + (export "v128.store_offset_65521" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/0.print b/tests/snapshots/testsuite/simd_align.wast/0.print new file mode 100644 index 0000000000..6f3a3d0981 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/0.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/1.print b/tests/snapshots/testsuite/simd_align.wast/1.print new file mode 100644 index 0000000000..3a3eb4fa82 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/1.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/10.print b/tests/snapshots/testsuite/simd_align.wast/10.print new file mode 100644 index 0000000000..c741eb64f5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/10.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8x8_s align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/11.print b/tests/snapshots/testsuite/simd_align.wast/11.print new file mode 100644 index 0000000000..c860e0c742 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/11.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8x8_s align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/12.print b/tests/snapshots/testsuite/simd_align.wast/12.print new file mode 100644 index 0000000000..4329d2f452 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/12.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8x8_s align=4 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/13.print b/tests/snapshots/testsuite/simd_align.wast/13.print new file mode 100644 index 0000000000..1205beb308 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/13.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8x8_s + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/14.print b/tests/snapshots/testsuite/simd_align.wast/14.print new file mode 100644 index 0000000000..87b597b2d9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/14.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8x8_u align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/15.print b/tests/snapshots/testsuite/simd_align.wast/15.print new file mode 100644 index 0000000000..92dc603be2 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/15.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8x8_u align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/16.print b/tests/snapshots/testsuite/simd_align.wast/16.print new file mode 100644 index 0000000000..2a5abd63b9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/16.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8x8_u align=4 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/17.print b/tests/snapshots/testsuite/simd_align.wast/17.print new file mode 100644 index 0000000000..babc83d536 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/17.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8x8_u + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/18.print b/tests/snapshots/testsuite/simd_align.wast/18.print new file mode 100644 index 0000000000..5136ca57a6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/18.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16x4_s align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/19.print b/tests/snapshots/testsuite/simd_align.wast/19.print new file mode 100644 index 0000000000..a40cb122f0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/19.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16x4_s align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/2.print b/tests/snapshots/testsuite/simd_align.wast/2.print new file mode 100644 index 0000000000..c45aa4eef9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/2.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load align=4 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/20.print b/tests/snapshots/testsuite/simd_align.wast/20.print new file mode 100644 index 0000000000..24daddb276 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/20.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16x4_s align=4 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/21.print b/tests/snapshots/testsuite/simd_align.wast/21.print new file mode 100644 index 0000000000..ff3c3fb520 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/21.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16x4_s + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/22.print b/tests/snapshots/testsuite/simd_align.wast/22.print new file mode 100644 index 0000000000..f4fd58700b --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/22.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16x4_u align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/23.print b/tests/snapshots/testsuite/simd_align.wast/23.print new file mode 100644 index 0000000000..055c2c582b --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/23.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16x4_u align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/24.print b/tests/snapshots/testsuite/simd_align.wast/24.print new file mode 100644 index 0000000000..15d035f7d4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/24.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16x4_u align=4 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/25.print b/tests/snapshots/testsuite/simd_align.wast/25.print new file mode 100644 index 0000000000..42294436f2 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/25.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16x4_u + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/26.print b/tests/snapshots/testsuite/simd_align.wast/26.print new file mode 100644 index 0000000000..8048aeed3a --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/26.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32x2_s align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/27.print b/tests/snapshots/testsuite/simd_align.wast/27.print new file mode 100644 index 0000000000..a8df2acc0d --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/27.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32x2_s align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/28.print b/tests/snapshots/testsuite/simd_align.wast/28.print new file mode 100644 index 0000000000..4b24c86f27 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/28.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32x2_s align=4 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/29.print b/tests/snapshots/testsuite/simd_align.wast/29.print new file mode 100644 index 0000000000..207e90542b --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/29.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32x2_s + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/3.print b/tests/snapshots/testsuite/simd_align.wast/3.print new file mode 100644 index 0000000000..f716215a81 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/3.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load align=8 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/30.print b/tests/snapshots/testsuite/simd_align.wast/30.print new file mode 100644 index 0000000000..c6f217fbe4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/30.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32x2_u align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/31.print b/tests/snapshots/testsuite/simd_align.wast/31.print new file mode 100644 index 0000000000..a68b822795 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/31.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32x2_u align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/32.print b/tests/snapshots/testsuite/simd_align.wast/32.print new file mode 100644 index 0000000000..8a4ecad190 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/32.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32x2_u align=4 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/33.print b/tests/snapshots/testsuite/simd_align.wast/33.print new file mode 100644 index 0000000000..1a948c2b29 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/33.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32x2_u + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/34.print b/tests/snapshots/testsuite/simd_align.wast/34.print new file mode 100644 index 0000000000..385bd3a400 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/34.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load8_splat + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/35.print b/tests/snapshots/testsuite/simd_align.wast/35.print new file mode 100644 index 0000000000..3cad85c1bc --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/35.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16_splat align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/36.print b/tests/snapshots/testsuite/simd_align.wast/36.print new file mode 100644 index 0000000000..4efe104d86 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/36.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load16_splat + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/37.print b/tests/snapshots/testsuite/simd_align.wast/37.print new file mode 100644 index 0000000000..93984a1c28 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/37.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32_splat align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/38.print b/tests/snapshots/testsuite/simd_align.wast/38.print new file mode 100644 index 0000000000..5769ea6b53 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/38.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32_splat align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/39.print b/tests/snapshots/testsuite/simd_align.wast/39.print new file mode 100644 index 0000000000..187e90430f --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/39.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load32_splat + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/4.print b/tests/snapshots/testsuite/simd_align.wast/4.print new file mode 100644 index 0000000000..0a22a9c5bc --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/4.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/40.print b/tests/snapshots/testsuite/simd_align.wast/40.print new file mode 100644 index 0000000000..c6800f664a --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/40.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load64_splat align=1 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/41.print b/tests/snapshots/testsuite/simd_align.wast/41.print new file mode 100644 index 0000000000..57c3fc3ee1 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/41.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load64_splat align=2 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/42.print b/tests/snapshots/testsuite/simd_align.wast/42.print new file mode 100644 index 0000000000..813a9af0cf --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/42.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load64_splat align=4 + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/43.print b/tests/snapshots/testsuite/simd_align.wast/43.print new file mode 100644 index 0000000000..871f89c6a5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/43.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.load64_splat + drop + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/5.print b/tests/snapshots/testsuite/simd_align.wast/5.print new file mode 100644 index 0000000000..7a07070200 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/5.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store align=1 + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/6.print b/tests/snapshots/testsuite/simd_align.wast/6.print new file mode 100644 index 0000000000..deb46fdcd5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/6.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store align=2 + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/7.print b/tests/snapshots/testsuite/simd_align.wast/7.print new file mode 100644 index 0000000000..2026efdbe0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/7.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store align=4 + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/8.print b/tests/snapshots/testsuite/simd_align.wast/8.print new file mode 100644 index 0000000000..d5ec1360f6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/8.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store align=8 + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/9.print b/tests/snapshots/testsuite/simd_align.wast/9.print new file mode 100644 index 0000000000..5e9941fea0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/9.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store + ) + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/90.print b/tests/snapshots/testsuite/simd_align.wast/90.print new file mode 100644 index 0000000000..4926d07e6d --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/90.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func (param i32) (result v128))) + (type (;1;) (func (param i32 v128))) + (func (;0;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load + ) + (func (;1;) (type 1) (param $address i32) (param $value v128) + local.get $address + local.get $value + v128.store + ) + (memory (;0;) 1 1) + (export "v128.load align=16" (func 0)) + (export "v128.store align=16" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_align.wast/95.print b/tests/snapshots/testsuite/simd_align.wast/95.print new file mode 100644 index 0000000000..14305994a5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_align.wast/95.print @@ -0,0 +1,40 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + (local v128) + i32.const 0 + v128.const i32x4 0x03020100 0x07060504 0x0b0a0908 0x0f0e0d0c + v128.store + i32.const 0 + v128.load + ) + (func (;1;) (type 0) (result v128) + (local v128) + i32.const 0 + v128.const i32x4 0x00010000 0x00030002 0x00050004 0x00070006 + v128.store align=2 + i32.const 0 + v128.load align=2 + ) + (func (;2;) (type 0) (result v128) + (local v128) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store + i32.const 0 + v128.load align=2 + ) + (func (;3;) (type 0) (result v128) + (local v128) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store align=2 + i32.const 0 + v128.load + ) + (memory (;0;) 1) + (export "v128_unaligned_read_and_write" (func 0)) + (export "v128_aligned_read_and_write" (func 1)) + (export "v128_aligned_read_and_unaligned_write" (func 2)) + (export "v128_unaligned_read_and_aligned_write" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_bit_shift.wast/0.print b/tests/snapshots/testsuite/simd_bit_shift.wast/0.print new file mode 100644 index 0000000000..cc0cfbf797 --- /dev/null +++ b/tests/snapshots/testsuite/simd_bit_shift.wast/0.print @@ -0,0 +1,148 @@ +(module + (type (;0;) (func (param v128 i32) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i8x16.shl + ) + (func (;1;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i8x16.shr_s + ) + (func (;2;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i8x16.shr_u + ) + (func (;3;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i16x8.shl + ) + (func (;4;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i16x8.shr_s + ) + (func (;5;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i16x8.shr_u + ) + (func (;6;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i32x4.shl + ) + (func (;7;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i32x4.shr_s + ) + (func (;8;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i32x4.shr_u + ) + (func (;9;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i64x2.shl + ) + (func (;10;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i64x2.shr_s + ) + (func (;11;) (type 0) (param $0 v128) (param $1 i32) (result v128) + local.get $0 + local.get $1 + i64x2.shr_u + ) + (func (;12;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 1 + i8x16.shl + ) + (func (;13;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 8 + i8x16.shr_u + ) + (func (;14;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 9 + i8x16.shr_s + ) + (func (;15;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 1 + i16x8.shl + ) + (func (;16;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 16 + i16x8.shr_u + ) + (func (;17;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 17 + i16x8.shr_s + ) + (func (;18;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 1 + i32x4.shl + ) + (func (;19;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 32 + i32x4.shr_u + ) + (func (;20;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 33 + i32x4.shr_s + ) + (func (;21;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 1 + i64x2.shl + ) + (func (;22;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 64 + i64x2.shr_u + ) + (func (;23;) (type 1) (param $0 v128) (result v128) + local.get $0 + i32.const 65 + i64x2.shr_s + ) + (export "i8x16.shl" (func 0)) + (export "i8x16.shr_s" (func 1)) + (export "i8x16.shr_u" (func 2)) + (export "i16x8.shl" (func 3)) + (export "i16x8.shr_s" (func 4)) + (export "i16x8.shr_u" (func 5)) + (export "i32x4.shl" (func 6)) + (export "i32x4.shr_s" (func 7)) + (export "i32x4.shr_u" (func 8)) + (export "i64x2.shl" (func 9)) + (export "i64x2.shr_s" (func 10)) + (export "i64x2.shr_u" (func 11)) + (export "i8x16.shl_1" (func 12)) + (export "i8x16.shr_u_8" (func 13)) + (export "i8x16.shr_s_9" (func 14)) + (export "i16x8.shl_1" (func 15)) + (export "i16x8.shr_u_16" (func 16)) + (export "i16x8.shr_s_17" (func 17)) + (export "i32x4.shl_1" (func 18)) + (export "i32x4.shr_u_32" (func 19)) + (export "i32x4.shr_s_33" (func 20)) + (export "i64x2.shl_1" (func 21)) + (export "i64x2.shr_u_64" (func 22)) + (export "i64x2.shr_s_65" (func 23)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_bit_shift.wast/188.print b/tests/snapshots/testsuite/simd_bit_shift.wast/188.print new file mode 100644 index 0000000000..ec227e8782 --- /dev/null +++ b/tests/snapshots/testsuite/simd_bit_shift.wast/188.print @@ -0,0 +1,316 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i8x16.shl + end + drop + end + ) + (func (;1;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i8x16.shr_s + end + drop + end + ) + (func (;2;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i8x16.shr_u + end + drop + end + ) + (func (;3;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i16x8.shl + end + drop + end + ) + (func (;4;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i16x8.shr_s + end + drop + end + ) + (func (;5;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i16x8.shr_u + end + drop + end + ) + (func (;6;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i32x4.shl + end + drop + end + ) + (func (;7;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i32x4.shr_s + end + drop + end + ) + (func (;8;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i32x4.shr_u + end + drop + end + ) + (func (;9;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i64x2.shl + end + drop + end + ) + (func (;10;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i64x2.shr_s + end + drop + end + ) + (func (;11;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + i32.const 1 + i64x2.shr_u + end + drop + end + ) + (func (;12;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i8x16.shl + i32.const 1 + i8x16.shl + i32.const 1 + i8x16.shl + drop + ) + (func (;13;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i8x16.shr_s + i32.const 1 + i8x16.shr_s + i32.const 1 + i8x16.shr_s + drop + ) + (func (;14;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i8x16.shr_u + i32.const 1 + i8x16.shr_u + i32.const 1 + i8x16.shr_u + drop + ) + (func (;15;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i16x8.shl + i32.const 1 + i16x8.shl + i32.const 1 + i16x8.shl + drop + ) + (func (;16;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i16x8.shr_s + i32.const 1 + i16x8.shr_s + i32.const 1 + i16x8.shr_s + drop + ) + (func (;17;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i16x8.shr_u + i32.const 1 + i16x8.shr_u + i32.const 1 + i16x8.shr_u + drop + ) + (func (;18;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i32x4.shl + i32.const 1 + i32x4.shl + i32.const 1 + i32x4.shl + drop + ) + (func (;19;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i32x4.shr_s + i32.const 1 + i32x4.shr_s + i32.const 1 + i32x4.shr_s + drop + ) + (func (;20;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i32x4.shr_u + i32.const 1 + i32x4.shr_u + i32.const 1 + i32x4.shr_u + drop + ) + (func (;21;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i64x2.shl + i32.const 1 + i64x2.shl + i32.const 1 + i64x2.shl + drop + ) + (func (;22;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i64x2.shr_s + i32.const 1 + i64x2.shr_s + i32.const 1 + i64x2.shr_s + drop + ) + (func (;23;) (type 0) + i32.const 0 + v128.load + i32.const 1 + i64x2.shr_u + i32.const 1 + i64x2.shr_u + i32.const 1 + i64x2.shr_u + drop + ) + (memory (;0;) 1) + (export "i8x16.shl-in-block" (func 0)) + (export "i8x16.shr_s-in-block" (func 1)) + (export "i8x16.shr_u-in-block" (func 2)) + (export "i16x8.shl-in-block" (func 3)) + (export "i16x8.shr_s-in-block" (func 4)) + (export "i16x8.shr_u-in-block" (func 5)) + (export "i32x4.shl-in-block" (func 6)) + (export "i32x4.shr_s-in-block" (func 7)) + (export "i32x4.shr_u-in-block" (func 8)) + (export "i64x2.shl-in-block" (func 9)) + (export "i64x2.shr_s-in-block" (func 10)) + (export "i64x2.shr_u-in-block" (func 11)) + (export "nested-i8x16.shl" (func 12)) + (export "nested-i8x16.shr_s" (func 13)) + (export "nested-i8x16.shr_u" (func 14)) + (export "nested-i16x8.shl" (func 15)) + (export "nested-i16x8.shr_s" (func 16)) + (export "nested-i16x8.shr_u" (func 17)) + (export "nested-i32x4.shl" (func 18)) + (export "nested-i32x4.shr_s" (func 19)) + (export "nested-i32x4.shr_u" (func 20)) + (export "nested-i64x2.shl" (func 21)) + (export "nested-i64x2.shr_s" (func 22)) + (export "nested-i64x2.shr_u" (func 23)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_bitwise.wast/0.print b/tests/snapshots/testsuite/simd_bitwise.wast/0.print new file mode 100644 index 0000000000..91c81dbefb --- /dev/null +++ b/tests/snapshots/testsuite/simd_bitwise.wast/0.print @@ -0,0 +1,41 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (type (;2;) (func (param v128 v128 v128) (result v128))) + (func (;0;) (type 0) (param $0 v128) (result v128) + local.get $0 + v128.not + ) + (func (;1;) (type 1) (param $0 v128) (param $1 v128) (result v128) + local.get $0 + local.get $1 + v128.and + ) + (func (;2;) (type 1) (param $0 v128) (param $1 v128) (result v128) + local.get $0 + local.get $1 + v128.or + ) + (func (;3;) (type 1) (param $0 v128) (param $1 v128) (result v128) + local.get $0 + local.get $1 + v128.xor + ) + (func (;4;) (type 2) (param $0 v128) (param $1 v128) (param $2 v128) (result v128) + local.get $0 + local.get $1 + local.get $2 + v128.bitselect + ) + (func (;5;) (type 1) (param $0 v128) (param $1 v128) (result v128) + local.get $0 + local.get $1 + v128.andnot + ) + (export "not" (func 0)) + (export "and" (func 1)) + (export "or" (func 2)) + (export "xor" (func 3)) + (export "bitselect" (func 4)) + (export "andnot" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_bitwise.wast/143.print b/tests/snapshots/testsuite/simd_bitwise.wast/143.print new file mode 100644 index 0000000000..24f3ef371f --- /dev/null +++ b/tests/snapshots/testsuite/simd_bitwise.wast/143.print @@ -0,0 +1,319 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + v128.not + end + drop + end + ) + (func (;1;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + v128.and + end + drop + end + ) + (func (;2;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + v128.or + end + drop + end + ) + (func (;3;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + v128.xor + end + drop + end + ) + (func (;4;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + block (result v128) ;; label = @3 + i32.const 2 + v128.load + end + v128.bitselect + end + drop + end + ) + (func (;5;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + v128.andnot + end + drop + end + ) + (func (;6;) (type 0) + i32.const 0 + v128.load + v128.not + v128.not + v128.not + drop + ) + (func (;7;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.and + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.and + v128.and + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.and + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.and + v128.and + v128.and + drop + ) + (func (;8;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.or + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.or + v128.or + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.or + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.or + v128.or + v128.or + drop + ) + (func (;9;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.xor + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.xor + v128.xor + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.xor + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.xor + v128.xor + v128.xor + drop + ) + (func (;10;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + v128.bitselect + v128.bitselect + drop + ) + (func (;11;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.andnot + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.andnot + v128.andnot + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.andnot + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.andnot + v128.andnot + v128.andnot + drop + ) + (func (;12;) (type 0) + i32.const 0 + v128.load + v128.not + i32.const 1 + v128.load + v128.not + v128.and + i32.const 0 + v128.load + i32.const 1 + v128.load + i32.const 2 + v128.load + v128.bitselect + i32.const 0 + v128.load + i32.const 1 + v128.load + v128.andnot + v128.xor + v128.or + drop + ) + (memory (;0;) 1) + (export "v128.not-in-block" (func 0)) + (export "v128.and-in-block" (func 1)) + (export "v128.or-in-block" (func 2)) + (export "v128.xor-in-block" (func 3)) + (export "v128.bitselect-in-block" (func 4)) + (export "v128.andnot-in-block" (func 5)) + (export "nested-v128.not" (func 6)) + (export "nested-v128.and" (func 7)) + (export "nested-v128.or" (func 8)) + (export "nested-v128.xor" (func 9)) + (export "nested-v128.bitselect" (func 10)) + (export "nested-v128.andnot" (func 11)) + (export "as-param" (func 12)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_boolean.wast/0.print b/tests/snapshots/testsuite/simd_boolean.wast/0.print new file mode 100644 index 0000000000..482c11f613 --- /dev/null +++ b/tests/snapshots/testsuite/simd_boolean.wast/0.print @@ -0,0 +1,58 @@ +(module + (type (;0;) (func (param v128) (result i32))) + (func (;0;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.any_true + ) + (func (;1;) (type 0) (param $0 v128) (result i32) + local.get $0 + i8x16.all_true + ) + (func (;2;) (type 0) (param $0 v128) (result i32) + local.get $0 + i8x16.bitmask + ) + (func (;3;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.any_true + ) + (func (;4;) (type 0) (param $0 v128) (result i32) + local.get $0 + i16x8.all_true + ) + (func (;5;) (type 0) (param $0 v128) (result i32) + local.get $0 + i16x8.bitmask + ) + (func (;6;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.any_true + ) + (func (;7;) (type 0) (param $0 v128) (result i32) + local.get $0 + i32x4.all_true + ) + (func (;8;) (type 0) (param $0 v128) (result i32) + local.get $0 + i32x4.bitmask + ) + (func (;9;) (type 0) (param $0 v128) (result i32) + local.get $0 + i64x2.all_true + ) + (func (;10;) (type 0) (param $0 v128) (result i32) + local.get $0 + i64x2.bitmask + ) + (export "i8x16.any_true" (func 0)) + (export "i8x16.all_true" (func 1)) + (export "i8x16.bitmask" (func 2)) + (export "i16x8.any_true" (func 3)) + (export "i16x8.all_true" (func 4)) + (export "i16x8.bitmask" (func 5)) + (export "i32x4.any_true" (func 6)) + (export "i32x4.all_true" (func 7)) + (export "i32x4.bitmask" (func 8)) + (export "i64x2.all_true" (func 9)) + (export "i64x2.bitmask" (func 10)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_boolean.wast/80.print b/tests/snapshots/testsuite/simd_boolean.wast/80.print new file mode 100644 index 0000000000..99e48c0487 --- /dev/null +++ b/tests/snapshots/testsuite/simd_boolean.wast/80.print @@ -0,0 +1,564 @@ +(module + (type (;0;) (func (param v128) (result i32))) + (type (;1;) (func (param v128 v128) (result i32))) + (type (;2;) (func (param v128 v128 v128) (result i32))) + (func (;0;) (type 0) (param v128) (result i32) + local.get 0 + v128.any_true + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + ) + (func (;1;) (type 0) (param v128) (result i32) + local.get 0 + v128.any_true + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + ) + (func (;2;) (type 0) (param v128) (result i32) + local.get 0 + v128.any_true + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + ) + (func (;3;) (type 0) (param v128) (result i32) + local.get 0 + i8x16.all_true + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + ) + (func (;4;) (type 0) (param v128) (result i32) + local.get 0 + i16x8.all_true + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + ) + (func (;5;) (type 0) (param v128) (result i32) + local.get 0 + i32x4.all_true + if (result i32) ;; label = @1 + i32.const 1 + else + i32.const 0 + end + ) + (func (;6;) (type 0) (param v128) (result i32) + i32.const 1 + i32.const 0 + local.get 0 + v128.any_true + select + ) + (func (;7;) (type 0) (param v128) (result i32) + i32.const 1 + i32.const 0 + local.get 0 + v128.any_true + select + ) + (func (;8;) (type 0) (param v128) (result i32) + i32.const 1 + i32.const 0 + local.get 0 + v128.any_true + select + ) + (func (;9;) (type 0) (param v128) (result i32) + i32.const 1 + i32.const 0 + local.get 0 + i8x16.all_true + select + ) + (func (;10;) (type 0) (param v128) (result i32) + i32.const 1 + i32.const 0 + local.get 0 + i16x8.all_true + select + ) + (func (;11;) (type 0) (param v128) (result i32) + i32.const 1 + i32.const 0 + local.get 0 + i32x4.all_true + select + ) + (func (;12;) (type 0) (param $0 v128) (result i32) + (local $1 i32) + i32.const 2 + local.set $1 + block ;; label = @1 + i32.const 1 + local.set $1 + local.get $0 + v128.any_true + br_if 0 (;@1;) + i32.const 0 + local.set $1 + end + local.get $1 + ) + (func (;13;) (type 0) (param $0 v128) (result i32) + (local $1 i32) + i32.const 2 + local.set $1 + block ;; label = @1 + i32.const 1 + local.set $1 + local.get $0 + v128.any_true + br_if 0 (;@1;) + i32.const 0 + local.set $1 + end + local.get $1 + ) + (func (;14;) (type 0) (param $0 v128) (result i32) + (local $1 i32) + i32.const 2 + local.set $1 + block ;; label = @1 + i32.const 1 + local.set $1 + local.get $0 + v128.any_true + br_if 0 (;@1;) + i32.const 0 + local.set $1 + end + local.get $1 + ) + (func (;15;) (type 0) (param $0 v128) (result i32) + (local $1 i32) + i32.const 2 + local.set $1 + block ;; label = @1 + i32.const 1 + local.set $1 + local.get $0 + i8x16.all_true + br_if 0 (;@1;) + i32.const 0 + local.set $1 + end + local.get $1 + ) + (func (;16;) (type 0) (param $0 v128) (result i32) + (local $1 i32) + i32.const 2 + local.set $1 + block ;; label = @1 + i32.const 1 + local.set $1 + local.get $0 + i16x8.all_true + br_if 0 (;@1;) + i32.const 0 + local.set $1 + end + local.get $1 + ) + (func (;17;) (type 0) (param $0 v128) (result i32) + (local $1 i32) + i32.const 2 + local.set $1 + block ;; label = @1 + i32.const 1 + local.set $1 + local.get $0 + i32x4.all_true + br_if 0 (;@1;) + i32.const 0 + local.set $1 + end + local.get $1 + ) + (func (;18;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.and + ) + (func (;19;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.and + ) + (func (;20;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.and + ) + (func (;21;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.or + ) + (func (;22;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.or + ) + (func (;23;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.or + ) + (func (;24;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.xor + ) + (func (;25;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.xor + ) + (func (;26;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + v128.any_true + local.get $1 + v128.any_true + i32.xor + ) + (func (;27;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i8x16.all_true + local.get $1 + i8x16.all_true + i32.and + ) + (func (;28;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i16x8.all_true + local.get $1 + i16x8.all_true + i32.and + ) + (func (;29;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i32x4.all_true + local.get $1 + i32x4.all_true + i32.and + ) + (func (;30;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i8x16.all_true + local.get $1 + i8x16.all_true + i32.or + ) + (func (;31;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i16x8.all_true + local.get $1 + i16x8.all_true + i32.or + ) + (func (;32;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i32x4.all_true + local.get $1 + i32x4.all_true + i32.or + ) + (func (;33;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i8x16.all_true + local.get $1 + i8x16.all_true + i32.xor + ) + (func (;34;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i16x8.all_true + local.get $1 + i16x8.all_true + i32.xor + ) + (func (;35;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + i32x4.all_true + local.get $1 + i32x4.all_true + i32.xor + ) + (func (;36;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.not + v128.any_true + ) + (func (;37;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.not + v128.any_true + ) + (func (;38;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.not + v128.any_true + ) + (func (;39;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.and + v128.any_true + ) + (func (;40;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.and + v128.any_true + ) + (func (;41;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.and + v128.any_true + ) + (func (;42;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.or + v128.any_true + ) + (func (;43;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.or + v128.any_true + ) + (func (;44;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.or + v128.any_true + ) + (func (;45;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.xor + v128.any_true + ) + (func (;46;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.xor + v128.any_true + ) + (func (;47;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.xor + v128.any_true + ) + (func (;48;) (type 2) (param $0 v128) (param $1 v128) (param $2 v128) (result i32) + local.get $0 + local.get $1 + local.get $2 + v128.bitselect + v128.any_true + ) + (func (;49;) (type 2) (param $0 v128) (param $1 v128) (param $2 v128) (result i32) + local.get $0 + local.get $1 + local.get $2 + v128.bitselect + v128.any_true + ) + (func (;50;) (type 2) (param $0 v128) (param $1 v128) (param $2 v128) (result i32) + local.get $0 + local.get $1 + local.get $2 + v128.bitselect + v128.any_true + ) + (func (;51;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.not + i8x16.all_true + ) + (func (;52;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.not + i16x8.all_true + ) + (func (;53;) (type 0) (param $0 v128) (result i32) + local.get $0 + v128.not + i32x4.all_true + ) + (func (;54;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.and + i8x16.all_true + ) + (func (;55;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.and + i16x8.all_true + ) + (func (;56;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.and + i32x4.all_true + ) + (func (;57;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.or + i8x16.all_true + ) + (func (;58;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.or + i16x8.all_true + ) + (func (;59;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.or + i32x4.all_true + ) + (func (;60;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.xor + i8x16.all_true + ) + (func (;61;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.xor + i16x8.all_true + ) + (func (;62;) (type 1) (param $0 v128) (param $1 v128) (result i32) + local.get $0 + local.get $1 + v128.xor + i32x4.all_true + ) + (func (;63;) (type 2) (param $0 v128) (param $1 v128) (param $2 v128) (result i32) + local.get $0 + local.get $1 + local.get $2 + v128.bitselect + i8x16.all_true + ) + (func (;64;) (type 2) (param $0 v128) (param $1 v128) (param $2 v128) (result i32) + local.get $0 + local.get $1 + local.get $2 + v128.bitselect + i16x8.all_true + ) + (func (;65;) (type 2) (param $0 v128) (param $1 v128) (param $2 v128) (result i32) + local.get $0 + local.get $1 + local.get $2 + v128.bitselect + i32x4.all_true + ) + (memory (;0;) 1) + (export "i8x16_any_true_as_if_cond" (func 0)) + (export "i16x8_any_true_as_if_cond" (func 1)) + (export "i32x4_any_true_as_if_cond" (func 2)) + (export "i8x16_all_true_as_if_cond" (func 3)) + (export "i16x8_all_true_as_if_cond" (func 4)) + (export "i32x4_all_true_as_if_cond" (func 5)) + (export "i8x16_any_true_as_select_cond" (func 6)) + (export "i16x8_any_true_as_select_cond" (func 7)) + (export "i32x4_any_true_as_select_cond" (func 8)) + (export "i8x16_all_true_as_select_cond" (func 9)) + (export "i16x8_all_true_as_select_cond" (func 10)) + (export "i32x4_all_true_as_select_cond" (func 11)) + (export "i8x16_any_true_as_br_if_cond" (func 12)) + (export "i16x8_any_true_as_br_if_cond" (func 13)) + (export "i32x4_any_true_as_br_if_cond" (func 14)) + (export "i8x16_all_true_as_br_if_cond" (func 15)) + (export "i16x8_all_true_as_br_if_cond" (func 16)) + (export "i32x4_all_true_as_br_if_cond" (func 17)) + (export "i8x16_any_true_as_i32.and_operand" (func 18)) + (export "i16x8_any_true_as_i32.and_operand" (func 19)) + (export "i32x4_any_true_as_i32.and_operand" (func 20)) + (export "i8x16_any_true_as_i32.or_operand" (func 21)) + (export "i16x8_any_true_as_i32.or_operand" (func 22)) + (export "i32x4_any_true_as_i32.or_operand" (func 23)) + (export "i8x16_any_true_as_i32.xor_operand" (func 24)) + (export "i16x8_any_true_as_i32.xor_operand" (func 25)) + (export "i32x4_any_true_as_i32.xor_operand" (func 26)) + (export "i8x16_all_true_as_i32.and_operand" (func 27)) + (export "i16x8_all_true_as_i32.and_operand" (func 28)) + (export "i32x4_all_true_as_i32.and_operand" (func 29)) + (export "i8x16_all_true_as_i32.or_operand" (func 30)) + (export "i16x8_all_true_as_i32.or_operand" (func 31)) + (export "i32x4_all_true_as_i32.or_operand" (func 32)) + (export "i8x16_all_true_as_i32.xor_operand" (func 33)) + (export "i16x8_all_true_as_i32.xor_operand" (func 34)) + (export "i32x4_all_true_as_i32.xor_operand" (func 35)) + (export "i8x16_any_true_with_v128.not" (func 36)) + (export "i16x8_any_true_with_v128.not" (func 37)) + (export "i32x4_any_true_with_v128.not" (func 38)) + (export "i8x16_any_true_with_v128.and" (func 39)) + (export "i16x8_any_true_with_v128.and" (func 40)) + (export "i32x4_any_true_with_v128.and" (func 41)) + (export "i8x16_any_true_with_v128.or" (func 42)) + (export "i16x8_any_true_with_v128.or" (func 43)) + (export "i32x4_any_true_with_v128.or" (func 44)) + (export "i8x16_any_true_with_v128.xor" (func 45)) + (export "i16x8_any_true_with_v128.xor" (func 46)) + (export "i32x4_any_true_with_v128.xor" (func 47)) + (export "i8x16_any_true_with_v128.bitselect" (func 48)) + (export "i16x8_any_true_with_v128.bitselect" (func 49)) + (export "i32x4_any_true_with_v128.bitselect" (func 50)) + (export "i8x16_all_true_with_v128.not" (func 51)) + (export "i16x8_all_true_with_v128.not" (func 52)) + (export "i32x4_all_true_with_v128.not" (func 53)) + (export "i8x16_all_true_with_v128.and" (func 54)) + (export "i16x8_all_true_with_v128.and" (func 55)) + (export "i32x4_all_true_with_v128.and" (func 56)) + (export "i8x16_all_true_with_v128.or" (func 57)) + (export "i16x8_all_true_with_v128.or" (func 58)) + (export "i32x4_all_true_with_v128.or" (func 59)) + (export "i8x16_all_true_with_v128.xor" (func 60)) + (export "i16x8_all_true_with_v128.xor" (func 61)) + (export "i32x4_all_true_with_v128.xor" (func 62)) + (export "i8x16_all_true_with_v128.bitselect" (func 63)) + (export "i16x8_all_true_with_v128.bitselect" (func 64)) + (export "i32x4_all_true_with_v128.bitselect" (func 65)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/0.print b/tests/snapshots/testsuite/simd_const.wast/0.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/0.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/1.print b/tests/snapshots/testsuite/simd_const.wast/1.print new file mode 100644 index 0000000000..3b342dc473 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/1.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80808080 0x80808080 0x80808080 0x80808080 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/10.print b/tests/snapshots/testsuite/simd_const.wast/10.print new file mode 100644 index 0000000000..7a0187c254 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/10.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x30393039 0x30393039 0x30393039 0x30393039 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/100.print b/tests/snapshots/testsuite/simd_const.wast/100.print new file mode 100644 index 0000000000..2a2cc0ac4e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/100.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00ff00ff 0xffffffff 0x80008000 0x80008000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/101.print b/tests/snapshots/testsuite/simd_const.wast/101.print new file mode 100644 index 0000000000..2a2cc0ac4e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/101.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00ff00ff 0xffffffff 0x80008000 0x80008000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/102.print b/tests/snapshots/testsuite/simd_const.wast/102.print new file mode 100644 index 0000000000..ba2959115e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/102.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0x80000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/103.print b/tests/snapshots/testsuite/simd_const.wast/103.print new file mode 100644 index 0000000000..ba2959115e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/103.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0x80000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/104.print b/tests/snapshots/testsuite/simd_const.wast/104.print new file mode 100644 index 0000000000..ba2959115e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/104.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0x80000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/105.print b/tests/snapshots/testsuite/simd_const.wast/105.print new file mode 100644 index 0000000000..d31172f6ee --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/105.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x7f000000 0x7f000000 0xff000000 0xfe967699 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/106.print b/tests/snapshots/testsuite/simd_const.wast/106.print new file mode 100644 index 0000000000..f90f75c504 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/106.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x7f000000 0x7f7fffff 0xfe967699 0xff7fffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/107.print b/tests/snapshots/testsuite/simd_const.wast/107.print new file mode 100644 index 0000000000..c1c5e81d5c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/107.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x7fc00000 0xffc00000 0x7f800000 0xff800000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/108.print b/tests/snapshots/testsuite/simd_const.wast/108.print new file mode 100644 index 0000000000..61b8ff4ae6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/108.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0x00000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/109.print b/tests/snapshots/testsuite/simd_const.wast/109.print new file mode 100644 index 0000000000..61b8ff4ae6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/109.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0x00000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/11.print b/tests/snapshots/testsuite/simd_const.wast/11.print new file mode 100644 index 0000000000..8eee69f6ad --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/11.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x12341234 0x12341234 0x12341234 0x12341234 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/110.print b/tests/snapshots/testsuite/simd_const.wast/110.print new file mode 100644 index 0000000000..ae453dbf98 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/110.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000000 0x7fe00000 0x85ebc8a0 0xffe1ccf3 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/111.print b/tests/snapshots/testsuite/simd_const.wast/111.print new file mode 100644 index 0000000000..274a8ff421 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/111.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000000 0x7ff80000 0x00000000 0xfff00000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/112.print b/tests/snapshots/testsuite/simd_const.wast/112.print new file mode 100644 index 0000000000..7a21b3f236 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/112.print @@ -0,0 +1,3 @@ +(module + (memory (;0;) 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/12.print b/tests/snapshots/testsuite/simd_const.wast/12.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/12.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/13.print b/tests/snapshots/testsuite/simd_const.wast/13.print new file mode 100644 index 0000000000..72b1c15d46 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/13.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80000000 0x80000000 0x80000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/14.print b/tests/snapshots/testsuite/simd_const.wast/14.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/14.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/15.print b/tests/snapshots/testsuite/simd_const.wast/15.print new file mode 100644 index 0000000000..72b1c15d46 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/15.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80000000 0x80000000 0x80000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/16.print b/tests/snapshots/testsuite/simd_const.wast/16.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/16.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/17.print b/tests/snapshots/testsuite/simd_const.wast/17.print new file mode 100644 index 0000000000..72b1c15d46 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/17.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80000000 0x80000000 0x80000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/18.print b/tests/snapshots/testsuite/simd_const.wast/18.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/18.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/19.print b/tests/snapshots/testsuite/simd_const.wast/19.print new file mode 100644 index 0000000000..72b1c15d46 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/19.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80000000 0x80000000 0x80000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/197.print b/tests/snapshots/testsuite/simd_const.wast/197.print new file mode 100644 index 0000000000..9f38af1c28 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/197.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x26800000 0x26800000 0x26800000 0x26800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/199.print b/tests/snapshots/testsuite/simd_const.wast/199.print new file mode 100644 index 0000000000..d7e96baddc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/199.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xa6800000 0xa6800000 0xa6800000 0xa6800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/2.print b/tests/snapshots/testsuite/simd_const.wast/2.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/2.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/20.print b/tests/snapshots/testsuite/simd_const.wast/20.print new file mode 100644 index 0000000000..fa94e49a5f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/20.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x075bcd15 0x075bcd15 0x075bcd15 0x075bcd15 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/201.print b/tests/snapshots/testsuite/simd_const.wast/201.print new file mode 100644 index 0000000000..2d2c163ab7 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/201.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x26800003 0x26800003 0x26800003 0x26800003 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/203.print b/tests/snapshots/testsuite/simd_const.wast/203.print new file mode 100644 index 0000000000..9777ae57c0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/203.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xa6800003 0xa6800003 0xa6800003 0xa6800003 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/205.print b/tests/snapshots/testsuite/simd_const.wast/205.print new file mode 100644 index 0000000000..9f38af1c28 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/205.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x26800000 0x26800000 0x26800000 0x26800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/207.print b/tests/snapshots/testsuite/simd_const.wast/207.print new file mode 100644 index 0000000000..d7e96baddc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/207.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xa6800000 0xa6800000 0xa6800000 0xa6800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/209.print b/tests/snapshots/testsuite/simd_const.wast/209.print new file mode 100644 index 0000000000..2d2c163ab7 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/209.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x26800003 0x26800003 0x26800003 0x26800003 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/21.print b/tests/snapshots/testsuite/simd_const.wast/21.print new file mode 100644 index 0000000000..474fba923f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/21.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x9acffbdf 0x9acffbdf 0x9acffbdf 0x9acffbdf + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/211.print b/tests/snapshots/testsuite/simd_const.wast/211.print new file mode 100644 index 0000000000..9777ae57c0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/211.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xa6800003 0xa6800003 0xa6800003 0xa6800003 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/213.print b/tests/snapshots/testsuite/simd_const.wast/213.print new file mode 100644 index 0000000000..9f38af1c28 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/213.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x26800000 0x26800000 0x26800000 0x26800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/215.print b/tests/snapshots/testsuite/simd_const.wast/215.print new file mode 100644 index 0000000000..d7e96baddc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/215.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xa6800000 0xa6800000 0xa6800000 0xa6800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/217.print b/tests/snapshots/testsuite/simd_const.wast/217.print new file mode 100644 index 0000000000..3cfdac097e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/217.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x26800002 0x26800002 0x26800002 0x26800002 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/219.print b/tests/snapshots/testsuite/simd_const.wast/219.print new file mode 100644 index 0000000000..ddb49a9f71 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/219.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xa6800002 0xa6800002 0xa6800002 0xa6800002 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/22.print b/tests/snapshots/testsuite/simd_const.wast/22.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/22.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/221.print b/tests/snapshots/testsuite/simd_const.wast/221.print new file mode 100644 index 0000000000..d6fa221845 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/221.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x58800000 0x58800000 0x58800000 0x58800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/223.print b/tests/snapshots/testsuite/simd_const.wast/223.print new file mode 100644 index 0000000000..e6d4794afc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/223.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xd8800000 0xd8800000 0xd8800000 0xd8800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/225.print b/tests/snapshots/testsuite/simd_const.wast/225.print new file mode 100644 index 0000000000..29884ad42c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/225.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x58800003 0x58800003 0x58800003 0x58800003 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/227.print b/tests/snapshots/testsuite/simd_const.wast/227.print new file mode 100644 index 0000000000..74fb958bbb --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/227.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xd8800003 0xd8800003 0xd8800003 0xd8800003 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/229.print b/tests/snapshots/testsuite/simd_const.wast/229.print new file mode 100644 index 0000000000..d6fa221845 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/229.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x58800000 0x58800000 0x58800000 0x58800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/23.print b/tests/snapshots/testsuite/simd_const.wast/23.print new file mode 100644 index 0000000000..6f785fb2d2 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/23.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000000 0x80000000 0x00000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/231.print b/tests/snapshots/testsuite/simd_const.wast/231.print new file mode 100644 index 0000000000..e6d4794afc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/231.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xd8800000 0xd8800000 0xd8800000 0xd8800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/233.print b/tests/snapshots/testsuite/simd_const.wast/233.print new file mode 100644 index 0000000000..3ac3c4abe4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/233.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x58800002 0x58800002 0x58800002 0x58800002 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/235.print b/tests/snapshots/testsuite/simd_const.wast/235.print new file mode 100644 index 0000000000..5b843a4230 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/235.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xd8800002 0xd8800002 0xd8800002 0xd8800002 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/237.print b/tests/snapshots/testsuite/simd_const.wast/237.print new file mode 100644 index 0000000000..d6fa221845 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/237.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x58800000 0x58800000 0x58800000 0x58800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/239.print b/tests/snapshots/testsuite/simd_const.wast/239.print new file mode 100644 index 0000000000..e6d4794afc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/239.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xd8800000 0xd8800000 0xd8800000 0xd8800000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/24.print b/tests/snapshots/testsuite/simd_const.wast/24.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/24.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/241.print b/tests/snapshots/testsuite/simd_const.wast/241.print new file mode 100644 index 0000000000..3ac3c4abe4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/241.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x58800002 0x58800002 0x58800002 0x58800002 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/243.print b/tests/snapshots/testsuite/simd_const.wast/243.print new file mode 100644 index 0000000000..5b843a4230 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/243.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xd8800002 0xd8800002 0xd8800002 0xd8800002 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/245.print b/tests/snapshots/testsuite/simd_const.wast/245.print new file mode 100644 index 0000000000..ddaf89798b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/245.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/247.print b/tests/snapshots/testsuite/simd_const.wast/247.print new file mode 100644 index 0000000000..d44438ac20 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/247.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x80000000 0x80000000 0x80000000 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/249.print b/tests/snapshots/testsuite/simd_const.wast/249.print new file mode 100644 index 0000000000..298c7fc4a8 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/249.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000003 0x00000003 0x00000003 0x00000003 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/25.print b/tests/snapshots/testsuite/simd_const.wast/25.print new file mode 100644 index 0000000000..6f785fb2d2 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/25.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000000 0x80000000 0x00000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/251.print b/tests/snapshots/testsuite/simd_const.wast/251.print new file mode 100644 index 0000000000..22f5499246 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/251.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x80000003 0x80000003 0x80000003 0x80000003 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/253.print b/tests/snapshots/testsuite/simd_const.wast/253.print new file mode 100644 index 0000000000..9ca6e90809 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/253.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x7f7fffff 0x7f7fffff 0x7f7fffff 0x7f7fffff + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/255.print b/tests/snapshots/testsuite/simd_const.wast/255.print new file mode 100644 index 0000000000..f1ecda85f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/255.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xff7fffff 0xff7fffff 0xff7fffff 0xff7fffff + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/257.print b/tests/snapshots/testsuite/simd_const.wast/257.print new file mode 100644 index 0000000000..9ca6e90809 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/257.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x7f7fffff 0x7f7fffff 0x7f7fffff 0x7f7fffff + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/259.print b/tests/snapshots/testsuite/simd_const.wast/259.print new file mode 100644 index 0000000000..f1ecda85f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/259.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xff7fffff 0xff7fffff 0xff7fffff 0xff7fffff + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/26.print b/tests/snapshots/testsuite/simd_const.wast/26.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/26.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/261.print b/tests/snapshots/testsuite/simd_const.wast/261.print new file mode 100644 index 0000000000..25558a4d1d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/261.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102884;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/263.print b/tests/snapshots/testsuite/simd_const.wast/263.print new file mode 100644 index 0000000000..456f0919c0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/263.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102884;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/265.print b/tests/snapshots/testsuite/simd_const.wast/265.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/265.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/267.print b/tests/snapshots/testsuite/simd_const.wast/267.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/267.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/269.print b/tests/snapshots/testsuite/simd_const.wast/269.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/269.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/27.print b/tests/snapshots/testsuite/simd_const.wast/27.print new file mode 100644 index 0000000000..6f785fb2d2 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/27.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000000 0x80000000 0x00000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/271.print b/tests/snapshots/testsuite/simd_const.wast/271.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/271.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/273.print b/tests/snapshots/testsuite/simd_const.wast/273.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/273.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/275.print b/tests/snapshots/testsuite/simd_const.wast/275.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/275.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/277.print b/tests/snapshots/testsuite/simd_const.wast/277.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/277.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/279.print b/tests/snapshots/testsuite/simd_const.wast/279.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/279.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/28.print b/tests/snapshots/testsuite/simd_const.wast/28.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/28.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/281.print b/tests/snapshots/testsuite/simd_const.wast/281.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/281.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/283.print b/tests/snapshots/testsuite/simd_const.wast/283.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/283.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/285.print b/tests/snapshots/testsuite/simd_const.wast/285.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/285.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/287.print b/tests/snapshots/testsuite/simd_const.wast/287.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/287.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/289.print b/tests/snapshots/testsuite/simd_const.wast/289.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/289.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/29.print b/tests/snapshots/testsuite/simd_const.wast/29.print new file mode 100644 index 0000000000..6f785fb2d2 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/29.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000000 0x80000000 0x00000000 0x80000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/291.print b/tests/snapshots/testsuite/simd_const.wast/291.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/291.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/293.print b/tests/snapshots/testsuite/simd_const.wast/293.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/293.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/295.print b/tests/snapshots/testsuite/simd_const.wast/295.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/295.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/297.print b/tests/snapshots/testsuite/simd_const.wast/297.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/297.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/299.print b/tests/snapshots/testsuite/simd_const.wast/299.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/299.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/3.print b/tests/snapshots/testsuite/simd_const.wast/3.print new file mode 100644 index 0000000000..3b342dc473 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/3.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80808080 0x80808080 0x80808080 0x80808080 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/30.print b/tests/snapshots/testsuite/simd_const.wast/30.print new file mode 100644 index 0000000000..b2e8abf2dc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/30.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x075bcd15 0x00000000 0x075bcd15 0x00000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/301.print b/tests/snapshots/testsuite/simd_const.wast/301.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/301.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/303.print b/tests/snapshots/testsuite/simd_const.wast/303.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/303.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/305.print b/tests/snapshots/testsuite/simd_const.wast/305.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/305.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/307.print b/tests/snapshots/testsuite/simd_const.wast/307.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/307.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/309.print b/tests/snapshots/testsuite/simd_const.wast/309.print new file mode 100644 index 0000000000..6de7afcf83 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/309.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000003p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028857;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/31.print b/tests/snapshots/testsuite/simd_const.wast/31.print new file mode 100644 index 0000000000..51bf502315 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/31.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xadefbcef 0x01256789 0xadefbcef 0x01256789 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/311.print b/tests/snapshots/testsuite/simd_const.wast/311.print new file mode 100644 index 0000000000..ecbedb246f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/311.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000003p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028857;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/313.print b/tests/snapshots/testsuite/simd_const.wast/313.print new file mode 100644 index 0000000000..25558a4d1d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/313.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102884;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/315.print b/tests/snapshots/testsuite/simd_const.wast/315.print new file mode 100644 index 0000000000..456f0919c0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/315.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102884;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/317.print b/tests/snapshots/testsuite/simd_const.wast/317.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/317.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/319.print b/tests/snapshots/testsuite/simd_const.wast/319.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/319.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/32.print b/tests/snapshots/testsuite/simd_const.wast/32.print new file mode 100644 index 0000000000..d802c2aac6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/32.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x7f000000 0x7f000000 0x7f000000 0x7f000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/321.print b/tests/snapshots/testsuite/simd_const.wast/321.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/321.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/323.print b/tests/snapshots/testsuite/simd_const.wast/323.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/323.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/325.print b/tests/snapshots/testsuite/simd_const.wast/325.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/325.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/327.print b/tests/snapshots/testsuite/simd_const.wast/327.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/327.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/329.print b/tests/snapshots/testsuite/simd_const.wast/329.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/329.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/33.print b/tests/snapshots/testsuite/simd_const.wast/33.print new file mode 100644 index 0000000000..8ae401ccb9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/33.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xff000000 0xff000000 0xff000000 0xff000000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/331.print b/tests/snapshots/testsuite/simd_const.wast/331.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/331.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/333.print b/tests/snapshots/testsuite/simd_const.wast/333.print new file mode 100644 index 0000000000..6744b429ea --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/333.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/335.print b/tests/snapshots/testsuite/simd_const.wast/335.print new file mode 100644 index 0000000000..8ee9bd7ef4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/335.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028847;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/337.print b/tests/snapshots/testsuite/simd_const.wast/337.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/337.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/339.print b/tests/snapshots/testsuite/simd_const.wast/339.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/339.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/34.print b/tests/snapshots/testsuite/simd_const.wast/34.print new file mode 100644 index 0000000000..baabcc4e37 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/34.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x7e967699 0x7e967699 0x7e967699 0x7e967699 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/341.print b/tests/snapshots/testsuite/simd_const.wast/341.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/341.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/343.print b/tests/snapshots/testsuite/simd_const.wast/343.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/343.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/345.print b/tests/snapshots/testsuite/simd_const.wast/345.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/345.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/347.print b/tests/snapshots/testsuite/simd_const.wast/347.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/347.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/349.print b/tests/snapshots/testsuite/simd_const.wast/349.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/349.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/35.print b/tests/snapshots/testsuite/simd_const.wast/35.print new file mode 100644 index 0000000000..a9db4f0140 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/35.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xfe967699 0xfe967699 0xfe967699 0xfe967699 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/351.print b/tests/snapshots/testsuite/simd_const.wast/351.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/351.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/353.print b/tests/snapshots/testsuite/simd_const.wast/353.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/353.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/355.print b/tests/snapshots/testsuite/simd_const.wast/355.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/355.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/357.print b/tests/snapshots/testsuite/simd_const.wast/357.print new file mode 100644 index 0000000000..65f025428d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/357.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p-600 (;=0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/359.print b/tests/snapshots/testsuite/simd_const.wast/359.print new file mode 100644 index 0000000000..12f1704c7c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/359.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p-600 (;=-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002409919865102885;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/36.print b/tests/snapshots/testsuite/simd_const.wast/36.print new file mode 100644 index 0000000000..4e017b383e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/36.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x7f7fffff 0x7f7fffff 0x7f7fffff 0x7f7fffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/361.print b/tests/snapshots/testsuite/simd_const.wast/361.print new file mode 100644 index 0000000000..6de7afcf83 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/361.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000003p-600 (;=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028857;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/363.print b/tests/snapshots/testsuite/simd_const.wast/363.print new file mode 100644 index 0000000000..ecbedb246f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/363.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000003p-600 (;=-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024099198651028857;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/365.print b/tests/snapshots/testsuite/simd_const.wast/365.print new file mode 100644 index 0000000000..ad96598516 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/365.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1p+999 (;=5357543035931337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/367.print b/tests/snapshots/testsuite/simd_const.wast/367.print new file mode 100644 index 0000000000..29e90b4215 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/367.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1p+999 (;=-5357543035931337000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/369.print b/tests/snapshots/testsuite/simd_const.wast/369.print new file mode 100644 index 0000000000..d45faab061 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/369.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+999 (;=5357543035931338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/37.print b/tests/snapshots/testsuite/simd_const.wast/37.print new file mode 100644 index 0000000000..8f89b8e116 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/37.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xff7fffff 0xff7fffff 0xff7fffff 0xff7fffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/371.print b/tests/snapshots/testsuite/simd_const.wast/371.print new file mode 100644 index 0000000000..714912a936 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/371.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+999 (;=-5357543035931338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/373.print b/tests/snapshots/testsuite/simd_const.wast/373.print new file mode 100644 index 0000000000..d45faab061 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/373.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000001p+999 (;=5357543035931338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/375.print b/tests/snapshots/testsuite/simd_const.wast/375.print new file mode 100644 index 0000000000..714912a936 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/375.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000001p+999 (;=-5357543035931338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/377.print b/tests/snapshots/testsuite/simd_const.wast/377.print new file mode 100644 index 0000000000..38f2cf1bae --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/377.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const 0x1.0000000000002p+999 (;=5357543035931339000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/379.print b/tests/snapshots/testsuite/simd_const.wast/379.print new file mode 100644 index 0000000000..78f5e077b2 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/379.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + f64.const -0x1.0000000000002p+999 (;=-5357543035931339000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/38.print b/tests/snapshots/testsuite/simd_const.wast/38.print new file mode 100644 index 0000000000..7290e22d50 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/38.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x7f800001 0x7f800001 0x7f800001 0x7f800001 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/381.print b/tests/snapshots/testsuite/simd_const.wast/381.print new file mode 100644 index 0000000000..367d07d273 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/381.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x65700000 0x00000000 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/383.print b/tests/snapshots/testsuite/simd_const.wast/383.print new file mode 100644 index 0000000000..98c4bbdf0b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/383.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0xe5700000 0x00000000 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/385.print b/tests/snapshots/testsuite/simd_const.wast/385.print new file mode 100644 index 0000000000..e5351d3676 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/385.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x65700000 0x00000001 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/387.print b/tests/snapshots/testsuite/simd_const.wast/387.print new file mode 100644 index 0000000000..55f3b01e2e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/387.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xe5700000 0x00000001 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/389.print b/tests/snapshots/testsuite/simd_const.wast/389.print new file mode 100644 index 0000000000..e5351d3676 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/389.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x65700000 0x00000001 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/39.print b/tests/snapshots/testsuite/simd_const.wast/39.print new file mode 100644 index 0000000000..9cf76ab1b4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/39.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x7fffffff 0x7fffffff 0x7fffffff 0x7fffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/391.print b/tests/snapshots/testsuite/simd_const.wast/391.print new file mode 100644 index 0000000000..55f3b01e2e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/391.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xe5700000 0x00000001 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/393.print b/tests/snapshots/testsuite/simd_const.wast/393.print new file mode 100644 index 0000000000..e5351d3676 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/393.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x65700000 0x00000001 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/395.print b/tests/snapshots/testsuite/simd_const.wast/395.print new file mode 100644 index 0000000000..55f3b01e2e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/395.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xe5700000 0x00000001 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/397.print b/tests/snapshots/testsuite/simd_const.wast/397.print new file mode 100644 index 0000000000..e5351d3676 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/397.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x65700000 0x00000001 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/399.print b/tests/snapshots/testsuite/simd_const.wast/399.print new file mode 100644 index 0000000000..55f3b01e2e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/399.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xe5700000 0x00000001 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/4.print b/tests/snapshots/testsuite/simd_const.wast/4.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/4.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/40.print b/tests/snapshots/testsuite/simd_const.wast/40.print new file mode 100644 index 0000000000..cf63e16295 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/40.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x4ceb79a3 0x4ceb79a3 0x4ceb79a3 0x4ceb79a3 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/401.print b/tests/snapshots/testsuite/simd_const.wast/401.print new file mode 100644 index 0000000000..e5351d3676 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/401.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x65700000 0x00000001 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/403.print b/tests/snapshots/testsuite/simd_const.wast/403.print new file mode 100644 index 0000000000..55f3b01e2e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/403.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xe5700000 0x00000001 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/405.print b/tests/snapshots/testsuite/simd_const.wast/405.print new file mode 100644 index 0000000000..e26238aee3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/405.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x65700000 0x00000002 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/407.print b/tests/snapshots/testsuite/simd_const.wast/407.print new file mode 100644 index 0000000000..bab521fc1e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/407.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xe5700000 0x00000002 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/409.print b/tests/snapshots/testsuite/simd_const.wast/409.print new file mode 100644 index 0000000000..e26238aee3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/409.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x65700000 0x00000002 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/41.print b/tests/snapshots/testsuite/simd_const.wast/41.print new file mode 100644 index 0000000000..251b80073f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/41.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/411.print b/tests/snapshots/testsuite/simd_const.wast/411.print new file mode 100644 index 0000000000..bab521fc1e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/411.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xe5700000 0x00000002 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/413.print b/tests/snapshots/testsuite/simd_const.wast/413.print new file mode 100644 index 0000000000..e26238aee3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/413.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x65700000 0x00000002 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/415.print b/tests/snapshots/testsuite/simd_const.wast/415.print new file mode 100644 index 0000000000..bab521fc1e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/415.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xe5700000 0x00000002 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/417.print b/tests/snapshots/testsuite/simd_const.wast/417.print new file mode 100644 index 0000000000..e26238aee3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/417.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x65700000 0x00000002 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/419.print b/tests/snapshots/testsuite/simd_const.wast/419.print new file mode 100644 index 0000000000..bab521fc1e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/419.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xe5700000 0x00000002 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/42.print b/tests/snapshots/testsuite/simd_const.wast/42.print new file mode 100644 index 0000000000..251b80073f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/42.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/421.print b/tests/snapshots/testsuite/simd_const.wast/421.print new file mode 100644 index 0000000000..e26238aee3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/421.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x65700000 0x00000002 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/423.print b/tests/snapshots/testsuite/simd_const.wast/423.print new file mode 100644 index 0000000000..bab521fc1e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/423.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xe5700000 0x00000002 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/425.print b/tests/snapshots/testsuite/simd_const.wast/425.print new file mode 100644 index 0000000000..e26238aee3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/425.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x65700000 0x00000002 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/427.print b/tests/snapshots/testsuite/simd_const.wast/427.print new file mode 100644 index 0000000000..bab521fc1e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/427.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xe5700000 0x00000002 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/429.print b/tests/snapshots/testsuite/simd_const.wast/429.print new file mode 100644 index 0000000000..e26238aee3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/429.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x65700000 0x00000002 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/43.print b/tests/snapshots/testsuite/simd_const.wast/43.print new file mode 100644 index 0000000000..b12d91dddd --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/43.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x2d592fff 0x2d592fff 0x2d592fff 0x2d592fff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/431.print b/tests/snapshots/testsuite/simd_const.wast/431.print new file mode 100644 index 0000000000..bab521fc1e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/431.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xe5700000 0x00000002 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/433.print b/tests/snapshots/testsuite/simd_const.wast/433.print new file mode 100644 index 0000000000..4960cea0d9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/433.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000003 0x65700000 0x00000003 0x65700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/435.print b/tests/snapshots/testsuite/simd_const.wast/435.print new file mode 100644 index 0000000000..639ea6a65d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/435.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000003 0xe5700000 0x00000003 0xe5700000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/437.print b/tests/snapshots/testsuite/simd_const.wast/437.print new file mode 100644 index 0000000000..1a78b39204 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/437.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x46000000 0x00000000 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/439.print b/tests/snapshots/testsuite/simd_const.wast/439.print new file mode 100644 index 0000000000..1e3bc5da11 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/439.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0xc6000000 0x00000000 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/44.print b/tests/snapshots/testsuite/simd_const.wast/44.print new file mode 100644 index 0000000000..cf63e16295 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/44.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x4ceb79a3 0x4ceb79a3 0x4ceb79a3 0x4ceb79a3 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/441.print b/tests/snapshots/testsuite/simd_const.wast/441.print new file mode 100644 index 0000000000..5a3712fca4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/441.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x46000000 0x00000001 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/443.print b/tests/snapshots/testsuite/simd_const.wast/443.print new file mode 100644 index 0000000000..481b2ffe9e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/443.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xc6000000 0x00000001 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/445.print b/tests/snapshots/testsuite/simd_const.wast/445.print new file mode 100644 index 0000000000..5a3712fca4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/445.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x46000000 0x00000001 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/447.print b/tests/snapshots/testsuite/simd_const.wast/447.print new file mode 100644 index 0000000000..481b2ffe9e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/447.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xc6000000 0x00000001 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/449.print b/tests/snapshots/testsuite/simd_const.wast/449.print new file mode 100644 index 0000000000..5a3712fca4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/449.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x46000000 0x00000001 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/45.print b/tests/snapshots/testsuite/simd_const.wast/45.print new file mode 100644 index 0000000000..251b80073f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/45.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/451.print b/tests/snapshots/testsuite/simd_const.wast/451.print new file mode 100644 index 0000000000..481b2ffe9e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/451.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xc6000000 0x00000001 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/453.print b/tests/snapshots/testsuite/simd_const.wast/453.print new file mode 100644 index 0000000000..5a3712fca4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/453.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x46000000 0x00000001 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/455.print b/tests/snapshots/testsuite/simd_const.wast/455.print new file mode 100644 index 0000000000..481b2ffe9e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/455.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xc6000000 0x00000001 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/457.print b/tests/snapshots/testsuite/simd_const.wast/457.print new file mode 100644 index 0000000000..5a3712fca4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/457.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x46000000 0x00000001 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/459.print b/tests/snapshots/testsuite/simd_const.wast/459.print new file mode 100644 index 0000000000..481b2ffe9e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/459.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xc6000000 0x00000001 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/46.print b/tests/snapshots/testsuite/simd_const.wast/46.print new file mode 100644 index 0000000000..251b80073f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/46.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/461.print b/tests/snapshots/testsuite/simd_const.wast/461.print new file mode 100644 index 0000000000..a8fb2739f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/461.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x46000000 0x00000002 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/463.print b/tests/snapshots/testsuite/simd_const.wast/463.print new file mode 100644 index 0000000000..1c8778c084 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/463.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xc6000000 0x00000002 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/465.print b/tests/snapshots/testsuite/simd_const.wast/465.print new file mode 100644 index 0000000000..a8fb2739f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/465.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x46000000 0x00000002 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/467.print b/tests/snapshots/testsuite/simd_const.wast/467.print new file mode 100644 index 0000000000..1c8778c084 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/467.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xc6000000 0x00000002 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/469.print b/tests/snapshots/testsuite/simd_const.wast/469.print new file mode 100644 index 0000000000..a8fb2739f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/469.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x46000000 0x00000002 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/47.print b/tests/snapshots/testsuite/simd_const.wast/47.print new file mode 100644 index 0000000000..b12d91dddd --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/47.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x2d592fff 0x2d592fff 0x2d592fff 0x2d592fff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/471.print b/tests/snapshots/testsuite/simd_const.wast/471.print new file mode 100644 index 0000000000..1c8778c084 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/471.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xc6000000 0x00000002 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/473.print b/tests/snapshots/testsuite/simd_const.wast/473.print new file mode 100644 index 0000000000..a8fb2739f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/473.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x46000000 0x00000002 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/475.print b/tests/snapshots/testsuite/simd_const.wast/475.print new file mode 100644 index 0000000000..1c8778c084 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/475.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xc6000000 0x00000002 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/477.print b/tests/snapshots/testsuite/simd_const.wast/477.print new file mode 100644 index 0000000000..a8fb2739f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/477.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x46000000 0x00000002 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/479.print b/tests/snapshots/testsuite/simd_const.wast/479.print new file mode 100644 index 0000000000..1c8778c084 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/479.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xc6000000 0x00000002 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/48.print b/tests/snapshots/testsuite/simd_const.wast/48.print new file mode 100644 index 0000000000..cf63e16295 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/48.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x4ceb79a3 0x4ceb79a3 0x4ceb79a3 0x4ceb79a3 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/481.print b/tests/snapshots/testsuite/simd_const.wast/481.print new file mode 100644 index 0000000000..a8fb2739f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/481.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x46000000 0x00000002 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/483.print b/tests/snapshots/testsuite/simd_const.wast/483.print new file mode 100644 index 0000000000..1c8778c084 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/483.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xc6000000 0x00000002 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/485.print b/tests/snapshots/testsuite/simd_const.wast/485.print new file mode 100644 index 0000000000..a8fb2739f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/485.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x46000000 0x00000002 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/487.print b/tests/snapshots/testsuite/simd_const.wast/487.print new file mode 100644 index 0000000000..1c8778c084 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/487.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xc6000000 0x00000002 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/489.print b/tests/snapshots/testsuite/simd_const.wast/489.print new file mode 100644 index 0000000000..c85d982999 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/489.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000003 0x46000000 0x00000003 0x46000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/49.print b/tests/snapshots/testsuite/simd_const.wast/49.print new file mode 100644 index 0000000000..251b80073f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/49.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/491.print b/tests/snapshots/testsuite/simd_const.wast/491.print new file mode 100644 index 0000000000..8c2b66f5bb --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/491.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000003 0xc6000000 0x00000003 0xc6000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/493.print b/tests/snapshots/testsuite/simd_const.wast/493.print new file mode 100644 index 0000000000..c8087dc271 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/493.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x43b00000 0x00000000 0x43b00000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/495.print b/tests/snapshots/testsuite/simd_const.wast/495.print new file mode 100644 index 0000000000..5426b9f0bb --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/495.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0xc3b00000 0x00000000 0xc3b00000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/497.print b/tests/snapshots/testsuite/simd_const.wast/497.print new file mode 100644 index 0000000000..baaaf0e8f7 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/497.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x43b00000 0x00000001 0x43b00000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/499.print b/tests/snapshots/testsuite/simd_const.wast/499.print new file mode 100644 index 0000000000..61adce5fa0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/499.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xc3b00000 0x00000001 0xc3b00000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/5.print b/tests/snapshots/testsuite/simd_const.wast/5.print new file mode 100644 index 0000000000..f6a834c1a9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/5.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80008000 0x80008000 0x80008000 0x80008000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/50.print b/tests/snapshots/testsuite/simd_const.wast/50.print new file mode 100644 index 0000000000..251b80073f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/50.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b 0x6c7f4d7b + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/501.print b/tests/snapshots/testsuite/simd_const.wast/501.print new file mode 100644 index 0000000000..baaaf0e8f7 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/501.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x43b00000 0x00000001 0x43b00000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/503.print b/tests/snapshots/testsuite/simd_const.wast/503.print new file mode 100644 index 0000000000..61adce5fa0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/503.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0xc3b00000 0x00000001 0xc3b00000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/505.print b/tests/snapshots/testsuite/simd_const.wast/505.print new file mode 100644 index 0000000000..fb0398fbae --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/505.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x43b00000 0x00000002 0x43b00000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/507.print b/tests/snapshots/testsuite/simd_const.wast/507.print new file mode 100644 index 0000000000..d47c5e8f38 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/507.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0xc3b00000 0x00000002 0xc3b00000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/509.print b/tests/snapshots/testsuite/simd_const.wast/509.print new file mode 100644 index 0000000000..ddaf89798b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/509.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/51.print b/tests/snapshots/testsuite/simd_const.wast/51.print new file mode 100644 index 0000000000..b12d91dddd --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/51.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x2d592fff 0x2d592fff 0x2d592fff 0x2d592fff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/511.print b/tests/snapshots/testsuite/simd_const.wast/511.print new file mode 100644 index 0000000000..d53ac89104 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/511.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x80000000 0x00000000 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/513.print b/tests/snapshots/testsuite/simd_const.wast/513.print new file mode 100644 index 0000000000..de67dfbf1b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/513.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x00000000 0x00000001 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/515.print b/tests/snapshots/testsuite/simd_const.wast/515.print new file mode 100644 index 0000000000..2f6eb8ca92 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/515.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x80000000 0x00000001 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/517.print b/tests/snapshots/testsuite/simd_const.wast/517.print new file mode 100644 index 0000000000..de67dfbf1b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/517.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x00000000 0x00000001 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/519.print b/tests/snapshots/testsuite/simd_const.wast/519.print new file mode 100644 index 0000000000..2f6eb8ca92 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/519.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x80000000 0x00000001 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/52.print b/tests/snapshots/testsuite/simd_const.wast/52.print new file mode 100644 index 0000000000..52208eeaf6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/52.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b91a2b4 0x5b91a2b4 0x5b91a2b4 0x5b91a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/521.print b/tests/snapshots/testsuite/simd_const.wast/521.print new file mode 100644 index 0000000000..de67dfbf1b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/521.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x00000000 0x00000001 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/523.print b/tests/snapshots/testsuite/simd_const.wast/523.print new file mode 100644 index 0000000000..2f6eb8ca92 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/523.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x80000000 0x00000001 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/525.print b/tests/snapshots/testsuite/simd_const.wast/525.print new file mode 100644 index 0000000000..de67dfbf1b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/525.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x00000000 0x00000001 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/527.print b/tests/snapshots/testsuite/simd_const.wast/527.print new file mode 100644 index 0000000000..2f6eb8ca92 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/527.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x80000000 0x00000001 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/529.print b/tests/snapshots/testsuite/simd_const.wast/529.print new file mode 100644 index 0000000000..de67dfbf1b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/529.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x00000000 0x00000001 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/53.print b/tests/snapshots/testsuite/simd_const.wast/53.print new file mode 100644 index 0000000000..e2ca00586e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/53.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6511a2b4 0x6511a2b4 0x6511a2b4 0x6511a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/531.print b/tests/snapshots/testsuite/simd_const.wast/531.print new file mode 100644 index 0000000000..2f6eb8ca92 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/531.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x80000000 0x00000001 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/533.print b/tests/snapshots/testsuite/simd_const.wast/533.print new file mode 100644 index 0000000000..f9665b9a33 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/533.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x00000000 0x00000002 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/535.print b/tests/snapshots/testsuite/simd_const.wast/535.print new file mode 100644 index 0000000000..b9038e9b2b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/535.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x80000000 0x00000002 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/537.print b/tests/snapshots/testsuite/simd_const.wast/537.print new file mode 100644 index 0000000000..f9665b9a33 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/537.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x00000000 0x00000002 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/539.print b/tests/snapshots/testsuite/simd_const.wast/539.print new file mode 100644 index 0000000000..b9038e9b2b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/539.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x80000000 0x00000002 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/54.print b/tests/snapshots/testsuite/simd_const.wast/54.print new file mode 100644 index 0000000000..e2ca00586e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/54.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6511a2b4 0x6511a2b4 0x6511a2b4 0x6511a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/541.print b/tests/snapshots/testsuite/simd_const.wast/541.print new file mode 100644 index 0000000000..f9665b9a33 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/541.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x00000000 0x00000002 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/543.print b/tests/snapshots/testsuite/simd_const.wast/543.print new file mode 100644 index 0000000000..b9038e9b2b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/543.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x80000000 0x00000002 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/545.print b/tests/snapshots/testsuite/simd_const.wast/545.print new file mode 100644 index 0000000000..f9665b9a33 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/545.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x00000000 0x00000002 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/547.print b/tests/snapshots/testsuite/simd_const.wast/547.print new file mode 100644 index 0000000000..b9038e9b2b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/547.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x80000000 0x00000002 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/549.print b/tests/snapshots/testsuite/simd_const.wast/549.print new file mode 100644 index 0000000000..f9665b9a33 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/549.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x00000000 0x00000002 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/55.print b/tests/snapshots/testsuite/simd_const.wast/55.print new file mode 100644 index 0000000000..23461dbe80 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/55.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5211a2b4 0x5211a2b4 0x5211a2b4 0x5211a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/551.print b/tests/snapshots/testsuite/simd_const.wast/551.print new file mode 100644 index 0000000000..b9038e9b2b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/551.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x80000000 0x00000002 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/553.print b/tests/snapshots/testsuite/simd_const.wast/553.print new file mode 100644 index 0000000000..f9665b9a33 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/553.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x00000000 0x00000002 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/555.print b/tests/snapshots/testsuite/simd_const.wast/555.print new file mode 100644 index 0000000000..b9038e9b2b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/555.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x80000000 0x00000002 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/557.print b/tests/snapshots/testsuite/simd_const.wast/557.print new file mode 100644 index 0000000000..f9665b9a33 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/557.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x00000000 0x00000002 0x00000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/559.print b/tests/snapshots/testsuite/simd_const.wast/559.print new file mode 100644 index 0000000000..b9038e9b2b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/559.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000002 0x80000000 0x00000002 0x80000000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/56.print b/tests/snapshots/testsuite/simd_const.wast/56.print new file mode 100644 index 0000000000..52208eeaf6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/56.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b91a2b4 0x5b91a2b4 0x5b91a2b4 0x5b91a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/561.print b/tests/snapshots/testsuite/simd_const.wast/561.print new file mode 100644 index 0000000000..f0c8d5e7c8 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/561.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000003 0x00100000 0x00000003 0x00100000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/563.print b/tests/snapshots/testsuite/simd_const.wast/563.print new file mode 100644 index 0000000000..b9072e2627 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/563.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000003 0x80100000 0x00000003 0x80100000 + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/565.print b/tests/snapshots/testsuite/simd_const.wast/565.print new file mode 100644 index 0000000000..99b08ec330 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/565.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xffffffff 0x7fefffff 0xffffffff 0x7fefffff + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/567.print b/tests/snapshots/testsuite/simd_const.wast/567.print new file mode 100644 index 0000000000..70027256e8 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/567.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xffffffff 0xffefffff 0xffffffff 0xffefffff + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/569.print b/tests/snapshots/testsuite/simd_const.wast/569.print new file mode 100644 index 0000000000..99b08ec330 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/569.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xffffffff 0x7fefffff 0xffffffff 0x7fefffff + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/57.print b/tests/snapshots/testsuite/simd_const.wast/57.print new file mode 100644 index 0000000000..e2ca00586e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/57.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6511a2b4 0x6511a2b4 0x6511a2b4 0x6511a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/571.print b/tests/snapshots/testsuite/simd_const.wast/571.print new file mode 100644 index 0000000000..70027256e8 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/571.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xffffffff 0xffefffff 0xffffffff 0xffefffff + ) + (export "f" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/573.print b/tests/snapshots/testsuite/simd_const.wast/573.print new file mode 100644 index 0000000000..df1fea8416 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/573.print @@ -0,0 +1,154 @@ +(module + (type $sig (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (result v128))) + (type (;2;) (func)) + (func (;0;) (type 1) (result v128) + block (result v128) ;; label = @1 + v128.const i32x4 0x03020100 0x07060504 0x0b0a0908 0x0f0e0d0c + br 0 (;@1;) + end + ) + (func (;1;) (type 1) (result v128) + block (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;2;) (type 1) (result v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + return + ) + (func (;3;) (type 1) (result v128) + i32.const 1 + if (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + else + v128.const i32x4 0x00000003 0x00000002 0x00000001 0x00000000 + end + ) + (func (;4;) (type 1) (result v128) + i32.const 0 + if (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + else + v128.const i32x4 0x00000003 0x00000002 0x00000001 0x00000000 + end + ) + (func $f (;5;) (type $sig) (param v128 v128 v128) (result v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + ) + (func (;6;) (type 1) (result v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + call $f + ) + (func (;7;) (type 1) (result v128) + block (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + end + ) + (func (;8;) (type 1) (result v128) + loop (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + end + ) + (func (;9;) (type 2) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + drop + ) + (func (;10;) (type 1) (result v128) + block (result v128) ;; label = @1 + v128.const i32x4 0x07060504 0x03020100 0x0f0e0d0c 0x0b0a0908 + br 0 (;@1;) + end + ) + (func (;11;) (type 1) (result v128) + block (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;12;) (type 1) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + return + ) + (func (;13;) (type 1) (result v128) + i32.const 1 + if (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + else + v128.const i32x4 0x00000001 0x00000000 0x00000000 0x00000000 + end + ) + (func (;14;) (type 1) (result v128) + i32.const 0 + if (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + else + v128.const i32x4 0x00000001 0x00000000 0x00000000 0x00000000 + end + ) + (func $f2 (;15;) (type $sig) (param v128 v128 v128) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + ) + (func (;16;) (type 1) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + call $f2 + ) + (func (;17;) (type 1) (result v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + i32.const 0 + call_indirect (type $sig) + ) + (func (;18;) (type 1) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + i32.const 1 + call_indirect (type $sig) + ) + (func (;19;) (type 1) (result v128) + block (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + end + ) + (func (;20;) (type 1) (result v128) + loop (result v128) ;; label = @1 + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + end + ) + (func (;21;) (type 2) + v128.const i32x4 0x00000000 0x00000000 0x00000001 0x00000000 + drop + ) + (table (;0;) 2 2 funcref) + (memory (;0;) 1) + (export "as-br-retval" (func 0)) + (export "as-br_if-retval" (func 1)) + (export "as-return-retval" (func 2)) + (export "as-if-then-retval" (func 3)) + (export "as-if-else-retval" (func 4)) + (export "as-call-param" (func 6)) + (export "as-block-retval" (func 7)) + (export "as-loop-retval" (func 8)) + (export "as-drop-operand" (func 9)) + (export "as-br-retval2" (func 10)) + (export "as-br_if-retval2" (func 11)) + (export "as-return-retval2" (func 12)) + (export "as-if-then-retval2" (func 13)) + (export "as-if-else-retval2" (func 14)) + (export "as-call-param2" (func 16)) + (export "as-call_indirect-param" (func 17)) + (export "as-call_indirect-param2" (func 18)) + (export "as-block-retval2" (func 19)) + (export "as-loop-retval2" (func 20)) + (export "as-drop-operand2" (func 21)) + (elem (;0;) (i32.const 0) func $f $f2) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/58.print b/tests/snapshots/testsuite/simd_const.wast/58.print new file mode 100644 index 0000000000..e2ca00586e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/58.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6511a2b4 0x6511a2b4 0x6511a2b4 0x6511a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/59.print b/tests/snapshots/testsuite/simd_const.wast/59.print new file mode 100644 index 0000000000..23461dbe80 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/59.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5211a2b4 0x5211a2b4 0x5211a2b4 0x5211a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/594.print b/tests/snapshots/testsuite/simd_const.wast/594.print new file mode 100644 index 0000000000..ddfc3cca98 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/594.print @@ -0,0 +1,44 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (type (;1;) (func (result v128))) + (func (;0;) (type 0) (param $0 v128) (result v128) + (local v128 v128 v128 v128) + local.get $0 + local.set $0 + local.get $0 + ) + (func (;1;) (type 0) (param $0 v128) (result v128) + (local v128 v128 v128 v128) + local.get $0 + local.set $0 + local.get $0 + local.set 1 + local.get 1 + local.set 2 + local.get 2 + local.set 3 + local.get $0 + ) + (func (;2;) (type 0) (param $0 v128) (result v128) + (local v128 v128 v128 v128) + local.get $0 + local.set $0 + local.get $0 + local.set 1 + local.get 1 + local.set 2 + local.get 2 + local.set 3 + local.get 3 + ) + (func (;3;) (type 1) (result v128) + (local v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + local.tee 0 + ) + (memory (;0;) 1) + (export "as-local.set/get-value_0_0" (func 0)) + (export "as-local.set/get-value_0_1" (func 1)) + (export "as-local.set/get-value_3_0" (func 2)) + (export "as-local.tee-value" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/599.print b/tests/snapshots/testsuite/simd_const.wast/599.print new file mode 100644 index 0000000000..b73d813b3a --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/599.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (param v128))) + (type (;1;) (func (param v128 v128))) + (type (;2;) (func (param v128 v128 v128 v128))) + (type (;3;) (func (result v128))) + (func $set_g0 (;0;) (type 0) (param $0 v128) + local.get $0 + global.set $g0 + ) + (func $set_g1_g2 (;1;) (type 1) (param $0 v128) (param $1 v128) + local.get $0 + global.set $g1 + local.get $1 + global.set $g2 + ) + (func $set_g0_g1_g2_g3 (;2;) (type 2) (param $0 v128) (param $1 v128) (param $2 v128) (param $3 v128) + local.get $0 + call $set_g0 + local.get $1 + local.get $2 + call $set_g1_g2 + local.get $3 + global.set $g3 + ) + (func (;3;) (type 3) (result v128) + global.get $g0 + ) + (func (;4;) (type 3) (result v128) + global.get $g1 + ) + (func (;5;) (type 3) (result v128) + global.get $g2 + ) + (func (;6;) (type 3) (result v128) + global.get $g3 + ) + (memory (;0;) 1) + (global $g0 (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003) + (global $g1 (;1;) (mut v128) v128.const i32x4 0x00000004 0x00000005 0x00000006 0x00000007) + (global $g2 (;2;) (mut v128) v128.const i32x4 0x00000008 0x00000009 0x0000000a 0x0000000b) + (global $g3 (;3;) (mut v128) v128.const i32x4 0x0000000c 0x0000000d 0x0000000e 0x0000000f) + (global $g4 (;4;) (mut v128) v128.const i32x4 0x00000010 0x00000011 0x00000012 0x00000013) + (export "as-global.set_value_$g0" (func $set_g0)) + (export "as-global.set_value_$g1_$g2" (func $set_g1_g2)) + (export "as-global.set_value_$g0_$g1_$g2_$g3" (func $set_g0_g1_g2_g3)) + (export "global.get_g0" (func 3)) + (export "global.get_g1" (func 4)) + (export "global.get_g2" (func 5)) + (export "global.get_g3" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/6.print b/tests/snapshots/testsuite/simd_const.wast/6.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/6.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/60.print b/tests/snapshots/testsuite/simd_const.wast/60.print new file mode 100644 index 0000000000..52208eeaf6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/60.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b91a2b4 0x5b91a2b4 0x5b91a2b4 0x5b91a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/605.print b/tests/snapshots/testsuite/simd_const.wast/605.print new file mode 100644 index 0000000000..fe08d7681e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/605.print @@ -0,0 +1,109 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x0badd00d 0x0badd00d 0x0badd00d 0x0badd00d + return + ) + (func (;1;) (type 0) (result v128) + v128.const i32x4 0x7fffffff 0x7fffffff 0x7fffffff 0x7fffffff + return + ) + (func (;2;) (type 0) (result v128) + v128.const i32x4 0x80000001 0x80000001 0x80000001 0x80000001 + return + ) + (func (;3;) (type 0) (result v128) + v128.const i32x4 0x80000000 0x80000000 0x80000000 0x80000000 + v128.const i32x4 0x00000001 0x00000001 0x00000001 0x00000001 + i32x4.add + return + ) + (func (;4;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + return + ) + (func (;5;) (type 0) (result v128) + v128.const i32x4 0x0000000a 0x0000000a 0x0000000a 0x0000000a + return + ) + (func (;6;) (type 0) (result v128) + v128.const i32x4 0x0000002a 0x0000002a 0x0000002a 0x0000002a + return + ) + (func (;7;) (type 0) (result v128) + v128.const i32x4 0x000f4240 0x000f4240 0x000f4240 0x000f4240 + ) + (func (;8;) (type 0) (result v128) + v128.const i32x4 0x000003e8 0x000003e8 0x000003e8 0x000003e8 + ) + (func (;9;) (type 0) (result v128) + v128.const i32x4 0x0a0f0099 0x0a0f0099 0x0a0f0099 0x0a0f0099 + ) + (func (;10;) (type 0) (result v128) + v128.const i32x4 0x0001aa0f 0x0001aa0f 0x0001aa0f 0x0001aa0f + ) + (func (;11;) (type 0) (result v128) + v128.const i32x4 0x0badd00d 0x0badd00d 0x0badd00d 0x0badd00d + return + ) + (func (;12;) (type 0) (result v128) + v128.const i32x4 0xffffffff 0x7fffffff 0xffffffff 0x7fffffff + return + ) + (func (;13;) (type 0) (result v128) + v128.const i32x4 0x00000001 0x80000000 0x00000001 0x80000000 + return + ) + (func (;14;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x80000000 0x00000000 0x80000000 + v128.const i32x4 0x00000001 0x00000000 0x00000001 0x00000000 + i64x2.add + return + ) + (func (;15;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + return + ) + (func (;16;) (type 0) (result v128) + v128.const i32x4 0x0000271a 0x00000000 0x0000271a 0x00000000 + return + ) + (func (;17;) (type 0) (result v128) + v128.const i32x4 0x0000002a 0x00000000 0x0000002a 0x00000000 + return + ) + (func (;18;) (type 0) (result v128) + v128.const i32x4 0x4e72a000 0x00000918 0x4e72a000 0x00000918 + ) + (func (;19;) (type 0) (result v128) + v128.const i32x4 0x00989680 0x00000000 0x00989680 0x00000000 + ) + (func (;20;) (type 0) (result v128) + v128.const i32x4 0x0a0f0099 0x0a0f0099 0x0a0f0099 0x0a0f0099 + ) + (func (;21;) (type 0) (result v128) + v128.const i32x4 0xa0f1aa0f 0x0000001a 0xa0f1aa0f 0x0000001a + ) + (export "i32x4.test" (func 0)) + (export "i32x4.smax" (func 1)) + (export "i32x4.neg_smax" (func 2)) + (export "i32x4.inc_smin" (func 3)) + (export "i32x4.neg_zero" (func 4)) + (export "i32x4.not_octal" (func 5)) + (export "i32x4.plus_sign" (func 6)) + (export "i32x4-dec-sep1" (func 7)) + (export "i32x4-dec-sep2" (func 8)) + (export "i32x4-hex-sep1" (func 9)) + (export "i32x4-hex-sep2" (func 10)) + (export "i64x2.test" (func 11)) + (export "i64x2.smax" (func 12)) + (export "i64x2.neg_smax" (func 13)) + (export "i64x2.inc_smin" (func 14)) + (export "i64x2.neg_zero" (func 15)) + (export "i64x2.not_octal" (func 16)) + (export "i64x2.plus_sign" (func 17)) + (export "i64x2-dec-sep1" (func 18)) + (export "i64x2-dec-sep2" (func 19)) + (export "i64x2-hex-sep1" (func 20)) + (export "i64x2-hex-sep2" (func 21)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/61.print b/tests/snapshots/testsuite/simd_const.wast/61.print new file mode 100644 index 0000000000..e2ca00586e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/61.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6511a2b4 0x6511a2b4 0x6511a2b4 0x6511a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/62.print b/tests/snapshots/testsuite/simd_const.wast/62.print new file mode 100644 index 0000000000..e2ca00586e --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/62.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x6511a2b4 0x6511a2b4 0x6511a2b4 0x6511a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/63.print b/tests/snapshots/testsuite/simd_const.wast/63.print new file mode 100644 index 0000000000..23461dbe80 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/63.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5211a2b4 0x5211a2b4 0x5211a2b4 0x5211a2b4 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/64.print b/tests/snapshots/testsuite/simd_const.wast/64.print new file mode 100644 index 0000000000..cfdeba7b1f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/64.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000000 0x7fe00000 0x00000000 0x7fe00000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/648.print b/tests/snapshots/testsuite/simd_const.wast/648.print new file mode 100644 index 0000000000..f36dad8b08 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/648.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x49742400 0x49742400 0x49742400 0x49742400 + ) + (func (;1;) (type 0) (result v128) + v128.const i32x4 0x447a0000 0x447a0000 0x447a0000 0x447a0000 + ) + (func (;2;) (type 0) (result v128) + v128.const i32x4 0x447ac910 0x447ac910 0x447ac910 0x447ac910 + ) + (func (;3;) (type 0) (result v128) + v128.const i32x4 0x58611996 0x58611996 0x58611996 0x58611996 + ) + (func (;4;) (type 0) (result v128) + v128.const i32x4 0x6e1dae74 0x6e1dae74 0x6e1dae74 0x6e1dae74 + ) + (func (;5;) (type 0) (result v128) + v128.const i32x4 0x4d20f00a 0x4d20f00a 0x4d20f00a 0x4d20f00a + ) + (func (;6;) (type 0) (result v128) + v128.const i32x4 0x47d50780 0x47d50780 0x47d50780 0x47d50780 + ) + (func (;7;) (type 0) (result v128) + v128.const i32x4 0x4720fff1 0x4720fff1 0x4720fff1 0x4720fff1 + ) + (func (;8;) (type 0) (result v128) + v128.const i32x4 0x49f00000 0x49f00000 0x49f00000 0x49f00000 + ) + (func (;9;) (type 0) (result v128) + v128.const i32x4 0x55abc028 0x55abc028 0x55abc028 0x55abc028 + ) + (func (;10;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x412e8480 0x00000000 0x412e8480 + ) + (func (;11;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x408f4000 0x00000000 0x408f4000 + ) + (func (;12;) (type 0) (result v128) + v128.const i32x4 0xfafc8b00 0x408f5921 0xfafc8b00 0x408f5921 + ) + (func (;13;) (type 0) (result v128) + v128.const i32x4 0xb29f0000 0x430c2332 0xb29f0000 0x430c2332 + ) + (func (;14;) (type 0) (result v128) + v128.const i32x4 0x725bde9c 0x45c3b5ce 0x725bde9c 0x45c3b5ce + ) + (func (;15;) (type 0) (result v128) + v128.const i32x4 0x32000000 0x41a41e01 0x32000000 0x41a41e01 + ) + (func (;16;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x40faa0f0 0x00000000 0x40faa0f0 + ) + (func (;17;) (type 0) (result v128) + v128.const i32x4 0x2834b340 0x40e41ffe 0x2834b340 0x40e41ffe + ) + (func (;18;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x413e0000 0x00000000 0x413e0000 + ) + (func (;19;) (type 0) (result v128) + v128.const i32x4 0x0f9f7000 0x42b57805 0x0f9f7000 0x42b57805 + ) + (export "f32-dec-sep1" (func 0)) + (export "f32-dec-sep2" (func 1)) + (export "f32-dec-sep3" (func 2)) + (export "f32-dec-sep4" (func 3)) + (export "f32-dec-sep5" (func 4)) + (export "f32-hex-sep1" (func 5)) + (export "f32-hex-sep2" (func 6)) + (export "f32-hex-sep3" (func 7)) + (export "f32-hex-sep4" (func 8)) + (export "f32-hex-sep5" (func 9)) + (export "f64-dec-sep1" (func 10)) + (export "f64-dec-sep2" (func 11)) + (export "f64-dec-sep3" (func 12)) + (export "f64-dec-sep4" (func 13)) + (export "f64-dec-sep5" (func 14)) + (export "f64-hex-sep1" (func 15)) + (export "f64-hex-sep2" (func 16)) + (export "f64-hex-sep3" (func 17)) + (export "f64-hex-sep4" (func 18)) + (export "f64-hex-sep5" (func 19)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/65.print b/tests/snapshots/testsuite/simd_const.wast/65.print new file mode 100644 index 0000000000..a5a47dcaf4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/65.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000000 0xffe00000 0x00000000 0xffe00000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/66.print b/tests/snapshots/testsuite/simd_const.wast/66.print new file mode 100644 index 0000000000..5639c437fe --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/66.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x85ebc8a0 0x7fe1ccf3 0x85ebc8a0 0x7fe1ccf3 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/67.print b/tests/snapshots/testsuite/simd_const.wast/67.print new file mode 100644 index 0000000000..580ce4fb16 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/67.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x85ebc8a0 0xffe1ccf3 0x85ebc8a0 0xffe1ccf3 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/68.print b/tests/snapshots/testsuite/simd_const.wast/68.print new file mode 100644 index 0000000000..2830daf4d1 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/68.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0x7fefffff 0xffffffff 0x7fefffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/69.print b/tests/snapshots/testsuite/simd_const.wast/69.print new file mode 100644 index 0000000000..339d48b72f --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/69.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffefffff 0xffffffff 0xffefffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/7.print b/tests/snapshots/testsuite/simd_const.wast/7.print new file mode 100644 index 0000000000..f6a834c1a9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/7.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80008000 0x80008000 0x80008000 0x80008000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/70.print b/tests/snapshots/testsuite/simd_const.wast/70.print new file mode 100644 index 0000000000..68986af178 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/70.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00000001 0x7ff00000 0x00000001 0x7ff00000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/71.print b/tests/snapshots/testsuite/simd_const.wast/71.print new file mode 100644 index 0000000000..5fc555615a --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/71.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0x7fffffff 0xffffffff 0x7fffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/72.print b/tests/snapshots/testsuite/simd_const.wast/72.print new file mode 100644 index 0000000000..feeee8faf8 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/72.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x54000000 0x419d6f34 0x54000000 0x419d6f34 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/73.print b/tests/snapshots/testsuite/simd_const.wast/73.print new file mode 100644 index 0000000000..5e97576625 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/73.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b5e16fa 0x458fe9af 0x5b5e16fa 0x458fe9af + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/74.print b/tests/snapshots/testsuite/simd_const.wast/74.print new file mode 100644 index 0000000000..5e97576625 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/74.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b5e16fa 0x458fe9af 0x5b5e16fa 0x458fe9af + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/745.print b/tests/snapshots/testsuite/simd_const.wast/745.print new file mode 100644 index 0000000000..dbf1ef4e9d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/745.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x80808080 0xffffffff 0xffffffff + ) + (export "parse_i8x16" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/747.print b/tests/snapshots/testsuite/simd_const.wast/747.print new file mode 100644 index 0000000000..e7bfc41b0d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/747.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x80008000 0xffffffff 0xffffffff + ) + (export "parse_i16x8" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/749.print b/tests/snapshots/testsuite/simd_const.wast/749.print new file mode 100644 index 0000000000..049b72cf3d --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/749.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xffffffd1 0xffffffd1 0xffffffd1 0xffffffd1 + ) + (export "parse_i32x4" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/75.print b/tests/snapshots/testsuite/simd_const.wast/75.print new file mode 100644 index 0000000000..c6929d4451 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/75.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xd62b4311 0x3dab25ff 0xd62b4311 0x3dab25ff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/751.print b/tests/snapshots/testsuite/simd_const.wast/751.print new file mode 100644 index 0000000000..a7bba2893c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/751.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xffffffff 0x7fffffff 0xffffffff 0x7fffffff + ) + (export "parse_i64x2" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/753.print b/tests/snapshots/testsuite/simd_const.wast/753.print new file mode 100644 index 0000000000..a75cd4d6cf --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/753.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x4f800000 0x4f800000 0x4f800000 0x4f800000 + ) + (export "parse_f32x4" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/755.print b/tests/snapshots/testsuite/simd_const.wast/755.print new file mode 100644 index 0000000000..6b94d2af24 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/755.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0xffffffff 0x7fefffff 0xffffffff 0x7fefffff + ) + (export "parse_f64x2" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/76.print b/tests/snapshots/testsuite/simd_const.wast/76.print new file mode 100644 index 0000000000..feeee8faf8 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/76.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x54000000 0x419d6f34 0x54000000 0x419d6f34 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/77.print b/tests/snapshots/testsuite/simd_const.wast/77.print new file mode 100644 index 0000000000..5e97576625 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/77.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b5e16fa 0x458fe9af 0x5b5e16fa 0x458fe9af + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/78.print b/tests/snapshots/testsuite/simd_const.wast/78.print new file mode 100644 index 0000000000..5e97576625 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/78.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b5e16fa 0x458fe9af 0x5b5e16fa 0x458fe9af + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/79.print b/tests/snapshots/testsuite/simd_const.wast/79.print new file mode 100644 index 0000000000..c6929d4451 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/79.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xd62b4311 0x3dab25ff 0xd62b4311 0x3dab25ff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/8.print b/tests/snapshots/testsuite/simd_const.wast/8.print new file mode 100644 index 0000000000..994cbb1f6b --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/8.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0xffffffff 0xffffffff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/80.print b/tests/snapshots/testsuite/simd_const.wast/80.print new file mode 100644 index 0000000000..3caad75cf3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/80.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x540ca458 0x419d6f34 0x540ca458 0x419d6f34 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/81.print b/tests/snapshots/testsuite/simd_const.wast/81.print new file mode 100644 index 0000000000..ecda515fb9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/81.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b6bcbd5 0x458fe9af 0x5b6bcbd5 0x458fe9af + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/82.print b/tests/snapshots/testsuite/simd_const.wast/82.print new file mode 100644 index 0000000000..ecda515fb9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/82.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x5b6bcbd5 0x458fe9af 0x5b6bcbd5 0x458fe9af + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/83.print b/tests/snapshots/testsuite/simd_const.wast/83.print new file mode 100644 index 0000000000..15c652b688 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/83.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xd636ec12 0x3dab25ff 0xd636ec12 0x3dab25ff + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/84.print b/tests/snapshots/testsuite/simd_const.wast/84.print new file mode 100644 index 0000000000..793dcf09a7 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/84.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x44f23456 0x789abcdf 0x44f23456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/85.print b/tests/snapshots/testsuite/simd_const.wast/85.print new file mode 100644 index 0000000000..4b6e9b856c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/85.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x46223456 0x789abcdf 0x46223456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/86.print b/tests/snapshots/testsuite/simd_const.wast/86.print new file mode 100644 index 0000000000..4b6e9b856c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/86.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x46223456 0x789abcdf 0x46223456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/87.print b/tests/snapshots/testsuite/simd_const.wast/87.print new file mode 100644 index 0000000000..f2ed914ba4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/87.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x43c23456 0x789abcdf 0x43c23456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/88.print b/tests/snapshots/testsuite/simd_const.wast/88.print new file mode 100644 index 0000000000..793dcf09a7 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/88.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x44f23456 0x789abcdf 0x44f23456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/89.print b/tests/snapshots/testsuite/simd_const.wast/89.print new file mode 100644 index 0000000000..4b6e9b856c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/89.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x46223456 0x789abcdf 0x46223456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/9.print b/tests/snapshots/testsuite/simd_const.wast/9.print new file mode 100644 index 0000000000..f6a834c1a9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/9.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x80008000 0x80008000 0x80008000 0x80008000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/90.print b/tests/snapshots/testsuite/simd_const.wast/90.print new file mode 100644 index 0000000000..4b6e9b856c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/90.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x46223456 0x789abcdf 0x46223456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/91.print b/tests/snapshots/testsuite/simd_const.wast/91.print new file mode 100644 index 0000000000..f2ed914ba4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/91.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x43c23456 0x789abcdf 0x43c23456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/92.print b/tests/snapshots/testsuite/simd_const.wast/92.print new file mode 100644 index 0000000000..793dcf09a7 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/92.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x44f23456 0x789abcdf 0x44f23456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/93.print b/tests/snapshots/testsuite/simd_const.wast/93.print new file mode 100644 index 0000000000..4b6e9b856c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/93.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x46223456 0x789abcdf 0x46223456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/94.print b/tests/snapshots/testsuite/simd_const.wast/94.print new file mode 100644 index 0000000000..4b6e9b856c --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/94.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x46223456 0x789abcdf 0x46223456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/95.print b/tests/snapshots/testsuite/simd_const.wast/95.print new file mode 100644 index 0000000000..f2ed914ba4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/95.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x789abcdf 0x43c23456 0x789abcdf 0x43c23456 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/96.print b/tests/snapshots/testsuite/simd_const.wast/96.print new file mode 100644 index 0000000000..20667122dc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/96.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0x80808080 0x80808080 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/97.print b/tests/snapshots/testsuite/simd_const.wast/97.print new file mode 100644 index 0000000000..20667122dc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/97.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0x80808080 0x80808080 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/98.print b/tests/snapshots/testsuite/simd_const.wast/98.print new file mode 100644 index 0000000000..20667122dc --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/98.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0xffffffff 0xffffffff 0x80808080 0x80808080 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_const.wast/99.print b/tests/snapshots/testsuite/simd_const.wast/99.print new file mode 100644 index 0000000000..c889f81432 --- /dev/null +++ b/tests/snapshots/testsuite/simd_const.wast/99.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + v128.const i32x4 0x00ff00ff 0x00ff00ff 0x80008000 0x80008000 + drop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_conversions.wast/0.print b/tests/snapshots/testsuite/simd_conversions.wast/0.print new file mode 100644 index 0000000000..f214ca9dc5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_conversions.wast/0.print @@ -0,0 +1,58 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + f32x4.convert_i32x4_s + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + f32x4.convert_i32x4_u + ) + (func (;2;) (type 0) (param v128) (result v128) + local.get 0 + f64x2.convert_low_i32x4_s + ) + (func (;3;) (type 0) (param v128) (result v128) + local.get 0 + f64x2.convert_low_i32x4_u + ) + (func (;4;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_s + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_u + ) + (func (;6;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_s + ) + (func (;7;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_u + ) + (func (;8;) (type 0) (param v128) (result v128) + local.get 0 + f64x2.promote_low_f32x4 + ) + (func (;9;) (type 0) (param v128) (result v128) + local.get 0 + f32x4.demote_f64x2_zero + ) + (export "f32x4.convert_i32x4_s" (func 0)) + (export "f32x4.convert_i32x4_u" (func 1)) + (export "f64x2.convert_low_i32x4_s" (func 2)) + (export "f64x2.convert_low_i32x4_u" (func 3)) + (export "i8x16.narrow_i16x8_s" (func 4)) + (export "i8x16.narrow_i16x8_u" (func 5)) + (export "i16x8.narrow_i32x4_s" (func 6)) + (export "i16x8.narrow_i32x4_u" (func 7)) + (export "f64x2.promote_low_f32x4" (func 8)) + (export "f32x4.demote_f64x2_zero" (func 9)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_conversions.wast/252.print b/tests/snapshots/testsuite/simd_conversions.wast/252.print new file mode 100644 index 0000000000..0e25ec1219 --- /dev/null +++ b/tests/snapshots/testsuite/simd_conversions.wast/252.print @@ -0,0 +1,136 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.add + f32x4.convert_i32x4_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.sub + f32x4.convert_i32x4_s + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.mul + f32x4.convert_i32x4_u + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_s + i16x8.extend_low_i8x16_s + ) + (func (;4;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_u + i16x8.extend_low_i8x16_s + ) + (func (;5;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_s + i16x8.extend_low_i8x16_s + ) + (func (;6;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_u + i16x8.extend_low_i8x16_s + ) + (func (;7;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_u + i16x8.extend_low_i8x16_u + ) + (func (;8;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_s + i16x8.extend_low_i8x16_u + ) + (func (;9;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_u + i16x8.extend_low_i8x16_u + ) + (func (;10;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.narrow_i16x8_s + i16x8.extend_low_i8x16_u + ) + (func (;11;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_s + i32x4.extend_low_i16x8_s + ) + (func (;12;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_u + i32x4.extend_low_i16x8_s + ) + (func (;13;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_s + i32x4.extend_low_i16x8_s + ) + (func (;14;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_u + i32x4.extend_low_i16x8_s + ) + (func (;15;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_u + i32x4.extend_low_i16x8_u + ) + (func (;16;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_s + i32x4.extend_low_i16x8_u + ) + (func (;17;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_u + i32x4.extend_low_i16x8_u + ) + (func (;18;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.narrow_i32x4_s + i32x4.extend_low_i16x8_u + ) + (export "f32x4_convert_i32x4_s_add" (func 0)) + (export "f32x4_convert_i32x4_s_sub" (func 1)) + (export "f32x4_convert_i32x4_u_mul" (func 2)) + (export "i16x8_low_extend_narrow_ss" (func 3)) + (export "i16x8_low_extend_narrow_su" (func 4)) + (export "i16x8_high_extend_narrow_ss" (func 5)) + (export "i16x8_high_extend_narrow_su" (func 6)) + (export "i16x8_low_extend_narrow_uu" (func 7)) + (export "i16x8_low_extend_narrow_us" (func 8)) + (export "i16x8_high_extend_narrow_uu" (func 9)) + (export "i16x8_high_extend_narrow_us" (func 10)) + (export "i32x4_low_extend_narrow_ss" (func 11)) + (export "i32x4_low_extend_narrow_su" (func 12)) + (export "i32x4_high_extend_narrow_ss" (func 13)) + (export "i32x4_high_extend_narrow_su" (func 14)) + (export "i32x4_low_extend_narrow_uu" (func 15)) + (export "i32x4_low_extend_narrow_us" (func 16)) + (export "i32x4_high_extend_narrow_uu" (func 17)) + (export "i32x4_high_extend_narrow_us" (func 18)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4.wast/0.print b/tests/snapshots/testsuite/simd_f32x4.wast/0.print new file mode 100644 index 0000000000..56f83badc5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4.wast/0.print @@ -0,0 +1,123 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (type (;2;) (func (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.min + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.max + ) + (func (;2;) (type 1) (param v128) (result v128) + local.get 0 + f32x4.abs + ) + (func (;3;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0xc0400000 + v128.const i32x4 0x00000000 0x40000000 0x3f800000 0x40400000 + f32x4.min + ) + (func (;4;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x40400000 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x40400000 + f32x4.min + ) + (func (;5;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + v128.const i32x4 0x00000000 0x40000000 0x3f800000 0x4f000000 + f32x4.min + ) + (func (;6;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + f32x4.min + ) + (func (;7;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0xc0400000 + f32x4.min + ) + (func (;8;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x40400000 + local.get 0 + f32x4.min + ) + (func (;9;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + local.get 0 + f32x4.min + ) + (func (;10;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + f32x4.min + ) + (func (;11;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0xc0400000 + v128.const i32x4 0x00000000 0x40000000 0x3f800000 0x40400000 + f32x4.max + ) + (func (;12;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x40400000 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x40400000 + f32x4.max + ) + (func (;13;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + v128.const i32x4 0x00000000 0x40000000 0x3f800000 0x4f000000 + f32x4.max + ) + (func (;14;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + f32x4.max + ) + (func (;15;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0xc0400000 + f32x4.max + ) + (func (;16;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x40400000 + local.get 0 + f32x4.max + ) + (func (;17;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + local.get 0 + f32x4.max + ) + (func (;18;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x4f000000 + f32x4.max + ) + (func (;19;) (type 2) (result v128) + v128.const i32x4 0x80000000 0xbf800000 0xc0000000 0xc0400000 + f32x4.abs + ) + (export "f32x4.min" (func 0)) + (export "f32x4.max" (func 1)) + (export "f32x4.abs" (func 2)) + (export "f32x4.min_with_const_0" (func 3)) + (export "f32x4.min_with_const_1" (func 4)) + (export "f32x4.min_with_const_2" (func 5)) + (export "f32x4.min_with_const_3" (func 6)) + (export "f32x4.min_with_const_5" (func 7)) + (export "f32x4.min_with_const_6" (func 8)) + (export "f32x4.min_with_const_7" (func 9)) + (export "f32x4.min_with_const_8" (func 10)) + (export "f32x4.max_with_const_10" (func 11)) + (export "f32x4.max_with_const_11" (func 12)) + (export "f32x4.max_with_const_12" (func 13)) + (export "f32x4.max_with_const_13" (func 14)) + (export "f32x4.max_with_const_15" (func 15)) + (export "f32x4.max_with_const_16" (func 16)) + (export "f32x4.max_with_const_17" (func 17)) + (export "f32x4.max_with_const_18" (func 18)) + (export "f32x4.abs_with_const" (func 19)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4.wast/785.print b/tests/snapshots/testsuite/simd_f32x4.wast/785.print new file mode 100644 index 0000000000..2f4c43ae77 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4.wast/785.print @@ -0,0 +1,34 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.min + local.get 2 + f32x4.max + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.max + local.get 2 + f32x4.min + ) + (func (;2;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.abs + local.get 1 + f32x4.max + ) + (func (;3;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.abs + local.get 1 + f32x4.min + ) + (export "max-min" (func 0)) + (export "min-max" (func 1)) + (export "max-abs" (func 2)) + (export "min-abs" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4_arith.wast/0.print b/tests/snapshots/testsuite/simd_f32x4_arith.wast/0.print new file mode 100644 index 0000000000..46ad1736ad --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4_arith.wast/0.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.add + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.sub + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.mul + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.div + ) + (func (;4;) (type 1) (param v128) (result v128) + local.get 0 + f32x4.neg + ) + (func (;5;) (type 1) (param v128) (result v128) + local.get 0 + f32x4.sqrt + ) + (export "f32x4.add" (func 0)) + (export "f32x4.sub" (func 1)) + (export "f32x4.mul" (func 2)) + (export "f32x4.div" (func 3)) + (export "f32x4.neg" (func 4)) + (export "f32x4.sqrt" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4_arith.wast/1785.print b/tests/snapshots/testsuite/simd_f32x4_arith.wast/1785.print new file mode 100644 index 0000000000..08a7c5a999 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4_arith.wast/1785.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x7fa00000 0xffa00000 0x41800000 0x41c80000 + f32x4.sqrt + ) + (func (;1;) (type 0) (result v128) + v128.const i32x4 0xbf800000 0x7fc00000 0x40800000 0x41100000 + f32x4.sqrt + ) + (func (;2;) (type 0) (result v128) + v128.const i32x4 0xff800000 0x7fa00000 0x42100000 0x42440000 + f32x4.sqrt + ) + (export "f32x4_sqrt_arith" (func 0)) + (export "f32x4_sqrt_canon" (func 1)) + (export "f32x4_sqrt_mixed" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4_arith.wast/1805.print b/tests/snapshots/testsuite/simd_f32x4_arith.wast/1805.print new file mode 100644 index 0000000000..9bef050f36 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4_arith.wast/1805.print @@ -0,0 +1,124 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.sub + local.get 2 + f32x4.add + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.add + local.get 2 + f32x4.div + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.mul + local.get 2 + f32x4.div + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.sub + local.get 2 + f32x4.div + ) + (func (;4;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.add + local.get 2 + f32x4.mul + ) + (func (;5;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.div + local.get 2 + f32x4.mul + ) + (func (;6;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.sub + local.get 2 + f32x4.mul + ) + (func (;7;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.add + local.get 2 + f32x4.sub + ) + (func (;8;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.neg + local.get 1 + f32x4.add + ) + (func (;9;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.sqrt + local.get 1 + f32x4.add + ) + (func (;10;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.neg + local.get 1 + f32x4.div + ) + (func (;11;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.sqrt + local.get 1 + f32x4.div + ) + (func (;12;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.neg + local.get 1 + f32x4.mul + ) + (func (;13;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.sqrt + local.get 1 + f32x4.mul + ) + (func (;14;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.neg + local.get 1 + f32x4.sub + ) + (func (;15;) (type 1) (param v128 v128) (result v128) + local.get 0 + f32x4.sqrt + local.get 1 + f32x4.sub + ) + (export "add-sub" (func 0)) + (export "div-add" (func 1)) + (export "div-mul" (func 2)) + (export "div-sub" (func 3)) + (export "mul-add" (func 4)) + (export "mul-div" (func 5)) + (export "mul-sub" (func 6)) + (export "sub-add" (func 7)) + (export "add-neg" (func 8)) + (export "add-sqrt" (func 9)) + (export "div-neg" (func 10)) + (export "div-sqrt" (func 11)) + (export "mul-neg" (func 12)) + (export "mul-sqrt" (func 13)) + (export "sub-neg" (func 14)) + (export "sub-sqrt" (func 15)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4_cmp.wast/0.print b/tests/snapshots/testsuite/simd_f32x4_cmp.wast/0.print new file mode 100644 index 0000000000..04b2feb67f --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4_cmp.wast/0.print @@ -0,0 +1,39 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + f32x4.eq + ) + (func (;1;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + f32x4.ne + ) + (func (;2;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + f32x4.lt + ) + (func (;3;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + f32x4.le + ) + (func (;4;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + f32x4.gt + ) + (func (;5;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + f32x4.ge + ) + (export "eq" (func 0)) + (export "ne" (func 1)) + (export "lt" (func 2)) + (export "le" (func 3)) + (export "gt" (func 4)) + (export "ge" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4_cmp.wast/2581.print b/tests/snapshots/testsuite/simd_f32x4_cmp.wast/2581.print new file mode 100644 index 0000000000..e442046812 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4_cmp.wast/2581.print @@ -0,0 +1,295 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f32x4.eq + end + drop + end + ) + (func (;1;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f32x4.ne + end + drop + end + ) + (func (;2;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f32x4.lt + end + drop + end + ) + (func (;3;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f32x4.le + end + drop + end + ) + (func (;4;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f32x4.gt + end + drop + end + ) + (func (;5;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f32x4.ge + end + drop + end + ) + (func (;6;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.eq + f32x4.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.eq + f32x4.eq + f32x4.eq + drop + ) + (func (;7;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.ne + f32x4.ne + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.ne + f32x4.ne + f32x4.ne + drop + ) + (func (;8;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.lt + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.lt + f32x4.lt + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.lt + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.lt + f32x4.lt + f32x4.lt + drop + ) + (func (;9;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.le + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.le + f32x4.le + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.le + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.le + f32x4.le + f32x4.le + drop + ) + (func (;10;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.gt + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.gt + f32x4.gt + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.gt + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.gt + f32x4.gt + f32x4.gt + drop + ) + (func (;11;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.ge + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.ge + f32x4.ge + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.ge + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.ge + f32x4.ge + f32x4.ge + drop + ) + (func (;12;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.lt + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.le + f32x4.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + f32x4.gt + i32.const 2 + v128.load + i32.const 3 + v128.load + f32x4.lt + f32x4.ne + f32x4.ge + drop + ) + (memory (;0;) 1) + (export "eq-in-block" (func 0)) + (export "ne-in-block" (func 1)) + (export "lt-in-block" (func 2)) + (export "le-in-block" (func 3)) + (export "gt-in-block" (func 4)) + (export "ge-in-block" (func 5)) + (export "nested-eq" (func 6)) + (export "nested-ne" (func 7)) + (export "nested-lt" (func 8)) + (export "nested-le" (func 9)) + (export "nested-gt" (func 10)) + (export "nested-ge" (func 11)) + (export "as-param" (func 12)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4_pmin_pmax.wast/0.print b/tests/snapshots/testsuite/simd_f32x4_pmin_pmax.wast/0.print new file mode 100644 index 0000000000..5793db769c --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4_pmin_pmax.wast/0.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.pmin + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f32x4.pmax + ) + (export "f32x4.pmin" (func 0)) + (export "f32x4.pmax" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f32x4_rounding.wast/0.print b/tests/snapshots/testsuite/simd_f32x4_rounding.wast/0.print new file mode 100644 index 0000000000..eb932d1b2b --- /dev/null +++ b/tests/snapshots/testsuite/simd_f32x4_rounding.wast/0.print @@ -0,0 +1,23 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + f32x4.ceil + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + f32x4.floor + ) + (func (;2;) (type 0) (param v128) (result v128) + local.get 0 + f32x4.trunc + ) + (func (;3;) (type 0) (param v128) (result v128) + local.get 0 + f32x4.nearest + ) + (export "f32x4.ceil" (func 0)) + (export "f32x4.floor" (func 1)) + (export "f32x4.trunc" (func 2)) + (export "f32x4.nearest" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2.wast/0.print b/tests/snapshots/testsuite/simd_f64x2.wast/0.print new file mode 100644 index 0000000000..0956c97b25 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2.wast/0.print @@ -0,0 +1,224 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (type (;2;) (func (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.min + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.max + ) + (func (;2;) (type 1) (param v128) (result v128) + local.get 0 + f64x2.abs + ) + (func (;3;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x40000000 + f64x2.min + ) + (func (;4;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0xc0080000 + v128.const i32x4 0x00000000 0x3ff00000 0x00000000 0x40080000 + f64x2.min + ) + (func (;5;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + f64x2.min + ) + (func (;6;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x40080000 + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x40080000 + f64x2.min + ) + (func (;7;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x40000000 + f64x2.min + ) + (func (;8;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + v128.const i32x4 0x00000000 0x3ff00000 0x00000000 0x41e00000 + f64x2.min + ) + (func (;9;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + f64x2.min + ) + (func (;10;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + f64x2.min + ) + (func (;11;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + f64x2.min + ) + (func (;12;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0xc0080000 + local.get 0 + f64x2.min + ) + (func (;13;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + local.get 0 + f64x2.min + ) + (func (;14;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x40080000 + f64x2.min + ) + (func (;15;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + local.get 0 + f64x2.min + ) + (func (;16;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + local.get 0 + f64x2.min + ) + (func (;17;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + local.get 0 + f64x2.min + ) + (func (;18;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + local.get 0 + f64x2.min + ) + (func (;19;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x40000000 + f64x2.max + ) + (func (;20;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0xc0080000 + v128.const i32x4 0x00000000 0x3ff00000 0x00000000 0x40080000 + f64x2.max + ) + (func (;21;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + f64x2.max + ) + (func (;22;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x40080000 + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x40080000 + f64x2.max + ) + (func (;23;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x40000000 + f64x2.max + ) + (func (;24;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + v128.const i32x4 0x00000000 0x3ff00000 0x00000000 0x41e00000 + f64x2.max + ) + (func (;25;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + f64x2.max + ) + (func (;26;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + f64x2.max + ) + (func (;27;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + f64x2.max + ) + (func (;28;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0xc0080000 + local.get 0 + f64x2.max + ) + (func (;29;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + local.get 0 + f64x2.max + ) + (func (;30;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x40080000 + f64x2.max + ) + (func (;31;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + local.get 0 + f64x2.max + ) + (func (;32;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + local.get 0 + f64x2.max + ) + (func (;33;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x3ff00000 + local.get 0 + f64x2.max + ) + (func (;34;) (type 1) (param v128) (result v128) + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x41e00000 + local.get 0 + f64x2.max + ) + (func (;35;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x80000000 0x00000000 0xbff00000 + f64x2.abs + ) + (func (;36;) (type 2) (result v128) + v128.const i32x4 0x00000000 0xc0000000 0x00000000 0xc0080000 + f64x2.abs + ) + (export "f64x2.min" (func 0)) + (export "f64x2.max" (func 1)) + (export "f64x2.abs" (func 2)) + (export "f64x2.min_with_const_0" (func 3)) + (export "f64x2.min_with_const_1" (func 4)) + (export "f64x2.min_with_const_2" (func 5)) + (export "f64x2.min_with_const_3" (func 6)) + (export "f64x2.min_with_const_4" (func 7)) + (export "f64x2.min_with_const_5" (func 8)) + (export "f64x2.min_with_const_6" (func 9)) + (export "f64x2.min_with_const_7" (func 10)) + (export "f64x2.min_with_const_9" (func 11)) + (export "f64x2.min_with_const_10" (func 12)) + (export "f64x2.min_with_const_11" (func 13)) + (export "f64x2.min_with_const_12" (func 14)) + (export "f64x2.min_with_const_13" (func 15)) + (export "f64x2.min_with_const_14" (func 16)) + (export "f64x2.min_with_const_15" (func 17)) + (export "f64x2.min_with_const_16" (func 18)) + (export "f64x2.max_with_const_18" (func 19)) + (export "f64x2.max_with_const_19" (func 20)) + (export "f64x2.max_with_const_20" (func 21)) + (export "f64x2.max_with_const_21" (func 22)) + (export "f64x2.max_with_const_22" (func 23)) + (export "f64x2.max_with_const_23" (func 24)) + (export "f64x2.max_with_const_24" (func 25)) + (export "f64x2.max_with_const_25" (func 26)) + (export "f64x2.max_with_const_27" (func 27)) + (export "f64x2.max_with_const_28" (func 28)) + (export "f64x2.max_with_const_29" (func 29)) + (export "f64x2.max_with_const_30" (func 30)) + (export "f64x2.max_with_const_31" (func 31)) + (export "f64x2.max_with_const_32" (func 32)) + (export "f64x2.max_with_const_33" (func 33)) + (export "f64x2.max_with_const_34" (func 34)) + (export "f64x2.abs_with_const_35" (func 35)) + (export "f64x2.abs_with_const_36" (func 36)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2.wast/798.print b/tests/snapshots/testsuite/simd_f64x2.wast/798.print new file mode 100644 index 0000000000..196a8b72c4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2.wast/798.print @@ -0,0 +1,34 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.min + local.get 2 + f64x2.max + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.max + local.get 2 + f64x2.min + ) + (func (;2;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.abs + local.get 1 + f64x2.max + ) + (func (;3;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.abs + local.get 1 + f64x2.min + ) + (export "max-min" (func 0)) + (export "min-max" (func 1)) + (export "max-abs" (func 2)) + (export "min-abs" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2_arith.wast/0.print b/tests/snapshots/testsuite/simd_f64x2_arith.wast/0.print new file mode 100644 index 0000000000..eb5fc8c1fd --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2_arith.wast/0.print @@ -0,0 +1,38 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.add + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.sub + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.mul + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.div + ) + (func (;4;) (type 1) (param v128) (result v128) + local.get 0 + f64x2.neg + ) + (func (;5;) (type 1) (param v128) (result v128) + local.get 0 + f64x2.sqrt + ) + (export "f64x2.add" (func 0)) + (export "f64x2.sub" (func 1)) + (export "f64x2.mul" (func 2)) + (export "f64x2.div" (func 3)) + (export "f64x2.neg" (func 4)) + (export "f64x2.sqrt" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2_arith.wast/1785.print b/tests/snapshots/testsuite/simd_f64x2_arith.wast/1785.print new file mode 100644 index 0000000000..71cf157712 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2_arith.wast/1785.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x7ff80000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x7ff80000 0x00000000 0x3ff00000 + f64x2.add + ) + (func (;1;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x7ff80000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x40000000 0x00000000 0xfff80000 + f64x2.div + ) + (func (;2;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x7ff80000 0x00000000 0x3ff00000 + v128.const i32x4 0x00000000 0x40000000 0x00000000 0x7ff80000 + f64x2.mul + ) + (func (;3;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x7ff80000 0x00000000 0x3ff00000 + f64x2.neg + ) + (func (;4;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x40100000 0x00000000 0xfff80000 + f64x2.sqrt + ) + (func (;5;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x3ff00000 0x00000000 0xbff00000 + v128.const i32x4 0x00000000 0xfff80000 0x00000000 0x3ff00000 + f64x2.sub + ) + (export "f64x2_add_arith" (func 0)) + (export "f64x2_div_mixed" (func 1)) + (export "f64x2_mul_mixed" (func 2)) + (export "f64x2_neg_canon" (func 3)) + (export "f64x2_sqrt_canon" (func 4)) + (export "f64x2_sub_arith" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2_arith.wast/1808.print b/tests/snapshots/testsuite/simd_f64x2_arith.wast/1808.print new file mode 100644 index 0000000000..f4fb026eea --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2_arith.wast/1808.print @@ -0,0 +1,124 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.sub + local.get 2 + f64x2.add + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.add + local.get 2 + f64x2.div + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.mul + local.get 2 + f64x2.div + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.sub + local.get 2 + f64x2.div + ) + (func (;4;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.add + local.get 2 + f64x2.mul + ) + (func (;5;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.div + local.get 2 + f64x2.mul + ) + (func (;6;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.sub + local.get 2 + f64x2.mul + ) + (func (;7;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.add + local.get 2 + f64x2.sub + ) + (func (;8;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.neg + local.get 1 + f64x2.add + ) + (func (;9;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.sqrt + local.get 1 + f64x2.add + ) + (func (;10;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.neg + local.get 1 + f64x2.div + ) + (func (;11;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.sqrt + local.get 1 + f64x2.div + ) + (func (;12;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.neg + local.get 1 + f64x2.mul + ) + (func (;13;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.sqrt + local.get 1 + f64x2.mul + ) + (func (;14;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.neg + local.get 1 + f64x2.sub + ) + (func (;15;) (type 1) (param v128 v128) (result v128) + local.get 0 + f64x2.sqrt + local.get 1 + f64x2.sub + ) + (export "add-sub" (func 0)) + (export "div-add" (func 1)) + (export "div-mul" (func 2)) + (export "div-sub" (func 3)) + (export "mul-add" (func 4)) + (export "mul-div" (func 5)) + (export "mul-sub" (func 6)) + (export "sub-add" (func 7)) + (export "add-neg" (func 8)) + (export "add-sqrt" (func 9)) + (export "div-neg" (func 10)) + (export "div-sqrt" (func 11)) + (export "mul-neg" (func 12)) + (export "mul-sqrt" (func 13)) + (export "sub-neg" (func 14)) + (export "sub-sqrt" (func 15)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2_cmp.wast/0.print b/tests/snapshots/testsuite/simd_f64x2_cmp.wast/0.print new file mode 100644 index 0000000000..f6d05cf693 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2_cmp.wast/0.print @@ -0,0 +1,39 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.eq + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.ne + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.lt + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.le + ) + (func (;4;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.gt + ) + (func (;5;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.ge + ) + (export "f64x2.eq" (func 0)) + (export "f64x2.ne" (func 1)) + (export "f64x2.lt" (func 2)) + (export "f64x2.le" (func 3)) + (export "f64x2.gt" (func 4)) + (export "f64x2.ge" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2_cmp.wast/2671.print b/tests/snapshots/testsuite/simd_f64x2_cmp.wast/2671.print new file mode 100644 index 0000000000..ae3056dcdd --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2_cmp.wast/2671.print @@ -0,0 +1,295 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f64x2.eq + end + drop + end + ) + (func (;1;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f64x2.ne + end + drop + end + ) + (func (;2;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f64x2.lt + end + drop + end + ) + (func (;3;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f64x2.le + end + drop + end + ) + (func (;4;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f64x2.gt + end + drop + end + ) + (func (;5;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + f64x2.ge + end + drop + end + ) + (func (;6;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.eq + f64x2.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.eq + f64x2.eq + f64x2.eq + drop + ) + (func (;7;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.ne + f64x2.ne + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.ne + f64x2.ne + f64x2.ne + drop + ) + (func (;8;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.lt + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.lt + f64x2.lt + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.lt + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.lt + f64x2.lt + f64x2.lt + drop + ) + (func (;9;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.le + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.le + f64x2.le + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.le + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.le + f64x2.le + f64x2.le + drop + ) + (func (;10;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.gt + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.gt + f64x2.gt + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.gt + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.gt + f64x2.gt + f64x2.gt + drop + ) + (func (;11;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.ge + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.ge + f64x2.ge + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.ge + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.ge + f64x2.ge + f64x2.ge + drop + ) + (func (;12;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.lt + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.le + f64x2.ne + i32.const 0 + v128.load + i32.const 1 + v128.load + f64x2.ge + i32.const 2 + v128.load + i32.const 3 + v128.load + f64x2.eq + f64x2.gt + f64x2.eq + drop + ) + (memory (;0;) 1) + (export "f64x2.eq-in-block" (func 0)) + (export "f64x2.ne-in-block" (func 1)) + (export "f64x2.lt-in-block" (func 2)) + (export "f64x2.le-in-block" (func 3)) + (export "f64x2.gt-in-block" (func 4)) + (export "f64x2.ge-in-block" (func 5)) + (export "nested-f64x2.eq" (func 6)) + (export "nested-f64x2.ne" (func 7)) + (export "nested-f64x2.lt" (func 8)) + (export "nested-f64x2.le" (func 9)) + (export "nested-f64x2.gt" (func 10)) + (export "nested-f64x2.ge" (func 11)) + (export "as-param" (func 12)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2_pmin_pmax.wast/0.print b/tests/snapshots/testsuite/simd_f64x2_pmin_pmax.wast/0.print new file mode 100644 index 0000000000..465045baaf --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2_pmin_pmax.wast/0.print @@ -0,0 +1,15 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.pmin + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.pmax + ) + (export "f64x2.pmin" (func 0)) + (export "f64x2.pmax" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_f64x2_rounding.wast/0.print b/tests/snapshots/testsuite/simd_f64x2_rounding.wast/0.print new file mode 100644 index 0000000000..87c159c933 --- /dev/null +++ b/tests/snapshots/testsuite/simd_f64x2_rounding.wast/0.print @@ -0,0 +1,23 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + f64x2.ceil + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + f64x2.floor + ) + (func (;2;) (type 0) (param v128) (result v128) + local.get 0 + f64x2.trunc + ) + (func (;3;) (type 0) (param v128) (result v128) + local.get 0 + f64x2.nearest + ) + (export "f64x2.ceil" (func 0)) + (export "f64x2.floor" (func 1)) + (export "f64x2.trunc" (func 2)) + (export "f64x2.nearest" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_arith.wast/0.print b/tests/snapshots/testsuite/simd_i16x8_arith.wast/0.print new file mode 100644 index 0000000000..5ed98528b1 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_arith.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.add + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.mul + ) + (func (;3;) (type 1) (param v128) (result v128) + local.get 0 + i16x8.neg + ) + (export "i16x8.add" (func 0)) + (export "i16x8.sub" (func 1)) + (export "i16x8.mul" (func 2)) + (export "i16x8.neg" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_arith.wast/186.print b/tests/snapshots/testsuite/simd_i16x8_arith.wast/186.print new file mode 100644 index 0000000000..a8f08eed55 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_arith.wast/186.print @@ -0,0 +1,57 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub + local.get 2 + i16x8.add + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.add + local.get 2 + i16x8.mul + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub + local.get 2 + i16x8.mul + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.add + local.get 2 + i16x8.sub + ) + (func (;4;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.neg + local.get 1 + i16x8.add + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.neg + local.get 1 + i16x8.mul + ) + (func (;6;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.neg + local.get 1 + i16x8.sub + ) + (export "add-sub" (func 0)) + (export "mul-add" (func 1)) + (export "mul-sub" (func 2)) + (export "sub-add" (func 3)) + (export "add-neg" (func 4)) + (export "mul-neg" (func 5)) + (export "sub-neg" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_arith2.wast/0.print b/tests/snapshots/testsuite/simd_i16x8_arith2.wast/0.print new file mode 100644 index 0000000000..ef4fde11f9 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_arith2.wast/0.print @@ -0,0 +1,165 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (type (;2;) (func (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_u + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_s + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_u + ) + (func (;4;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.avgr_u + ) + (func (;5;) (type 1) (param v128) (result v128) + local.get 0 + i16x8.abs + ) + (func (;6;) (type 2) (result v128) + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + v128.const i32x4 0xffffffff 0x40004000 0x7fff7fff 0x80008000 + i16x8.min_s + ) + (func (;7;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + v128.const i32x4 0x00030003 0x00020002 0x00010001 0x00000000 + i16x8.min_s + ) + (func (;8;) (type 2) (result v128) + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + v128.const i32x4 0xffffffff 0x40004000 0x7fff7fff 0x80008000 + i16x8.min_u + ) + (func (;9;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + v128.const i32x4 0x00030003 0x00020002 0x00010001 0x00000000 + i16x8.min_u + ) + (func (;10;) (type 2) (result v128) + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + v128.const i32x4 0xffffffff 0x40004000 0x7fff7fff 0x80008000 + i16x8.max_s + ) + (func (;11;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + v128.const i32x4 0x00030003 0x00020002 0x00010001 0x00000000 + i16x8.max_s + ) + (func (;12;) (type 2) (result v128) + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + v128.const i32x4 0xffffffff 0x40004000 0x7fff7fff 0x80008000 + i16x8.max_u + ) + (func (;13;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + v128.const i32x4 0x00030003 0x00020002 0x00010001 0x00000000 + i16x8.max_u + ) + (func (;14;) (type 2) (result v128) + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + v128.const i32x4 0xffffffff 0x40004000 0x7fff7fff 0x80008000 + i16x8.avgr_u + ) + (func (;15;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + v128.const i32x4 0x00030003 0x00020002 0x00010001 0x00000000 + i16x8.avgr_u + ) + (func (;16;) (type 2) (result v128) + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + i16x8.abs + ) + (func (;17;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + i16x8.min_s + ) + (func (;18;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + i16x8.min_s + ) + (func (;19;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + i16x8.min_u + ) + (func (;20;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + i16x8.min_u + ) + (func (;21;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + i16x8.max_s + ) + (func (;22;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + i16x8.max_s + ) + (func (;23;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + i16x8.max_u + ) + (func (;24;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + i16x8.max_u + ) + (func (;25;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80008000 0x7fff7fff 0x40004000 0xffffffff + i16x8.avgr_u + ) + (func (;26;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00010001 0x00020002 0x00030003 + i16x8.avgr_u + ) + (export "i16x8.min_s" (func 0)) + (export "i16x8.min_u" (func 1)) + (export "i16x8.max_s" (func 2)) + (export "i16x8.max_u" (func 3)) + (export "i16x8.avgr_u" (func 4)) + (export "i16x8.abs" (func 5)) + (export "i16x8.min_s_with_const_0" (func 6)) + (export "i16x8.min_s_with_const_1" (func 7)) + (export "i16x8.min_u_with_const_2" (func 8)) + (export "i16x8.min_u_with_const_3" (func 9)) + (export "i16x8.max_s_with_const_4" (func 10)) + (export "i16x8.max_s_with_const_5" (func 11)) + (export "i16x8.max_u_with_const_6" (func 12)) + (export "i16x8.max_u_with_const_7" (func 13)) + (export "i16x8.avgr_u_with_const_8" (func 14)) + (export "i16x8.avgr_u_with_const_9" (func 15)) + (export "i16x8.abs_with_const_10" (func 16)) + (export "i16x8.min_s_with_const_11" (func 17)) + (export "i16x8.min_s_with_const_12" (func 18)) + (export "i16x8.min_u_with_const_13" (func 19)) + (export "i16x8.min_u_with_const_14" (func 20)) + (export "i16x8.max_s_with_const_15" (func 21)) + (export "i16x8.max_s_with_const_16" (func 22)) + (export "i16x8.max_u_with_const_17" (func 23)) + (export "i16x8.max_u_with_const_18" (func 24)) + (export "i16x8.avgr_u_with_const_19" (func 25)) + (export "i16x8.avgr_u_with_const_20" (func 26)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_arith2.wast/135.print b/tests/snapshots/testsuite/simd_i16x8_arith2.wast/135.print new file mode 100644 index 0000000000..0c31e84272 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_arith2.wast/135.print @@ -0,0 +1,281 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (type (;2;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.avgr_u + local.get 2 + i16x8.min_s + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_u + local.get 2 + i16x8.min_s + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_s + local.get 2 + i16x8.min_s + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_u + local.get 2 + i16x8.min_s + ) + (func (;4;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_s + local.get 2 + i16x8.min_s + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.abs + local.get 1 + i16x8.min_s + ) + (func (;6;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_s + i16x8.abs + ) + (func (;7;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.avgr_u + local.get 2 + i16x8.min_u + ) + (func (;8;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_u + local.get 2 + i16x8.min_u + ) + (func (;9;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_s + local.get 2 + i16x8.min_u + ) + (func (;10;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_u + local.get 2 + i16x8.min_u + ) + (func (;11;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_s + local.get 2 + i16x8.min_u + ) + (func (;12;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.abs + local.get 1 + i16x8.min_u + ) + (func (;13;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_u + i16x8.abs + ) + (func (;14;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.avgr_u + local.get 2 + i16x8.max_s + ) + (func (;15;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_u + local.get 2 + i16x8.max_s + ) + (func (;16;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_s + local.get 2 + i16x8.max_s + ) + (func (;17;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_u + local.get 2 + i16x8.max_s + ) + (func (;18;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_s + local.get 2 + i16x8.max_s + ) + (func (;19;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.abs + local.get 1 + i16x8.max_s + ) + (func (;20;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_s + i16x8.abs + ) + (func (;21;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.avgr_u + local.get 2 + i16x8.max_u + ) + (func (;22;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_u + local.get 2 + i16x8.max_u + ) + (func (;23;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_s + local.get 2 + i16x8.max_u + ) + (func (;24;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_u + local.get 2 + i16x8.max_u + ) + (func (;25;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_s + local.get 2 + i16x8.max_u + ) + (func (;26;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.abs + local.get 1 + i16x8.max_u + ) + (func (;27;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_u + i16x8.abs + ) + (func (;28;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.avgr_u + local.get 2 + i16x8.avgr_u + ) + (func (;29;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_u + local.get 2 + i16x8.avgr_u + ) + (func (;30;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.max_s + local.get 2 + i16x8.avgr_u + ) + (func (;31;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_u + local.get 2 + i16x8.avgr_u + ) + (func (;32;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.min_s + local.get 2 + i16x8.avgr_u + ) + (func (;33;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.abs + local.get 1 + i16x8.avgr_u + ) + (func (;34;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.avgr_u + i16x8.abs + ) + (func (;35;) (type 2) (param v128) (result v128) + local.get 0 + i16x8.abs + i16x8.abs + ) + (export "i16x8.min_s-i16x8.avgr_u" (func 0)) + (export "i16x8.min_s-i16x8.max_u" (func 1)) + (export "i16x8.min_s-i16x8.max_s" (func 2)) + (export "i16x8.min_s-i16x8.min_u" (func 3)) + (export "i16x8.min_s-i16x8.min_s" (func 4)) + (export "i16x8.min_s-i16x8.abs" (func 5)) + (export "i16x8.abs-i16x8.min_s" (func 6)) + (export "i16x8.min_u-i16x8.avgr_u" (func 7)) + (export "i16x8.min_u-i16x8.max_u" (func 8)) + (export "i16x8.min_u-i16x8.max_s" (func 9)) + (export "i16x8.min_u-i16x8.min_u" (func 10)) + (export "i16x8.min_u-i16x8.min_s" (func 11)) + (export "i16x8.min_u-i16x8.abs" (func 12)) + (export "i16x8.abs-i16x8.min_u" (func 13)) + (export "i16x8.max_s-i16x8.avgr_u" (func 14)) + (export "i16x8.max_s-i16x8.max_u" (func 15)) + (export "i16x8.max_s-i16x8.max_s" (func 16)) + (export "i16x8.max_s-i16x8.min_u" (func 17)) + (export "i16x8.max_s-i16x8.min_s" (func 18)) + (export "i16x8.max_s-i16x8.abs" (func 19)) + (export "i16x8.abs-i16x8.max_s" (func 20)) + (export "i16x8.max_u-i16x8.avgr_u" (func 21)) + (export "i16x8.max_u-i16x8.max_u" (func 22)) + (export "i16x8.max_u-i16x8.max_s" (func 23)) + (export "i16x8.max_u-i16x8.min_u" (func 24)) + (export "i16x8.max_u-i16x8.min_s" (func 25)) + (export "i16x8.max_u-i16x8.abs" (func 26)) + (export "i16x8.abs-i16x8.max_u" (func 27)) + (export "i16x8.avgr_u-i16x8.avgr_u" (func 28)) + (export "i16x8.avgr_u-i16x8.max_u" (func 29)) + (export "i16x8.avgr_u-i16x8.max_s" (func 30)) + (export "i16x8.avgr_u-i16x8.min_u" (func 31)) + (export "i16x8.avgr_u-i16x8.min_s" (func 32)) + (export "i16x8.avgr_u-i16x8.abs" (func 33)) + (export "i16x8.abs-i16x8.avgr_u" (func 34)) + (export "i16x8.abs-i16x8.abs" (func 35)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_cmp.wast/0.print b/tests/snapshots/testsuite/simd_i16x8_cmp.wast/0.print new file mode 100644 index 0000000000..ec4b6642f1 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_cmp.wast/0.print @@ -0,0 +1,63 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.eq + ) + (func (;1;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.ne + ) + (func (;2;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.lt_s + ) + (func (;3;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.lt_u + ) + (func (;4;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.le_s + ) + (func (;5;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.le_u + ) + (func (;6;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.gt_s + ) + (func (;7;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.gt_u + ) + (func (;8;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.ge_s + ) + (func (;9;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i16x8.ge_u + ) + (export "eq" (func 0)) + (export "ne" (func 1)) + (export "lt_s" (func 2)) + (export "lt_u" (func 3)) + (export "le_s" (func 4)) + (export "le_u" (func 5)) + (export "gt_s" (func 6)) + (export "gt_u" (func 7)) + (export "ge_s" (func 8)) + (export "ge_u" (func 9)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_cmp.wast/431.print b/tests/snapshots/testsuite/simd_i16x8_cmp.wast/431.print new file mode 100644 index 0000000000..7e43eddafa --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_cmp.wast/431.print @@ -0,0 +1,295 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i16x8.eq + end + drop + end + ) + (func (;1;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i16x8.ne + end + drop + end + ) + (func (;2;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i16x8.lt_s + end + drop + end + ) + (func (;3;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i16x8.le_u + end + drop + end + ) + (func (;4;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i16x8.gt_u + end + drop + end + ) + (func (;5;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i16x8.ge_s + end + drop + end + ) + (func (;6;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.eq + i16x8.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.eq + i16x8.eq + i16x8.eq + drop + ) + (func (;7;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.ne + i16x8.ne + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.ne + i16x8.ne + i16x8.ne + drop + ) + (func (;8;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.lt_s + i16x8.lt_s + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.lt_s + i16x8.lt_s + i16x8.lt_s + drop + ) + (func (;9;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.le_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.le_u + i16x8.le_u + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.le_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.le_u + i16x8.le_u + i16x8.le_u + drop + ) + (func (;10;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.gt_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.gt_u + i16x8.gt_u + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.gt_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.gt_u + i16x8.gt_u + i16x8.gt_u + drop + ) + (func (;11;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.ge_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.ge_s + i16x8.ge_s + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.ge_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.ge_s + i16x8.ge_s + i16x8.ge_s + drop + ) + (func (;12;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.le_u + i16x8.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + i16x8.gt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i16x8.lt_u + i16x8.ne + i16x8.ge_u + drop + ) + (memory (;0;) 1) + (export "eq-in-block" (func 0)) + (export "ne-in-block" (func 1)) + (export "lt_s-in-block" (func 2)) + (export "le_u-in-block" (func 3)) + (export "gt_u-in-block" (func 4)) + (export "ge_s-in-block" (func 5)) + (export "nested-eq" (func 6)) + (export "nested-ne" (func 7)) + (export "nested-lt_s" (func 8)) + (export "nested-le_u" (func 9)) + (export "nested-gt_u" (func 10)) + (export "nested-ge_s" (func 11)) + (export "as-param" (func 12)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_extadd_pairwise_i8x16.wast/0.print b/tests/snapshots/testsuite/simd_i16x8_extadd_pairwise_i8x16.wast/0.print new file mode 100644 index 0000000000..a6425898c5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_extadd_pairwise_i8x16.wast/0.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i16x8.extadd_pairwise_i8x16_s + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + i16x8.extadd_pairwise_i8x16_u + ) + (export "i16x8.extadd_pairwise_i8x16_s" (func 0)) + (export "i16x8.extadd_pairwise_i8x16_u" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_extmul_i8x16.wast/0.print b/tests/snapshots/testsuite/simd_i16x8_extmul_i8x16.wast/0.print new file mode 100644 index 0000000000..1f0c98169c --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_extmul_i8x16.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.extmul_low_i8x16_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.extmul_high_i8x16_s + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.extmul_low_i8x16_u + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.extmul_high_i8x16_u + ) + (export "i16x8.extmul_low_i8x16_s" (func 0)) + (export "i16x8.extmul_high_i8x16_s" (func 1)) + (export "i16x8.extmul_low_i8x16_u" (func 2)) + (export "i16x8.extmul_high_i8x16_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_q15mulr_sat_s.wast/0.print b/tests/snapshots/testsuite/simd_i16x8_q15mulr_sat_s.wast/0.print new file mode 100644 index 0000000000..b56543bebb --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_q15mulr_sat_s.wast/0.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.q15mulr_sat_s + ) + (export "i16x8.q15mulr_sat_s" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_sat_arith.wast/0.print b/tests/snapshots/testsuite/simd_i16x8_sat_arith.wast/0.print new file mode 100644 index 0000000000..5ccae3a80a --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_sat_arith.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.add_sat_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.add_sat_u + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub_sat_s + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub_sat_u + ) + (export "i16x8.add_sat_s" (func 0)) + (export "i16x8.add_sat_u" (func 1)) + (export "i16x8.sub_sat_s" (func 2)) + (export "i16x8.sub_sat_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i16x8_sat_arith.wast/213.print b/tests/snapshots/testsuite/simd_i16x8_sat_arith.wast/213.print new file mode 100644 index 0000000000..69bc906962 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i16x8_sat_arith.wast/213.print @@ -0,0 +1,64 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub_sat_s + local.get 2 + i16x8.add_sat_s + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub_sat_u + local.get 2 + i16x8.add_sat_s + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub_sat_s + local.get 2 + i16x8.add_sat_u + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.sub_sat_u + local.get 2 + i16x8.add_sat_u + ) + (func (;4;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.neg + local.get 1 + i16x8.add_sat_s + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.neg + local.get 1 + i16x8.add_sat_u + ) + (func (;6;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.neg + local.get 1 + i16x8.sub_sat_s + ) + (func (;7;) (type 1) (param v128 v128) (result v128) + local.get 0 + i16x8.neg + local.get 1 + i16x8.sub_sat_u + ) + (export "sat-add_s-sub_s" (func 0)) + (export "sat-add_s-sub_u" (func 1)) + (export "sat-add_u-sub_s" (func 2)) + (export "sat-add_u-sub_u" (func 3)) + (export "sat-add_s-neg" (func 4)) + (export "sat-add_u-neg" (func 5)) + (export "sat-sub_s-neg" (func 6)) + (export "sat-sub_u-neg" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_arith.wast/0.print b/tests/snapshots/testsuite/simd_i32x4_arith.wast/0.print new file mode 100644 index 0000000000..3a29b9fb5f --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_arith.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.add + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.sub + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.mul + ) + (func (;3;) (type 1) (param v128) (result v128) + local.get 0 + i32x4.neg + ) + (export "i32x4.add" (func 0)) + (export "i32x4.sub" (func 1)) + (export "i32x4.mul" (func 2)) + (export "i32x4.neg" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_arith.wast/186.print b/tests/snapshots/testsuite/simd_i32x4_arith.wast/186.print new file mode 100644 index 0000000000..e7db257de6 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_arith.wast/186.print @@ -0,0 +1,57 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.sub + local.get 2 + i32x4.add + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.add + local.get 2 + i32x4.mul + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.sub + local.get 2 + i32x4.mul + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.add + local.get 2 + i32x4.sub + ) + (func (;4;) (type 1) (param v128 v128) (result v128) + local.get 0 + i32x4.neg + local.get 1 + i32x4.add + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + i32x4.neg + local.get 1 + i32x4.mul + ) + (func (;6;) (type 1) (param v128 v128) (result v128) + local.get 0 + i32x4.neg + local.get 1 + i32x4.sub + ) + (export "add-sub" (func 0)) + (export "mul-add" (func 1)) + (export "mul-sub" (func 2)) + (export "sub-add" (func 3)) + (export "add-neg" (func 4)) + (export "mul-neg" (func 5)) + (export "sub-neg" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_arith2.wast/0.print b/tests/snapshots/testsuite/simd_i32x4_arith2.wast/0.print new file mode 100644 index 0000000000..4b3ffaf3a3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_arith2.wast/0.print @@ -0,0 +1,135 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (type (;2;) (func (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_u + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_s + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_u + ) + (func (;4;) (type 1) (param v128) (result v128) + local.get 0 + i32x4.abs + ) + (func (;5;) (type 2) (result v128) + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + v128.const i32x4 0xffffffff 0x40000000 0x7fffffff 0x80000000 + i32x4.min_s + ) + (func (;6;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.const i32x4 0x00000003 0x00000002 0x00000001 0x00000000 + i32x4.min_s + ) + (func (;7;) (type 2) (result v128) + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + v128.const i32x4 0xffffffff 0x40000000 0x7fffffff 0x80000000 + i32x4.min_u + ) + (func (;8;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.const i32x4 0x00000003 0x00000002 0x00000001 0x00000000 + i32x4.min_u + ) + (func (;9;) (type 2) (result v128) + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + v128.const i32x4 0xffffffff 0x40000000 0x7fffffff 0x80000000 + i32x4.max_s + ) + (func (;10;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.const i32x4 0x00000003 0x00000002 0x00000001 0x00000000 + i32x4.max_s + ) + (func (;11;) (type 2) (result v128) + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + v128.const i32x4 0xffffffff 0x40000000 0x7fffffff 0x80000000 + i32x4.max_u + ) + (func (;12;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.const i32x4 0x00000003 0x00000002 0x00000001 0x00000000 + i32x4.max_u + ) + (func (;13;) (type 2) (result v128) + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + i32x4.abs + ) + (func (;14;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + i32x4.min_s + ) + (func (;15;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + i32x4.min_s + ) + (func (;16;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + i32x4.min_u + ) + (func (;17;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + i32x4.min_u + ) + (func (;18;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + i32x4.max_s + ) + (func (;19;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + i32x4.max_s + ) + (func (;20;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80000000 0x7fffffff 0x40000000 0xffffffff + i32x4.max_u + ) + (func (;21;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + i32x4.max_u + ) + (export "i32x4.min_s" (func 0)) + (export "i32x4.min_u" (func 1)) + (export "i32x4.max_s" (func 2)) + (export "i32x4.max_u" (func 3)) + (export "i32x4.abs" (func 4)) + (export "i32x4.min_s_with_const_0" (func 5)) + (export "i32x4.min_s_with_const_1" (func 6)) + (export "i32x4.min_u_with_const_2" (func 7)) + (export "i32x4.min_u_with_const_3" (func 8)) + (export "i32x4.max_s_with_const_4" (func 9)) + (export "i32x4.max_s_with_const_5" (func 10)) + (export "i32x4.max_u_with_const_6" (func 11)) + (export "i32x4.max_u_with_const_7" (func 12)) + (export "i32x4.abs_with_const_8" (func 13)) + (export "i32x4.min_s_with_const_9" (func 14)) + (export "i32x4.min_s_with_const_10" (func 15)) + (export "i32x4.min_u_with_const_11" (func 16)) + (export "i32x4.min_u_with_const_12" (func 17)) + (export "i32x4.max_s_with_const_13" (func 18)) + (export "i32x4.max_s_with_const_14" (func 19)) + (export "i32x4.max_u_with_const_15" (func 20)) + (export "i32x4.max_u_with_const_16" (func 21)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_arith2.wast/123.print b/tests/snapshots/testsuite/simd_i32x4_arith2.wast/123.print new file mode 100644 index 0000000000..60d5c2d809 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_arith2.wast/123.print @@ -0,0 +1,195 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (type (;2;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_u + local.get 2 + i32x4.min_s + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_s + local.get 2 + i32x4.min_s + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_u + local.get 2 + i32x4.min_s + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_s + local.get 2 + i32x4.min_s + ) + (func (;4;) (type 1) (param v128 v128) (result v128) + local.get 0 + i32x4.abs + local.get 1 + i32x4.min_s + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_s + i32x4.abs + ) + (func (;6;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_u + local.get 2 + i32x4.min_u + ) + (func (;7;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_s + local.get 2 + i32x4.min_u + ) + (func (;8;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_u + local.get 2 + i32x4.min_u + ) + (func (;9;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_s + local.get 2 + i32x4.min_u + ) + (func (;10;) (type 1) (param v128 v128) (result v128) + local.get 0 + i32x4.abs + local.get 1 + i32x4.min_u + ) + (func (;11;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_u + i32x4.abs + ) + (func (;12;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_u + local.get 2 + i32x4.max_s + ) + (func (;13;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_s + local.get 2 + i32x4.max_s + ) + (func (;14;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_u + local.get 2 + i32x4.max_s + ) + (func (;15;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_s + local.get 2 + i32x4.max_s + ) + (func (;16;) (type 1) (param v128 v128) (result v128) + local.get 0 + i32x4.abs + local.get 1 + i32x4.max_s + ) + (func (;17;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_s + i32x4.abs + ) + (func (;18;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_u + local.get 2 + i32x4.max_u + ) + (func (;19;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_s + local.get 2 + i32x4.max_u + ) + (func (;20;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_u + local.get 2 + i32x4.max_u + ) + (func (;21;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.min_s + local.get 2 + i32x4.max_u + ) + (func (;22;) (type 1) (param v128 v128) (result v128) + local.get 0 + i32x4.abs + local.get 1 + i32x4.max_u + ) + (func (;23;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.max_u + i32x4.abs + ) + (func (;24;) (type 2) (param v128) (result v128) + local.get 0 + i32x4.abs + i32x4.abs + ) + (export "i32x4.min_s-i32x4.max_u" (func 0)) + (export "i32x4.min_s-i32x4.max_s" (func 1)) + (export "i32x4.min_s-i32x4.min_u" (func 2)) + (export "i32x4.min_s-i32x4.min_s" (func 3)) + (export "i32x4.min_s-i32x4.abs" (func 4)) + (export "i32x4.abs-i32x4.min_s" (func 5)) + (export "i32x4.min_u-i32x4.max_u" (func 6)) + (export "i32x4.min_u-i32x4.max_s" (func 7)) + (export "i32x4.min_u-i32x4.min_u" (func 8)) + (export "i32x4.min_u-i32x4.min_s" (func 9)) + (export "i32x4.min_u-i32x4.abs" (func 10)) + (export "i32x4.abs-i32x4.min_u" (func 11)) + (export "i32x4.max_s-i32x4.max_u" (func 12)) + (export "i32x4.max_s-i32x4.max_s" (func 13)) + (export "i32x4.max_s-i32x4.min_u" (func 14)) + (export "i32x4.max_s-i32x4.min_s" (func 15)) + (export "i32x4.max_s-i32x4.abs" (func 16)) + (export "i32x4.abs-i32x4.max_s" (func 17)) + (export "i32x4.max_u-i32x4.max_u" (func 18)) + (export "i32x4.max_u-i32x4.max_s" (func 19)) + (export "i32x4.max_u-i32x4.min_u" (func 20)) + (export "i32x4.max_u-i32x4.min_s" (func 21)) + (export "i32x4.max_u-i32x4.abs" (func 22)) + (export "i32x4.abs-i32x4.max_u" (func 23)) + (export "i32x4.abs-i32x4.abs" (func 24)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_cmp.wast/0.print b/tests/snapshots/testsuite/simd_i32x4_cmp.wast/0.print new file mode 100644 index 0000000000..3abb5c862c --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_cmp.wast/0.print @@ -0,0 +1,63 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.eq + ) + (func (;1;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.ne + ) + (func (;2;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.lt_s + ) + (func (;3;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.lt_u + ) + (func (;4;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.le_s + ) + (func (;5;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.le_u + ) + (func (;6;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.gt_s + ) + (func (;7;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.gt_u + ) + (func (;8;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.ge_s + ) + (func (;9;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i32x4.ge_u + ) + (export "eq" (func 0)) + (export "ne" (func 1)) + (export "lt_s" (func 2)) + (export "lt_u" (func 3)) + (export "le_s" (func 4)) + (export "le_u" (func 5)) + (export "gt_s" (func 6)) + (export "gt_u" (func 7)) + (export "ge_s" (func 8)) + (export "ge_u" (func 9)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_cmp.wast/431.print b/tests/snapshots/testsuite/simd_i32x4_cmp.wast/431.print new file mode 100644 index 0000000000..ff4491ce3d --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_cmp.wast/431.print @@ -0,0 +1,295 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i32x4.eq + end + drop + end + ) + (func (;1;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i32x4.ne + end + drop + end + ) + (func (;2;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i32x4.lt_s + end + drop + end + ) + (func (;3;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i32x4.le_u + end + drop + end + ) + (func (;4;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i32x4.gt_u + end + drop + end + ) + (func (;5;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i32x4.ge_s + end + drop + end + ) + (func (;6;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.eq + i32x4.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.eq + i32x4.eq + i32x4.eq + drop + ) + (func (;7;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.ne + i32x4.ne + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.ne + i32x4.ne + i32x4.ne + drop + ) + (func (;8;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.lt_s + i32x4.lt_s + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.lt_s + i32x4.lt_s + i32x4.lt_s + drop + ) + (func (;9;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.le_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.le_u + i32x4.le_u + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.le_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.le_u + i32x4.le_u + i32x4.le_u + drop + ) + (func (;10;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.gt_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.gt_u + i32x4.gt_u + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.gt_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.gt_u + i32x4.gt_u + i32x4.gt_u + drop + ) + (func (;11;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.ge_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.ge_s + i32x4.ge_s + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.ge_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.ge_s + i32x4.ge_s + i32x4.ge_s + drop + ) + (func (;12;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.le_u + i32x4.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + i32x4.gt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i32x4.lt_u + i32x4.ne + i32x4.ge_u + drop + ) + (memory (;0;) 1) + (export "eq-in-block" (func 0)) + (export "ne-in-block" (func 1)) + (export "lt_s-in-block" (func 2)) + (export "le_u-in-block" (func 3)) + (export "gt_u-in-block" (func 4)) + (export "ge_s-in-block" (func 5)) + (export "nested-eq" (func 6)) + (export "nested-ne" (func 7)) + (export "nested-lt_s" (func 8)) + (export "nested-le_u" (func 9)) + (export "nested-gt_u" (func 10)) + (export "nested-ge_s" (func 11)) + (export "as-param" (func 12)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_dot_i16x8.wast/0.print b/tests/snapshots/testsuite/simd_i32x4_dot_i16x8.wast/0.print new file mode 100644 index 0000000000..960eec9209 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_dot_i16x8.wast/0.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.dot_i16x8_s + ) + (export "i32x4.dot_i16x8_s" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_extadd_pairwise_i16x8.wast/0.print b/tests/snapshots/testsuite/simd_i32x4_extadd_pairwise_i16x8.wast/0.print new file mode 100644 index 0000000000..f9b52f8c02 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_extadd_pairwise_i16x8.wast/0.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.extadd_pairwise_i16x8_s + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.extadd_pairwise_i16x8_u + ) + (export "i32x4.extadd_pairwise_i16x8_s" (func 0)) + (export "i32x4.extadd_pairwise_i16x8_u" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_extmul_i16x8.wast/0.print b/tests/snapshots/testsuite/simd_i32x4_extmul_i16x8.wast/0.print new file mode 100644 index 0000000000..8976eeb7ac --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_extmul_i16x8.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.extmul_low_i16x8_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.extmul_high_i16x8_s + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.extmul_low_i16x8_u + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.extmul_high_i16x8_u + ) + (export "i32x4.extmul_low_i16x8_s" (func 0)) + (export "i32x4.extmul_high_i16x8_s" (func 1)) + (export "i32x4.extmul_low_i16x8_u" (func 2)) + (export "i32x4.extmul_high_i16x8_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_trunc_sat_f32x4.wast/0.print b/tests/snapshots/testsuite/simd_i32x4_trunc_sat_f32x4.wast/0.print new file mode 100644 index 0000000000..308277f25e --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_trunc_sat_f32x4.wast/0.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.trunc_sat_f32x4_s + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.trunc_sat_f32x4_u + ) + (export "i32x4.trunc_sat_f32x4_s" (func 0)) + (export "i32x4.trunc_sat_f32x4_u" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i32x4_trunc_sat_f64x2.wast/0.print b/tests/snapshots/testsuite/simd_i32x4_trunc_sat_f64x2.wast/0.print new file mode 100644 index 0000000000..d0e6ffdae8 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i32x4_trunc_sat_f64x2.wast/0.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.trunc_sat_f64x2_s_zero + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.trunc_sat_f64x2_u_zero + ) + (export "i32x4.trunc_sat_f64x2_s_zero" (func 0)) + (export "i32x4.trunc_sat_f64x2_u_zero" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i64x2_arith.wast/0.print b/tests/snapshots/testsuite/simd_i64x2_arith.wast/0.print new file mode 100644 index 0000000000..08199e61dd --- /dev/null +++ b/tests/snapshots/testsuite/simd_i64x2_arith.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.add + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.sub + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.mul + ) + (func (;3;) (type 1) (param v128) (result v128) + local.get 0 + i64x2.neg + ) + (export "i64x2.add" (func 0)) + (export "i64x2.sub" (func 1)) + (export "i64x2.mul" (func 2)) + (export "i64x2.neg" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i64x2_arith.wast/192.print b/tests/snapshots/testsuite/simd_i64x2_arith.wast/192.print new file mode 100644 index 0000000000..d19027e152 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i64x2_arith.wast/192.print @@ -0,0 +1,57 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.sub + local.get 2 + i64x2.add + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.add + local.get 2 + i64x2.mul + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.sub + local.get 2 + i64x2.mul + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.add + local.get 2 + i64x2.sub + ) + (func (;4;) (type 1) (param v128 v128) (result v128) + local.get 0 + i64x2.neg + local.get 1 + i64x2.add + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + i64x2.neg + local.get 1 + i64x2.mul + ) + (func (;6;) (type 1) (param v128 v128) (result v128) + local.get 0 + i64x2.neg + local.get 1 + i64x2.sub + ) + (export "add-sub" (func 0)) + (export "mul-add" (func 1)) + (export "mul-sub" (func 2)) + (export "sub-add" (func 3)) + (export "add-neg" (func 4)) + (export "mul-neg" (func 5)) + (export "sub-neg" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i64x2_arith2.wast/0.print b/tests/snapshots/testsuite/simd_i64x2_arith2.wast/0.print new file mode 100644 index 0000000000..07c187a213 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i64x2_arith2.wast/0.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (type (;1;) (func (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i64x2.abs + ) + (func (;1;) (type 1) (result v128) + v128.const i32x4 0x00000000 0x80000000 0xffffffff 0x7fffffff + i64x2.abs + ) + (export "i64x2.abs" (func 0)) + (export "i64x2.abs_with_const_0" (func 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i64x2_arith2.wast/23.print b/tests/snapshots/testsuite/simd_i64x2_arith2.wast/23.print new file mode 100644 index 0000000000..66f1b4f9d5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i64x2_arith2.wast/23.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i64x2.abs + i64x2.abs + ) + (export "i64x2.abs-i64x2.abs" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i64x2_cmp.wast/0.print b/tests/snapshots/testsuite/simd_i64x2_cmp.wast/0.print new file mode 100644 index 0000000000..3c20d0c3e0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i64x2_cmp.wast/0.print @@ -0,0 +1,39 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i64x2.eq + ) + (func (;1;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i64x2.ne + ) + (func (;2;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i64x2.lt_s + ) + (func (;3;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i64x2.le_s + ) + (func (;4;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i64x2.gt_s + ) + (func (;5;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i64x2.ge_s + ) + (export "eq" (func 0)) + (export "ne" (func 1)) + (export "lt_s" (func 2)) + (export "le_s" (func 3)) + (export "gt_s" (func 4)) + (export "ge_s" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i64x2_extmul_i32x4.wast/0.print b/tests/snapshots/testsuite/simd_i64x2_extmul_i32x4.wast/0.print new file mode 100644 index 0000000000..ca5c6b05f3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i64x2_extmul_i32x4.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.extmul_low_i32x4_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.extmul_high_i32x4_s + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.extmul_low_i32x4_u + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.extmul_high_i32x4_u + ) + (export "i64x2.extmul_low_i32x4_s" (func 0)) + (export "i64x2.extmul_high_i32x4_s" (func 1)) + (export "i64x2.extmul_low_i32x4_u" (func 2)) + (export "i64x2.extmul_high_i32x4_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i8x16_arith.wast/0.print b/tests/snapshots/testsuite/simd_i8x16_arith.wast/0.print new file mode 100644 index 0000000000..986cb777ca --- /dev/null +++ b/tests/snapshots/testsuite/simd_i8x16_arith.wast/0.print @@ -0,0 +1,21 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.add + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.sub + ) + (func (;2;) (type 1) (param v128) (result v128) + local.get 0 + i8x16.neg + ) + (export "i8x16.add" (func 0)) + (export "i8x16.sub" (func 1)) + (export "i8x16.neg" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i8x16_arith.wast/126.print b/tests/snapshots/testsuite/simd_i8x16_arith.wast/126.print new file mode 100644 index 0000000000..c4ac9df5c0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i8x16_arith.wast/126.print @@ -0,0 +1,34 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.sub + local.get 2 + i8x16.add + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.add + local.get 2 + i8x16.sub + ) + (func (;2;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.neg + local.get 1 + i8x16.add + ) + (func (;3;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.neg + local.get 1 + i8x16.sub + ) + (export "add-sub" (func 0)) + (export "sub-add" (func 1)) + (export "add-neg" (func 2)) + (export "sub-neg" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i8x16_arith2.wast/0.print b/tests/snapshots/testsuite/simd_i8x16_arith2.wast/0.print new file mode 100644 index 0000000000..defbd7d949 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i8x16_arith2.wast/0.print @@ -0,0 +1,175 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (type (;2;) (func (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_u + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_s + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_u + ) + (func (;4;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.avgr_u + ) + (func (;5;) (type 1) (param v128) (result v128) + local.get 0 + i8x16.abs + ) + (func (;6;) (type 1) (param v128) (result v128) + local.get 0 + i8x16.popcnt + ) + (func (;7;) (type 2) (result v128) + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + v128.const i32x4 0xffffffff 0x40404040 0x7f7f7f7f 0x80808080 + i8x16.min_s + ) + (func (;8;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + v128.const i32x4 0x03030303 0x02020202 0x01010101 0x00000000 + i8x16.min_s + ) + (func (;9;) (type 2) (result v128) + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + v128.const i32x4 0xffffffff 0x40404040 0x7f7f7f7f 0x80808080 + i8x16.min_u + ) + (func (;10;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + v128.const i32x4 0x03030303 0x02020202 0x01010101 0x00000000 + i8x16.min_u + ) + (func (;11;) (type 2) (result v128) + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + v128.const i32x4 0xffffffff 0x40404040 0x7f7f7f7f 0x80808080 + i8x16.max_s + ) + (func (;12;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + v128.const i32x4 0x03030303 0x02020202 0x01010101 0x00000000 + i8x16.max_s + ) + (func (;13;) (type 2) (result v128) + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + v128.const i32x4 0xffffffff 0x40404040 0x7f7f7f7f 0x80808080 + i8x16.max_u + ) + (func (;14;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + v128.const i32x4 0x03030303 0x02020202 0x01010101 0x00000000 + i8x16.max_u + ) + (func (;15;) (type 2) (result v128) + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + v128.const i32x4 0xffffffff 0x40404040 0x7f7f7f7f 0x80808080 + i8x16.avgr_u + ) + (func (;16;) (type 2) (result v128) + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + v128.const i32x4 0x03030303 0x02020202 0x01010101 0x00000000 + i8x16.avgr_u + ) + (func (;17;) (type 2) (result v128) + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + i8x16.abs + ) + (func (;18;) (type 2) (result v128) + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + i8x16.popcnt + ) + (func (;19;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + i8x16.min_s + ) + (func (;20;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + i8x16.min_s + ) + (func (;21;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + i8x16.min_u + ) + (func (;22;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + i8x16.min_u + ) + (func (;23;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + i8x16.max_s + ) + (func (;24;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + i8x16.max_s + ) + (func (;25;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + i8x16.max_u + ) + (func (;26;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + i8x16.max_u + ) + (func (;27;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x80808080 0x7f7f7f7f 0x40404040 0xffffffff + i8x16.avgr_u + ) + (func (;28;) (type 1) (param v128) (result v128) + local.get 0 + v128.const i32x4 0x00000000 0x01010101 0x02020202 0x03030303 + i8x16.avgr_u + ) + (export "i8x16.min_s" (func 0)) + (export "i8x16.min_u" (func 1)) + (export "i8x16.max_s" (func 2)) + (export "i8x16.max_u" (func 3)) + (export "i8x16.avgr_u" (func 4)) + (export "i8x16.abs" (func 5)) + (export "i8x16.popcnt" (func 6)) + (export "i8x16.min_s_with_const_0" (func 7)) + (export "i8x16.min_s_with_const_1" (func 8)) + (export "i8x16.min_u_with_const_2" (func 9)) + (export "i8x16.min_u_with_const_3" (func 10)) + (export "i8x16.max_s_with_const_4" (func 11)) + (export "i8x16.max_s_with_const_5" (func 12)) + (export "i8x16.max_u_with_const_6" (func 13)) + (export "i8x16.max_u_with_const_7" (func 14)) + (export "i8x16.avgr_u_with_const_8" (func 15)) + (export "i8x16.avgr_u_with_const_9" (func 16)) + (export "i8x16.abs_with_const_10" (func 17)) + (export "i8x16.popcnt_with_const_11" (func 18)) + (export "i8x16.min_s_with_const_12" (func 19)) + (export "i8x16.min_s_with_const_13" (func 20)) + (export "i8x16.min_u_with_const_14" (func 21)) + (export "i8x16.min_u_with_const_15" (func 22)) + (export "i8x16.max_s_with_const_16" (func 23)) + (export "i8x16.max_s_with_const_17" (func 24)) + (export "i8x16.max_u_with_const_18" (func 25)) + (export "i8x16.max_u_with_const_19" (func 26)) + (export "i8x16.avgr_u_with_const_20" (func 27)) + (export "i8x16.avgr_u_with_const_21" (func 28)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i8x16_arith2.wast/161.print b/tests/snapshots/testsuite/simd_i8x16_arith2.wast/161.print new file mode 100644 index 0000000000..6bf44ee2fa --- /dev/null +++ b/tests/snapshots/testsuite/simd_i8x16_arith2.wast/161.print @@ -0,0 +1,369 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (type (;2;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.avgr_u + local.get 2 + i8x16.min_s + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_u + local.get 2 + i8x16.min_s + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_s + local.get 2 + i8x16.min_s + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_u + local.get 2 + i8x16.min_s + ) + (func (;4;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_s + local.get 2 + i8x16.min_s + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.abs + local.get 1 + i8x16.min_s + ) + (func (;6;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_s + i8x16.abs + ) + (func (;7;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.popcnt + local.get 1 + i8x16.min_s + ) + (func (;8;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_s + i8x16.popcnt + ) + (func (;9;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.avgr_u + local.get 2 + i8x16.min_u + ) + (func (;10;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_u + local.get 2 + i8x16.min_u + ) + (func (;11;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_s + local.get 2 + i8x16.min_u + ) + (func (;12;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_u + local.get 2 + i8x16.min_u + ) + (func (;13;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_s + local.get 2 + i8x16.min_u + ) + (func (;14;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.abs + local.get 1 + i8x16.min_u + ) + (func (;15;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_u + i8x16.abs + ) + (func (;16;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.popcnt + local.get 1 + i8x16.min_u + ) + (func (;17;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_u + i8x16.popcnt + ) + (func (;18;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.avgr_u + local.get 2 + i8x16.max_s + ) + (func (;19;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_u + local.get 2 + i8x16.max_s + ) + (func (;20;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_s + local.get 2 + i8x16.max_s + ) + (func (;21;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_u + local.get 2 + i8x16.max_s + ) + (func (;22;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_s + local.get 2 + i8x16.max_s + ) + (func (;23;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.abs + local.get 1 + i8x16.max_s + ) + (func (;24;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_s + i8x16.abs + ) + (func (;25;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.popcnt + local.get 1 + i8x16.max_s + ) + (func (;26;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_s + i8x16.popcnt + ) + (func (;27;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.avgr_u + local.get 2 + i8x16.max_u + ) + (func (;28;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_u + local.get 2 + i8x16.max_u + ) + (func (;29;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_s + local.get 2 + i8x16.max_u + ) + (func (;30;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_u + local.get 2 + i8x16.max_u + ) + (func (;31;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_s + local.get 2 + i8x16.max_u + ) + (func (;32;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.abs + local.get 1 + i8x16.max_u + ) + (func (;33;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_u + i8x16.abs + ) + (func (;34;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.popcnt + local.get 1 + i8x16.max_u + ) + (func (;35;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_u + i8x16.popcnt + ) + (func (;36;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.avgr_u + local.get 2 + i8x16.avgr_u + ) + (func (;37;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_u + local.get 2 + i8x16.avgr_u + ) + (func (;38;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.max_s + local.get 2 + i8x16.avgr_u + ) + (func (;39;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_u + local.get 2 + i8x16.avgr_u + ) + (func (;40;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.min_s + local.get 2 + i8x16.avgr_u + ) + (func (;41;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.abs + local.get 1 + i8x16.avgr_u + ) + (func (;42;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.avgr_u + i8x16.abs + ) + (func (;43;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.popcnt + local.get 1 + i8x16.avgr_u + ) + (func (;44;) (type 1) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.avgr_u + i8x16.popcnt + ) + (func (;45;) (type 2) (param v128) (result v128) + local.get 0 + i8x16.popcnt + i8x16.abs + ) + (func (;46;) (type 2) (param v128) (result v128) + local.get 0 + i8x16.abs + i8x16.abs + ) + (func (;47;) (type 2) (param v128) (result v128) + local.get 0 + i8x16.popcnt + i8x16.popcnt + ) + (func (;48;) (type 2) (param v128) (result v128) + local.get 0 + i8x16.abs + i8x16.popcnt + ) + (export "i8x16.min_s-i8x16.avgr_u" (func 0)) + (export "i8x16.min_s-i8x16.max_u" (func 1)) + (export "i8x16.min_s-i8x16.max_s" (func 2)) + (export "i8x16.min_s-i8x16.min_u" (func 3)) + (export "i8x16.min_s-i8x16.min_s" (func 4)) + (export "i8x16.min_s-i8x16.abs" (func 5)) + (export "i8x16.abs-i8x16.min_s" (func 6)) + (export "i8x16.min_s-i8x16.popcnt" (func 7)) + (export "i8x16.popcnt-i8x16.min_s" (func 8)) + (export "i8x16.min_u-i8x16.avgr_u" (func 9)) + (export "i8x16.min_u-i8x16.max_u" (func 10)) + (export "i8x16.min_u-i8x16.max_s" (func 11)) + (export "i8x16.min_u-i8x16.min_u" (func 12)) + (export "i8x16.min_u-i8x16.min_s" (func 13)) + (export "i8x16.min_u-i8x16.abs" (func 14)) + (export "i8x16.abs-i8x16.min_u" (func 15)) + (export "i8x16.min_u-i8x16.popcnt" (func 16)) + (export "i8x16.popcnt-i8x16.min_u" (func 17)) + (export "i8x16.max_s-i8x16.avgr_u" (func 18)) + (export "i8x16.max_s-i8x16.max_u" (func 19)) + (export "i8x16.max_s-i8x16.max_s" (func 20)) + (export "i8x16.max_s-i8x16.min_u" (func 21)) + (export "i8x16.max_s-i8x16.min_s" (func 22)) + (export "i8x16.max_s-i8x16.abs" (func 23)) + (export "i8x16.abs-i8x16.max_s" (func 24)) + (export "i8x16.max_s-i8x16.popcnt" (func 25)) + (export "i8x16.popcnt-i8x16.max_s" (func 26)) + (export "i8x16.max_u-i8x16.avgr_u" (func 27)) + (export "i8x16.max_u-i8x16.max_u" (func 28)) + (export "i8x16.max_u-i8x16.max_s" (func 29)) + (export "i8x16.max_u-i8x16.min_u" (func 30)) + (export "i8x16.max_u-i8x16.min_s" (func 31)) + (export "i8x16.max_u-i8x16.abs" (func 32)) + (export "i8x16.abs-i8x16.max_u" (func 33)) + (export "i8x16.max_u-i8x16.popcnt" (func 34)) + (export "i8x16.popcnt-i8x16.max_u" (func 35)) + (export "i8x16.avgr_u-i8x16.avgr_u" (func 36)) + (export "i8x16.avgr_u-i8x16.max_u" (func 37)) + (export "i8x16.avgr_u-i8x16.max_s" (func 38)) + (export "i8x16.avgr_u-i8x16.min_u" (func 39)) + (export "i8x16.avgr_u-i8x16.min_s" (func 40)) + (export "i8x16.avgr_u-i8x16.abs" (func 41)) + (export "i8x16.abs-i8x16.avgr_u" (func 42)) + (export "i8x16.avgr_u-i8x16.popcnt" (func 43)) + (export "i8x16.popcnt-i8x16.avgr_u" (func 44)) + (export "i8x16.abs-i8x16.popcnt" (func 45)) + (export "i8x16.abs-i8x16.abs" (func 46)) + (export "i8x16.popcnt-i8x16.popcnt" (func 47)) + (export "i8x16.popcnt-i8x16.abs" (func 48)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i8x16_cmp.wast/0.print b/tests/snapshots/testsuite/simd_i8x16_cmp.wast/0.print new file mode 100644 index 0000000000..e5b66e6587 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i8x16_cmp.wast/0.print @@ -0,0 +1,63 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.eq + ) + (func (;1;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.ne + ) + (func (;2;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.lt_s + ) + (func (;3;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.lt_u + ) + (func (;4;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.le_s + ) + (func (;5;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.le_u + ) + (func (;6;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.gt_s + ) + (func (;7;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.gt_u + ) + (func (;8;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.ge_s + ) + (func (;9;) (type 0) (param $x v128) (param $y v128) (result v128) + local.get $x + local.get $y + i8x16.ge_u + ) + (export "eq" (func 0)) + (export "ne" (func 1)) + (export "lt_s" (func 2)) + (export "lt_u" (func 3)) + (export "le_s" (func 4)) + (export "le_u" (func 5)) + (export "gt_s" (func 6)) + (export "gt_u" (func 7)) + (export "ge_s" (func 8)) + (export "ge_u" (func 9)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i8x16_cmp.wast/411.print b/tests/snapshots/testsuite/simd_i8x16_cmp.wast/411.print new file mode 100644 index 0000000000..ab084c43d5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i8x16_cmp.wast/411.print @@ -0,0 +1,295 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i8x16.eq + end + drop + end + ) + (func (;1;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i8x16.ne + end + drop + end + ) + (func (;2;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i8x16.lt_s + end + drop + end + ) + (func (;3;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i8x16.le_u + end + drop + end + ) + (func (;4;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i8x16.gt_u + end + drop + end + ) + (func (;5;) (type 0) + block ;; label = @1 + block (result v128) ;; label = @2 + block (result v128) ;; label = @3 + i32.const 0 + v128.load + end + block (result v128) ;; label = @3 + i32.const 1 + v128.load + end + i8x16.ge_s + end + drop + end + ) + (func (;6;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.eq + i8x16.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.eq + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.eq + i8x16.eq + i8x16.eq + drop + ) + (func (;7;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.ne + i8x16.ne + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.ne + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.ne + i8x16.ne + i8x16.ne + drop + ) + (func (;8;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.lt_s + i8x16.lt_s + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.lt_s + i8x16.lt_s + i8x16.lt_s + drop + ) + (func (;9;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.le_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.le_u + i8x16.le_u + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.le_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.le_u + i8x16.le_u + i8x16.le_u + drop + ) + (func (;10;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.gt_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.gt_u + i8x16.gt_u + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.gt_u + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.gt_u + i8x16.gt_u + i8x16.gt_u + drop + ) + (func (;11;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.ge_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.ge_s + i8x16.ge_s + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.ge_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.ge_s + i8x16.ge_s + i8x16.ge_s + drop + ) + (func (;12;) (type 0) + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.lt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.le_u + i8x16.eq + i32.const 0 + v128.load + i32.const 1 + v128.load + i8x16.gt_s + i32.const 2 + v128.load + i32.const 3 + v128.load + i8x16.lt_u + i8x16.ne + i8x16.ge_u + drop + ) + (memory (;0;) 1) + (export "eq-in-block" (func 0)) + (export "ne-in-block" (func 1)) + (export "lt_s-in-block" (func 2)) + (export "le_u-in-block" (func 3)) + (export "gt_u-in-block" (func 4)) + (export "ge_s-in-block" (func 5)) + (export "nested-eq" (func 6)) + (export "nested-ne" (func 7)) + (export "nested-lt_s" (func 8)) + (export "nested-le_u" (func 9)) + (export "nested-gt_u" (func 10)) + (export "nested-ge_s" (func 11)) + (export "as-param" (func 12)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i8x16_sat_arith.wast/0.print b/tests/snapshots/testsuite/simd_i8x16_sat_arith.wast/0.print new file mode 100644 index 0000000000..bb284025d2 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i8x16_sat_arith.wast/0.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.add_sat_s + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.add_sat_u + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.sub_sat_s + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.sub_sat_u + ) + (export "i8x16.add_sat_s" (func 0)) + (export "i8x16.add_sat_u" (func 1)) + (export "i8x16.sub_sat_s" (func 2)) + (export "i8x16.sub_sat_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_i8x16_sat_arith.wast/205.print b/tests/snapshots/testsuite/simd_i8x16_sat_arith.wast/205.print new file mode 100644 index 0000000000..f741c36017 --- /dev/null +++ b/tests/snapshots/testsuite/simd_i8x16_sat_arith.wast/205.print @@ -0,0 +1,64 @@ +(module + (type (;0;) (func (param v128 v128 v128) (result v128))) + (type (;1;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.sub_sat_s + local.get 2 + i8x16.add_sat_s + ) + (func (;1;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.sub_sat_u + local.get 2 + i8x16.add_sat_s + ) + (func (;2;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.sub_sat_s + local.get 2 + i8x16.add_sat_u + ) + (func (;3;) (type 0) (param v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.sub_sat_u + local.get 2 + i8x16.add_sat_u + ) + (func (;4;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.neg + local.get 1 + i8x16.add_sat_s + ) + (func (;5;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.neg + local.get 1 + i8x16.add_sat_u + ) + (func (;6;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.neg + local.get 1 + i8x16.sub_sat_s + ) + (func (;7;) (type 1) (param v128 v128) (result v128) + local.get 0 + i8x16.neg + local.get 1 + i8x16.sub_sat_u + ) + (export "sat-add_s-sub_s" (func 0)) + (export "sat-add_s-sub_u" (func 1)) + (export "sat-add_u-sub_s" (func 2)) + (export "sat-add_u-sub_u" (func 3)) + (export "sat-add_s-neg" (func 4)) + (export "sat-add_u-neg" (func 5)) + (export "sat-sub_s-neg" (func 6)) + (export "sat-sub_u-neg" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_int_to_int_extend.wast/0.print b/tests/snapshots/testsuite/simd_int_to_int_extend.wast/0.print new file mode 100644 index 0000000000..1c436b6cab --- /dev/null +++ b/tests/snapshots/testsuite/simd_int_to_int_extend.wast/0.print @@ -0,0 +1,63 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i16x8.extend_high_i8x16_s + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + i16x8.extend_high_i8x16_u + ) + (func (;2;) (type 0) (param v128) (result v128) + local.get 0 + i16x8.extend_low_i8x16_s + ) + (func (;3;) (type 0) (param v128) (result v128) + local.get 0 + i16x8.extend_low_i8x16_u + ) + (func (;4;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.extend_high_i16x8_s + ) + (func (;5;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.extend_high_i16x8_u + ) + (func (;6;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.extend_low_i16x8_s + ) + (func (;7;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.extend_low_i16x8_u + ) + (func (;8;) (type 0) (param v128) (result v128) + local.get 0 + i64x2.extend_high_i32x4_s + ) + (func (;9;) (type 0) (param v128) (result v128) + local.get 0 + i64x2.extend_high_i32x4_u + ) + (func (;10;) (type 0) (param v128) (result v128) + local.get 0 + i64x2.extend_low_i32x4_s + ) + (func (;11;) (type 0) (param v128) (result v128) + local.get 0 + i64x2.extend_low_i32x4_u + ) + (export "i16x8.extend_high_i8x16_s" (func 0)) + (export "i16x8.extend_high_i8x16_u" (func 1)) + (export "i16x8.extend_low_i8x16_s" (func 2)) + (export "i16x8.extend_low_i8x16_u" (func 3)) + (export "i32x4.extend_high_i16x8_s" (func 4)) + (export "i32x4.extend_high_i16x8_u" (func 5)) + (export "i32x4.extend_low_i16x8_s" (func 6)) + (export "i32x4.extend_low_i16x8_u" (func 7)) + (export "i64x2.extend_high_i32x4_s" (func 8)) + (export "i64x2.extend_high_i32x4_u" (func 9)) + (export "i64x2.extend_low_i32x4_s" (func 10)) + (export "i64x2.extend_low_i32x4_u" (func 11)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/0.print b/tests/snapshots/testsuite/simd_lane.wast/0.print new file mode 100644 index 0000000000..ed4fa2f057 --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/0.print @@ -0,0 +1,211 @@ +(module + (type (;0;) (func (param v128) (result i32))) + (type (;1;) (func (param v128) (result f32))) + (type (;2;) (func (param v128 i32) (result v128))) + (type (;3;) (func (param v128 f32) (result v128))) + (type (;4;) (func (param v128) (result i64))) + (type (;5;) (func (param v128) (result f64))) + (type (;6;) (func (param v128 i64) (result v128))) + (type (;7;) (func (param v128 f64) (result v128))) + (type (;8;) (func (param v128 v128) (result v128))) + (func (;0;) (type 0) (param v128) (result i32) + local.get 0 + i8x16.extract_lane_s 0 + ) + (func (;1;) (type 0) (param v128) (result i32) + local.get 0 + i8x16.extract_lane_s 15 + ) + (func (;2;) (type 0) (param v128) (result i32) + local.get 0 + i8x16.extract_lane_u 0 + ) + (func (;3;) (type 0) (param v128) (result i32) + local.get 0 + i8x16.extract_lane_u 15 + ) + (func (;4;) (type 0) (param v128) (result i32) + local.get 0 + i16x8.extract_lane_s 0 + ) + (func (;5;) (type 0) (param v128) (result i32) + local.get 0 + i16x8.extract_lane_s 7 + ) + (func (;6;) (type 0) (param v128) (result i32) + local.get 0 + i16x8.extract_lane_u 0 + ) + (func (;7;) (type 0) (param v128) (result i32) + local.get 0 + i16x8.extract_lane_u 7 + ) + (func (;8;) (type 0) (param v128) (result i32) + local.get 0 + i32x4.extract_lane 0 + ) + (func (;9;) (type 0) (param v128) (result i32) + local.get 0 + i32x4.extract_lane 3 + ) + (func (;10;) (type 1) (param v128) (result f32) + local.get 0 + f32x4.extract_lane 0 + ) + (func (;11;) (type 1) (param v128) (result f32) + local.get 0 + f32x4.extract_lane 3 + ) + (func (;12;) (type 2) (param v128 i32) (result v128) + local.get 0 + local.get 1 + i8x16.replace_lane 0 + ) + (func (;13;) (type 2) (param v128 i32) (result v128) + local.get 0 + local.get 1 + i8x16.replace_lane 15 + ) + (func (;14;) (type 2) (param v128 i32) (result v128) + local.get 0 + local.get 1 + i16x8.replace_lane 0 + ) + (func (;15;) (type 2) (param v128 i32) (result v128) + local.get 0 + local.get 1 + i16x8.replace_lane 7 + ) + (func (;16;) (type 2) (param v128 i32) (result v128) + local.get 0 + local.get 1 + i32x4.replace_lane 0 + ) + (func (;17;) (type 2) (param v128 i32) (result v128) + local.get 0 + local.get 1 + i32x4.replace_lane 3 + ) + (func (;18;) (type 3) (param v128 f32) (result v128) + local.get 0 + local.get 1 + f32x4.replace_lane 0 + ) + (func (;19;) (type 3) (param v128 f32) (result v128) + local.get 0 + local.get 1 + f32x4.replace_lane 3 + ) + (func (;20;) (type 4) (param v128) (result i64) + local.get 0 + i64x2.extract_lane 0 + ) + (func (;21;) (type 4) (param v128) (result i64) + local.get 0 + i64x2.extract_lane 1 + ) + (func (;22;) (type 5) (param v128) (result f64) + local.get 0 + f64x2.extract_lane 0 + ) + (func (;23;) (type 5) (param v128) (result f64) + local.get 0 + f64x2.extract_lane 1 + ) + (func (;24;) (type 6) (param v128 i64) (result v128) + local.get 0 + local.get 1 + i64x2.replace_lane 0 + ) + (func (;25;) (type 6) (param v128 i64) (result v128) + local.get 0 + local.get 1 + i64x2.replace_lane 1 + ) + (func (;26;) (type 7) (param v128 f64) (result v128) + local.get 0 + local.get 1 + f64x2.replace_lane 0 + ) + (func (;27;) (type 7) (param v128 f64) (result v128) + local.get 0 + local.get 1 + f64x2.replace_lane 1 + ) + (func (;28;) (type 8) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.swizzle + ) + (func (;29;) (type 8) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + ) + (func (;30;) (type 8) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + ) + (func (;31;) (type 8) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 + ) + (func (;32;) (type 8) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + ) + (func (;33;) (type 8) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ) + (func (;34;) (type 8) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + ) + (func (;35;) (type 8) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 0 0 0 0 0 0 0 0 16 16 16 16 16 16 16 16 + ) + (export "i8x16_extract_lane_s-first" (func 0)) + (export "i8x16_extract_lane_s-last" (func 1)) + (export "i8x16_extract_lane_u-first" (func 2)) + (export "i8x16_extract_lane_u-last" (func 3)) + (export "i16x8_extract_lane_s-first" (func 4)) + (export "i16x8_extract_lane_s-last" (func 5)) + (export "i16x8_extract_lane_u-first" (func 6)) + (export "i16x8_extract_lane_u-last" (func 7)) + (export "i32x4_extract_lane-first" (func 8)) + (export "i32x4_extract_lane-last" (func 9)) + (export "f32x4_extract_lane-first" (func 10)) + (export "f32x4_extract_lane-last" (func 11)) + (export "i8x16_replace_lane-first" (func 12)) + (export "i8x16_replace_lane-last" (func 13)) + (export "i16x8_replace_lane-first" (func 14)) + (export "i16x8_replace_lane-last" (func 15)) + (export "i32x4_replace_lane-first" (func 16)) + (export "i32x4_replace_lane-last" (func 17)) + (export "f32x4_replace_lane-first" (func 18)) + (export "f32x4_replace_lane-last" (func 19)) + (export "i64x2_extract_lane-first" (func 20)) + (export "i64x2_extract_lane-last" (func 21)) + (export "f64x2_extract_lane-first" (func 22)) + (export "f64x2_extract_lane-last" (func 23)) + (export "i64x2_replace_lane-first" (func 24)) + (export "i64x2_replace_lane-last" (func 25)) + (export "f64x2_replace_lane-first" (func 26)) + (export "f64x2_replace_lane-last" (func 27)) + (export "v8x16_swizzle" (func 28)) + (export "v8x16_shuffle-1" (func 29)) + (export "v8x16_shuffle-2" (func 30)) + (export "v8x16_shuffle-3" (func 31)) + (export "v8x16_shuffle-4" (func 32)) + (export "v8x16_shuffle-5" (func 33)) + (export "v8x16_shuffle-6" (func 34)) + (export "v8x16_shuffle-7" (func 35)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/360.print b/tests/snapshots/testsuite/simd_lane.wast/360.print new file mode 100644 index 0000000000..ce062165fa --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/360.print @@ -0,0 +1,139 @@ +(module + (type (;0;) (func (param v128 v128) (result v128))) + (type (;1;) (func (param v128 i32) (result i32))) + (type (;2;) (func (param v128 f32) (result f32))) + (type (;3;) (func (param v128 i64) (result i64))) + (type (;4;) (func (param v128 f64) (result f64))) + (type (;5;) (func (param v128 i32 v128) (result v128))) + (type (;6;) (func (param v128 i32 v128 i32) (result v128))) + (func (;0;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.extract_lane_s 0 + i8x16.replace_lane 0 + ) + (func (;1;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.extract_lane_u 0 + i8x16.replace_lane 0 + ) + (func (;2;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.extract_lane_s 0 + i16x8.replace_lane 0 + ) + (func (;3;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i16x8.extract_lane_u 0 + i16x8.replace_lane 0 + ) + (func (;4;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.extract_lane 0 + i32x4.replace_lane 0 + ) + (func (;5;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i32x4.extract_lane 0 + i32x4.replace_lane 0 + ) + (func (;6;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i64x2.extract_lane 0 + i64x2.replace_lane 0 + ) + (func (;7;) (type 0) (param v128 v128) (result v128) + local.get 0 + local.get 1 + f64x2.extract_lane 0 + f64x2.replace_lane 0 + ) + (func (;8;) (type 1) (param v128 i32) (result i32) + local.get 0 + local.get 1 + i8x16.replace_lane 15 + i8x16.extract_lane_s 15 + ) + (func (;9;) (type 1) (param v128 i32) (result i32) + local.get 0 + local.get 1 + i8x16.replace_lane 15 + i8x16.extract_lane_u 15 + ) + (func (;10;) (type 1) (param v128 i32) (result i32) + local.get 0 + local.get 1 + i16x8.replace_lane 7 + i16x8.extract_lane_s 7 + ) + (func (;11;) (type 1) (param v128 i32) (result i32) + local.get 0 + local.get 1 + i16x8.replace_lane 7 + i16x8.extract_lane_u 7 + ) + (func (;12;) (type 1) (param v128 i32) (result i32) + local.get 0 + local.get 1 + i32x4.replace_lane 3 + i32x4.extract_lane 3 + ) + (func (;13;) (type 2) (param v128 f32) (result f32) + local.get 0 + local.get 1 + f32x4.replace_lane 3 + f32x4.extract_lane 3 + ) + (func (;14;) (type 3) (param v128 i64) (result i64) + local.get 0 + local.get 1 + i64x2.replace_lane 1 + i64x2.extract_lane 1 + ) + (func (;15;) (type 4) (param v128 f64) (result f64) + local.get 0 + local.get 1 + f64x2.replace_lane 1 + f64x2.extract_lane 1 + ) + (func (;16;) (type 5) (param v128 i32 v128) (result v128) + local.get 0 + local.get 1 + i8x16.replace_lane 0 + local.get 2 + i8x16.swizzle + ) + (func (;17;) (type 6) (param v128 i32 v128 i32) (result v128) + local.get 0 + local.get 1 + i8x16.replace_lane 0 + local.get 2 + local.get 3 + i8x16.replace_lane 15 + i8x16.shuffle 16 1 18 3 20 5 22 7 24 9 26 11 28 13 30 15 + ) + (export "i8x16_extract_lane_s" (func 0)) + (export "i8x16_extract_lane_u" (func 1)) + (export "i16x8_extract_lane_s" (func 2)) + (export "i16x8_extract_lane_u" (func 3)) + (export "i32x4_extract_lane" (func 4)) + (export "f32x4_extract_lane" (func 5)) + (export "i64x2_extract_lane" (func 6)) + (export "f64x2_extract_lane" (func 7)) + (export "i8x16_replace_lane-s" (func 8)) + (export "i8x16_replace_lane-u" (func 9)) + (export "i16x8_replace_lane-s" (func 10)) + (export "i16x8_replace_lane-u" (func 11)) + (export "i32x4_replace_lane" (func 12)) + (export "f32x4_replace_lane" (func 13)) + (export "i64x2_replace_lane" (func 14)) + (export "f64x2_replace_lane" (func 15)) + (export "as-v8x16_swizzle-operand" (func 16)) + (export "as-v8x16_shuffle-operands" (func 17)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/379.print b/tests/snapshots/testsuite/simd_lane.wast/379.print new file mode 100644 index 0000000000..81b39f7954 --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/379.print @@ -0,0 +1,147 @@ +(module + (type (;0;) (func (param v128) (result v128))) + (type (;1;) (func (param v128 i32 v128 i32) (result v128))) + (type (;2;) (func (param v128 i64 v128 i64) (result v128))) + (type (;3;) (func (param v128 v128 v128 v128) (result v128))) + (type (;4;) (func (param v128 i32) (result i32))) + (type (;5;) (func (param v128 i64) (result i32))) + (type (;6;) (func (param v128 v128) (result i32))) + (func (;0;) (type 0) (param v128) (result v128) + local.get 0 + i8x16.extract_lane_s 0 + i8x16.splat + ) + (func (;1;) (type 0) (param v128) (result v128) + local.get 0 + i16x8.extract_lane_u 0 + i16x8.splat + ) + (func (;2;) (type 0) (param v128) (result v128) + local.get 0 + i32x4.extract_lane 0 + i32x4.splat + ) + (func (;3;) (type 0) (param v128) (result v128) + local.get 0 + f32x4.extract_lane 0 + f32x4.splat + ) + (func (;4;) (type 0) (param v128) (result v128) + local.get 0 + i64x2.extract_lane 0 + i64x2.splat + ) + (func (;5;) (type 0) (param v128) (result v128) + local.get 0 + f64x2.extract_lane 0 + f64x2.splat + ) + (func (;6;) (type 1) (param v128 i32 v128 i32) (result v128) + local.get 0 + local.get 1 + i8x16.replace_lane 0 + local.get 2 + local.get 3 + i8x16.replace_lane 15 + i8x16.add + ) + (func (;7;) (type 1) (param v128 i32 v128 i32) (result v128) + local.get 0 + local.get 1 + i16x8.replace_lane 0 + local.get 2 + local.get 3 + i16x8.replace_lane 7 + i16x8.add + ) + (func (;8;) (type 1) (param v128 i32 v128 i32) (result v128) + local.get 0 + local.get 1 + i32x4.replace_lane 0 + local.get 2 + local.get 3 + i32x4.replace_lane 3 + i32x4.add + ) + (func (;9;) (type 2) (param v128 i64 v128 i64) (result v128) + local.get 0 + local.get 1 + i64x2.replace_lane 0 + local.get 2 + local.get 3 + i64x2.replace_lane 1 + i64x2.add + ) + (func (;10;) (type 3) (param v128 v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.swizzle + local.get 2 + local.get 3 + i8x16.swizzle + i8x16.add + ) + (func (;11;) (type 3) (param v128 v128 v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + local.get 2 + local.get 3 + i8x16.shuffle 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + i8x16.sub + ) + (func (;12;) (type 4) (param v128 i32) (result i32) + local.get 0 + local.get 1 + i8x16.replace_lane 0 + v128.any_true + ) + (func (;13;) (type 4) (param v128 i32) (result i32) + local.get 0 + local.get 1 + i16x8.replace_lane 0 + v128.any_true + ) + (func (;14;) (type 4) (param v128 i32) (result i32) + local.get 0 + local.get 1 + i32x4.replace_lane 0 + v128.any_true + ) + (func (;15;) (type 5) (param v128 i64) (result i32) + local.get 0 + local.get 1 + i64x2.replace_lane 0 + v128.any_true + ) + (func (;16;) (type 6) (param v128 v128) (result i32) + local.get 0 + local.get 1 + i8x16.swizzle + i8x16.all_true + ) + (func (;17;) (type 6) (param v128 v128) (result i32) + local.get 0 + local.get 1 + i8x16.shuffle 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + v128.any_true + ) + (export "as-i8x16_splat-operand" (func 0)) + (export "as-i16x8_splat-operand" (func 1)) + (export "as-i32x4_splat-operand" (func 2)) + (export "as-f32x4_splat-operand" (func 3)) + (export "as-i64x2_splat-operand" (func 4)) + (export "as-f64x2_splat-operand" (func 5)) + (export "as-i8x16_add-operands" (func 6)) + (export "as-i16x8_add-operands" (func 7)) + (export "as-i32x4_add-operands" (func 8)) + (export "as-i64x2_add-operands" (func 9)) + (export "swizzle-as-i8x16_add-operands" (func 10)) + (export "shuffle-as-i8x16_sub-operands" (func 11)) + (export "as-i8x16_any_true-operand" (func 12)) + (export "as-i16x8_any_true-operand" (func 13)) + (export "as-i32x4_any_true-operand1" (func 14)) + (export "as-i32x4_any_true-operand2" (func 15)) + (export "swizzle-as-i8x16_all_true-operands" (func 16)) + (export "shuffle-as-i8x16_any_true-operands" (func 17)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/399.print b/tests/snapshots/testsuite/simd_lane.wast/399.print new file mode 100644 index 0000000000..5137cce386 --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/399.print @@ -0,0 +1,67 @@ +(module + (type (;0;) (func (param v128 i32) (result v128))) + (type (;1;) (func (param v128 f32) (result v128))) + (type (;2;) (func (param v128 i64) (result v128))) + (type (;3;) (func (param v128 f64) (result v128))) + (func (;0;) (type 0) (param v128 i32) (result v128) + i32.const 0 + local.get 0 + local.get 1 + i8x16.replace_lane 0 + v128.store + i32.const 0 + v128.load + ) + (func (;1;) (type 0) (param v128 i32) (result v128) + i32.const 0 + local.get 0 + local.get 1 + i16x8.replace_lane 0 + v128.store + i32.const 0 + v128.load + ) + (func (;2;) (type 0) (param v128 i32) (result v128) + i32.const 0 + local.get 0 + local.get 1 + i32x4.replace_lane 0 + v128.store + i32.const 0 + v128.load + ) + (func (;3;) (type 1) (param v128 f32) (result v128) + i32.const 0 + local.get 0 + local.get 1 + f32x4.replace_lane 0 + v128.store + i32.const 0 + v128.load + ) + (func (;4;) (type 2) (param v128 i64) (result v128) + i32.const 0 + local.get 0 + local.get 1 + i64x2.replace_lane 0 + v128.store + i32.const 0 + v128.load + ) + (func (;5;) (type 3) (param v128 f64) (result v128) + i32.const 0 + local.get 0 + local.get 1 + f64x2.replace_lane 0 + v128.store + i32.const 0 + v128.load + ) + (memory (;0;) 1) + (export "as-v128_store-operand-1" (func 0)) + (export "as-v128_store-operand-2" (func 1)) + (export "as-v128_store-operand-3" (func 2)) + (export "as-v128_store-operand-4" (func 3)) + (export "as-v128_store-operand-5" (func 4)) + (export "as-v128_store-operand-6" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/406.print b/tests/snapshots/testsuite/simd_lane.wast/406.print new file mode 100644 index 0000000000..7e0de1c7fa --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/406.print @@ -0,0 +1,79 @@ +(module + (type (;0;) (func (param v128) (result i32))) + (type (;1;) (func (param v128 i32) (result v128))) + (type (;2;) (func (param v128 f32) (result v128))) + (type (;3;) (func (param v128 v128) (result v128))) + (type (;4;) (func (param v128) (result i64))) + (type (;5;) (func (param v128 f64) (result v128))) + (func (;0;) (type 0) (param v128) (result i32) + local.get 0 + i8x16.extract_lane_s 0 + if (result i32) ;; label = @1 + i32.const 255 + else + i32.const 0 + end + ) + (func (;1;) (type 1) (param v128 i32) (result v128) + local.get 0 + local.get 1 + i16x8.replace_lane 0 + return + ) + (func (;2;) (type 0) (param v128) (result i32) + (local i32) + local.get 0 + i32x4.extract_lane 0 + local.set 1 + local.get 1 + return + ) + (func (;3;) (type 2) (param v128 f32) (result v128) + local.get 0 + local.get 1 + f32x4.replace_lane 0 + global.set $g + global.get $g + return + ) + (func (;4;) (type 3) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.swizzle + return + ) + (func (;5;) (type 3) (param v128 v128) (result v128) + local.get 0 + local.get 1 + i8x16.shuffle 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31 + global.set $h + global.get $h + return + ) + (func (;6;) (type 4) (param v128) (result i64) + (local i64) + local.get 0 + i64x2.extract_lane 0 + local.set 1 + local.get 1 + return + ) + (func (;7;) (type 5) (param v128 f64) (result v128) + local.get 0 + local.get 1 + f64x2.replace_lane 0 + global.set $g + global.get $g + return + ) + (global $g (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (global $h (;1;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (export "as-if-condition-value" (func 0)) + (export "as-return-value-1" (func 1)) + (export "as-local_set-value" (func 2)) + (export "as-global_set-value-1" (func 3)) + (export "as-return-value-2" (func 4)) + (export "as-global_set-value-2" (func 5)) + (export "as-local_set-value-1" (func 6)) + (export "as-global_set-value-3" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/422.print b/tests/snapshots/testsuite/simd_lane.wast/422.print new file mode 100644 index 0000000000..226e8046dd --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/422.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i8x16.extract_lane_s 15 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/423.print b/tests/snapshots/testsuite/simd_lane.wast/423.print new file mode 100644 index 0000000000..8922464b3d --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/423.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.extract_lane_s 7 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/424.print b/tests/snapshots/testsuite/simd_lane.wast/424.print new file mode 100644 index 0000000000..c99ad5f293 --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/424.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i16x8.extract_lane_u 7 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/425.print b/tests/snapshots/testsuite/simd_lane.wast/425.print new file mode 100644 index 0000000000..bcd2c8ce81 --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/425.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i32x4.extract_lane 3 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/426.print b/tests/snapshots/testsuite/simd_lane.wast/426.print new file mode 100644 index 0000000000..9075937a5c --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/426.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func (result f64))) + (func (;0;) (type 0) (result f64) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + f64x2.extract_lane 1 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/427.print b/tests/snapshots/testsuite/simd_lane.wast/427.print new file mode 100644 index 0000000000..39aba05059 --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/427.print @@ -0,0 +1,8 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + f32.const 0x1p+0 (;=1;) + f32x4.replace_lane 3 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_lane.wast/428.print b/tests/snapshots/testsuite/simd_lane.wast/428.print new file mode 100644 index 0000000000..590621ca76 --- /dev/null +++ b/tests/snapshots/testsuite/simd_lane.wast/428.print @@ -0,0 +1,8 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + i64.const 1 + i64x2.replace_lane 1 + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_linking.wast/0.print b/tests/snapshots/testsuite/simd_linking.wast/0.print new file mode 100644 index 0000000000..d65cfbb30e --- /dev/null +++ b/tests/snapshots/testsuite/simd_linking.wast/0.print @@ -0,0 +1,6 @@ +(module + (global (;0;) v128 v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (global (;1;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (export "g-v128" (global 0)) + (export "mg-v128" (global 1)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_linking.wast/2.print b/tests/snapshots/testsuite/simd_linking.wast/2.print new file mode 100644 index 0000000000..9b322829ed --- /dev/null +++ b/tests/snapshots/testsuite/simd_linking.wast/2.print @@ -0,0 +1,3 @@ +(module + (import "Mv128" "mg-v128" (global (;0;) (mut v128))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/0.print b/tests/snapshots/testsuite/simd_load.wast/0.print new file mode 100644 index 0000000000..d8fb0a62a4 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/0.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + ) + (memory (;0;) 1) + (export "v128.load" (func 0)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/11.print b/tests/snapshots/testsuite/simd_load.wast/11.print new file mode 100644 index 0000000000..54a6eb8933 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/11.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + i32.const 16 + v128.load + i32.const 32 + v128.load + v128.bitselect + ) + (memory (;0;) 1) + (export "as-v128.bitselect-operand" (func 0)) + (data (;0;) (i32.const 0) "\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa") + (data (;1;) (i32.const 16) "\bb\bb\bb\bb\bb\bb\bb\bb\bb\bb\bb\bb\bb\bb\bb\bb") + (data (;2;) (i32.const 32) "\f0\f0\f0\f0\ff\ff\ff\ff\00\00\00\00\ff\00\ff\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/13.print b/tests/snapshots/testsuite/simd_load.wast/13.print new file mode 100644 index 0000000000..b187085c26 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/13.print @@ -0,0 +1,12 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + i32.const 1 + i8x16.shl + ) + (memory (;0;) 1) + (export "as-i8x16.shl-operand" (func 0)) + (data (;0;) (i32.const 0) "\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/15.print b/tests/snapshots/testsuite/simd_load.wast/15.print new file mode 100644 index 0000000000..3353baacbd --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/15.print @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + i32.const 16 + v128.load + i8x16.add + i32.const 16 + v128.load + i8x16.sub + ) + (memory (;0;) 1) + (export "as-add/sub-operand" (func 0)) + (data (;0;) (i32.const 0) "\02\00\00\00\02\00\00\00\02\00\00\00\02\00\00\00") + (data (;1;) (i32.const 16) "\03\00\00\00\03\00\00\00\03\00\00\00\03\00\00\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/17.print b/tests/snapshots/testsuite/simd_load.wast/17.print new file mode 100644 index 0000000000..d923b86053 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/17.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + i32.const 16 + v128.load + f32x4.mul + ) + (memory (;0;) 1) + (export "as-f32x4.mul-operand" (func 0)) + (data (;0;) (i32.const 0) "\00\00\00C\00\00\80?ff\e6?\00\00\80\bf") + (data (;1;) (i32.const 16) "\00\00\00@\00\00\00@\00\00\00@\00\00\00@") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/19.print b/tests/snapshots/testsuite/simd_load.wast/19.print new file mode 100644 index 0000000000..dc7ef26ca0 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/19.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + f32x4.abs + ) + (memory (;0;) 1) + (export "as-f32x4.abs-operand" (func 0)) + (data (;0;) (i32.const 0) "\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/21.print b/tests/snapshots/testsuite/simd_load.wast/21.print new file mode 100644 index 0000000000..8c2bb998eb --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/21.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + i32.const 1 + v128.load offset=16 + f32x4.min + ) + (memory (;0;) 1) + (export "as-f32x4.min-operand" (func 0)) + (data (;0;) (i32.const 0) "\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa\aa") + (data (;1;) (i32.const 16) "\02\00\00\00\02\00\00\00\02\00\00\00\02\00\00\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/23.print b/tests/snapshots/testsuite/simd_load.wast/23.print new file mode 100644 index 0000000000..e8809da158 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/23.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + i32x4.trunc_sat_f32x4_s + ) + (memory (;0;) 1) + (export "as-i32x4.trunc_sat_f32x4_s-operand" (func 0)) + (data (;0;) (i32.const 0) "\00\00\00C\00\00\80?ff\e6?\00\00\80\bf") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/25.print b/tests/snapshots/testsuite/simd_load.wast/25.print new file mode 100644 index 0000000000..03db328c1b --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/25.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + f32x4.convert_i32x4_u + ) + (memory (;0;) 1) + (export "as-f32x4.convert_i32x4_u-operand" (func 0)) + (data (;0;) (i32.const 0) "\02\00\00\00\02\00\00\00\02\00\00\00\02\00\00\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/27.print b/tests/snapshots/testsuite/simd_load.wast/27.print new file mode 100644 index 0000000000..191c031e01 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/27.print @@ -0,0 +1,14 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + i32.const 1 + v128.load offset=15 + i8x16.swizzle + ) + (memory (;0;) 1) + (export "as-i8x16.swizzle-operand" (func 0)) + (data (;0;) (i32.const 0) "defghijklmnopqrs") + (data (;1;) (i32.const 16) "\0f\0e\0d\0c\0b\0a\09\08\07\06\05\04\03\02\01\00") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/29.print b/tests/snapshots/testsuite/simd_load.wast/29.print new file mode 100644 index 0000000000..0682943e2d --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/29.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 0 + v128.load + br 0 (;@1;) + end + ) + (memory (;0;) 1) + (export "as-br-value" (func 0)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/4.print b/tests/snapshots/testsuite/simd_load.wast/4.print new file mode 100644 index 0000000000..d0697a4f42 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/4.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 0 + v128.load + i8x16.extract_lane_s 0 + ) + (memory (;0;) 1) + (export "as-i8x16_extract_lane_s-value/0" (func 0)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/6.print b/tests/snapshots/testsuite/simd_load.wast/6.print new file mode 100644 index 0000000000..9c222121ff --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/6.print @@ -0,0 +1,13 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + i32.const 0 + v128.load offset=16 + i8x16.eq + ) + (memory (;0;) 1) + (export "as-i8x16.eq-operand" (func 0)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load.wast/8.print b/tests/snapshots/testsuite/simd_load.wast/8.print new file mode 100644 index 0000000000..1ed0acfc46 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load.wast/8.print @@ -0,0 +1,18 @@ +(module + (type (;0;) (func (result v128))) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.load + v128.not + ) + (func (;1;) (type 1) (result i32) + i32.const 0 + v128.load + i8x16.all_true + ) + (memory (;0;) 1) + (export "as-v128.not-operand" (func 0)) + (export "as-i8x16.all_true-operand" (func 1)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load16_lane.wast/0.print b/tests/snapshots/testsuite/simd_load16_lane.wast/0.print new file mode 100644 index 0000000000..5df85fe7c1 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load16_lane.wast/0.print @@ -0,0 +1,198 @@ +(module + (type (;0;) (func (param i32 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 0 + ) + (func (;1;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 1 + ) + (func (;2;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 2 + ) + (func (;3;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 3 + ) + (func (;4;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 4 + ) + (func (;5;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 5 + ) + (func (;6;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 6 + ) + (func (;7;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 7 + ) + (func (;8;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load16_lane 0 + ) + (func (;9;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load16_lane offset=1 1 + ) + (func (;10;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load16_lane offset=2 2 + ) + (func (;11;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load16_lane offset=3 3 + ) + (func (;12;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load16_lane offset=4 4 + ) + (func (;13;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load16_lane offset=5 5 + ) + (func (;14;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load16_lane offset=6 6 + ) + (func (;15;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load16_lane offset=7 7 + ) + (func (;16;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane align=1 0 + ) + (func (;17;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 0 + ) + (func (;18;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane align=1 1 + ) + (func (;19;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 1 + ) + (func (;20;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane align=1 2 + ) + (func (;21;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 2 + ) + (func (;22;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane align=1 3 + ) + (func (;23;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 3 + ) + (func (;24;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane align=1 4 + ) + (func (;25;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 4 + ) + (func (;26;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane align=1 5 + ) + (func (;27;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 5 + ) + (func (;28;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane align=1 6 + ) + (func (;29;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 6 + ) + (func (;30;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane align=1 7 + ) + (func (;31;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load16_lane 7 + ) + (memory (;0;) 1) + (export "v128.load16_lane_0" (func 0)) + (export "v128.load16_lane_1" (func 1)) + (export "v128.load16_lane_2" (func 2)) + (export "v128.load16_lane_3" (func 3)) + (export "v128.load16_lane_4" (func 4)) + (export "v128.load16_lane_5" (func 5)) + (export "v128.load16_lane_6" (func 6)) + (export "v128.load16_lane_7" (func 7)) + (export "v128.load16_lane_0_offset_0" (func 8)) + (export "v128.load16_lane_1_offset_1" (func 9)) + (export "v128.load16_lane_2_offset_2" (func 10)) + (export "v128.load16_lane_3_offset_3" (func 11)) + (export "v128.load16_lane_4_offset_4" (func 12)) + (export "v128.load16_lane_5_offset_5" (func 13)) + (export "v128.load16_lane_6_offset_6" (func 14)) + (export "v128.load16_lane_7_offset_7" (func 15)) + (export "v128.load16_lane_0_align_1" (func 16)) + (export "v128.load16_lane_0_align_2" (func 17)) + (export "v128.load16_lane_1_align_1" (func 18)) + (export "v128.load16_lane_1_align_2" (func 19)) + (export "v128.load16_lane_2_align_1" (func 20)) + (export "v128.load16_lane_2_align_2" (func 21)) + (export "v128.load16_lane_3_align_1" (func 22)) + (export "v128.load16_lane_3_align_2" (func 23)) + (export "v128.load16_lane_4_align_1" (func 24)) + (export "v128.load16_lane_4_align_2" (func 25)) + (export "v128.load16_lane_5_align_1" (func 26)) + (export "v128.load16_lane_5_align_2" (func 27)) + (export "v128.load16_lane_6_align_1" (func 28)) + (export "v128.load16_lane_6_align_2" (func 29)) + (export "v128.load16_lane_7_align_1" (func 30)) + (export "v128.load16_lane_7_align_2" (func 31)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load32_lane.wast/0.print b/tests/snapshots/testsuite/simd_load32_lane.wast/0.print new file mode 100644 index 0000000000..a79d227623 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load32_lane.wast/0.print @@ -0,0 +1,126 @@ +(module + (type (;0;) (func (param i32 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane 0 + ) + (func (;1;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane 1 + ) + (func (;2;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane 2 + ) + (func (;3;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane 3 + ) + (func (;4;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load32_lane 0 + ) + (func (;5;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load32_lane offset=1 1 + ) + (func (;6;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load32_lane offset=2 2 + ) + (func (;7;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load32_lane offset=3 3 + ) + (func (;8;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane align=1 0 + ) + (func (;9;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane align=2 0 + ) + (func (;10;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane 0 + ) + (func (;11;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane align=1 1 + ) + (func (;12;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane align=2 1 + ) + (func (;13;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane 1 + ) + (func (;14;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane align=1 2 + ) + (func (;15;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane align=2 2 + ) + (func (;16;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane 2 + ) + (func (;17;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane align=1 3 + ) + (func (;18;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane align=2 3 + ) + (func (;19;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load32_lane 3 + ) + (memory (;0;) 1) + (export "v128.load32_lane_0" (func 0)) + (export "v128.load32_lane_1" (func 1)) + (export "v128.load32_lane_2" (func 2)) + (export "v128.load32_lane_3" (func 3)) + (export "v128.load32_lane_0_offset_0" (func 4)) + (export "v128.load32_lane_1_offset_1" (func 5)) + (export "v128.load32_lane_2_offset_2" (func 6)) + (export "v128.load32_lane_3_offset_3" (func 7)) + (export "v128.load32_lane_0_align_1" (func 8)) + (export "v128.load32_lane_0_align_2" (func 9)) + (export "v128.load32_lane_0_align_4" (func 10)) + (export "v128.load32_lane_1_align_1" (func 11)) + (export "v128.load32_lane_1_align_2" (func 12)) + (export "v128.load32_lane_1_align_4" (func 13)) + (export "v128.load32_lane_2_align_1" (func 14)) + (export "v128.load32_lane_2_align_2" (func 15)) + (export "v128.load32_lane_2_align_4" (func 16)) + (export "v128.load32_lane_3_align_1" (func 17)) + (export "v128.load32_lane_3_align_2" (func 18)) + (export "v128.load32_lane_3_align_4" (func 19)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load64_lane.wast/0.print b/tests/snapshots/testsuite/simd_load64_lane.wast/0.print new file mode 100644 index 0000000000..9afddb8e7e --- /dev/null +++ b/tests/snapshots/testsuite/simd_load64_lane.wast/0.print @@ -0,0 +1,78 @@ +(module + (type (;0;) (func (param i32 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane 0 + ) + (func (;1;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane 1 + ) + (func (;2;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load64_lane 0 + ) + (func (;3;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load64_lane offset=1 1 + ) + (func (;4;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane align=1 0 + ) + (func (;5;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane align=2 0 + ) + (func (;6;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane align=4 0 + ) + (func (;7;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane 0 + ) + (func (;8;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane align=1 1 + ) + (func (;9;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane align=2 1 + ) + (func (;10;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane align=4 1 + ) + (func (;11;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load64_lane 1 + ) + (memory (;0;) 1) + (export "v128.load64_lane_0" (func 0)) + (export "v128.load64_lane_1" (func 1)) + (export "v128.load64_lane_0_offset_0" (func 2)) + (export "v128.load64_lane_1_offset_1" (func 3)) + (export "v128.load64_lane_0_align_1" (func 4)) + (export "v128.load64_lane_0_align_2" (func 5)) + (export "v128.load64_lane_0_align_4" (func 6)) + (export "v128.load64_lane_0_align_8" (func 7)) + (export "v128.load64_lane_1_align_1" (func 8)) + (export "v128.load64_lane_1_align_2" (func 9)) + (export "v128.load64_lane_1_align_4" (func 10)) + (export "v128.load64_lane_1_align_8" (func 11)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load8_lane.wast/0.print b/tests/snapshots/testsuite/simd_load8_lane.wast/0.print new file mode 100644 index 0000000000..8e52230715 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load8_lane.wast/0.print @@ -0,0 +1,294 @@ +(module + (type (;0;) (func (param i32 v128) (result v128))) + (type (;1;) (func (param v128) (result v128))) + (func (;0;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 0 + ) + (func (;1;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 1 + ) + (func (;2;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 2 + ) + (func (;3;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 3 + ) + (func (;4;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 4 + ) + (func (;5;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 5 + ) + (func (;6;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 6 + ) + (func (;7;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 7 + ) + (func (;8;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 8 + ) + (func (;9;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 9 + ) + (func (;10;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 10 + ) + (func (;11;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 11 + ) + (func (;12;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 12 + ) + (func (;13;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 13 + ) + (func (;14;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 14 + ) + (func (;15;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 15 + ) + (func (;16;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane 0 + ) + (func (;17;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=1 1 + ) + (func (;18;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=2 2 + ) + (func (;19;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=3 3 + ) + (func (;20;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=4 4 + ) + (func (;21;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=5 5 + ) + (func (;22;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=6 6 + ) + (func (;23;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=7 7 + ) + (func (;24;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=8 8 + ) + (func (;25;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=9 9 + ) + (func (;26;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=10 10 + ) + (func (;27;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=11 11 + ) + (func (;28;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=12 12 + ) + (func (;29;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=13 13 + ) + (func (;30;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=14 14 + ) + (func (;31;) (type 1) (param $x v128) (result v128) + i32.const 0 + local.get $x + v128.load8_lane offset=15 15 + ) + (func (;32;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 0 + ) + (func (;33;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 1 + ) + (func (;34;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 2 + ) + (func (;35;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 3 + ) + (func (;36;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 4 + ) + (func (;37;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 5 + ) + (func (;38;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 6 + ) + (func (;39;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 7 + ) + (func (;40;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 8 + ) + (func (;41;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 9 + ) + (func (;42;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 10 + ) + (func (;43;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 11 + ) + (func (;44;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 12 + ) + (func (;45;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 13 + ) + (func (;46;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 14 + ) + (func (;47;) (type 0) (param $address i32) (param $x v128) (result v128) + local.get $address + local.get $x + v128.load8_lane 15 + ) + (memory (;0;) 1) + (export "v128.load8_lane_0" (func 0)) + (export "v128.load8_lane_1" (func 1)) + (export "v128.load8_lane_2" (func 2)) + (export "v128.load8_lane_3" (func 3)) + (export "v128.load8_lane_4" (func 4)) + (export "v128.load8_lane_5" (func 5)) + (export "v128.load8_lane_6" (func 6)) + (export "v128.load8_lane_7" (func 7)) + (export "v128.load8_lane_8" (func 8)) + (export "v128.load8_lane_9" (func 9)) + (export "v128.load8_lane_10" (func 10)) + (export "v128.load8_lane_11" (func 11)) + (export "v128.load8_lane_12" (func 12)) + (export "v128.load8_lane_13" (func 13)) + (export "v128.load8_lane_14" (func 14)) + (export "v128.load8_lane_15" (func 15)) + (export "v128.load8_lane_0_offset_0" (func 16)) + (export "v128.load8_lane_1_offset_1" (func 17)) + (export "v128.load8_lane_2_offset_2" (func 18)) + (export "v128.load8_lane_3_offset_3" (func 19)) + (export "v128.load8_lane_4_offset_4" (func 20)) + (export "v128.load8_lane_5_offset_5" (func 21)) + (export "v128.load8_lane_6_offset_6" (func 22)) + (export "v128.load8_lane_7_offset_7" (func 23)) + (export "v128.load8_lane_8_offset_8" (func 24)) + (export "v128.load8_lane_9_offset_9" (func 25)) + (export "v128.load8_lane_10_offset_10" (func 26)) + (export "v128.load8_lane_11_offset_11" (func 27)) + (export "v128.load8_lane_12_offset_12" (func 28)) + (export "v128.load8_lane_13_offset_13" (func 29)) + (export "v128.load8_lane_14_offset_14" (func 30)) + (export "v128.load8_lane_15_offset_15" (func 31)) + (export "v128.load8_lane_0_align_1" (func 32)) + (export "v128.load8_lane_1_align_1" (func 33)) + (export "v128.load8_lane_2_align_1" (func 34)) + (export "v128.load8_lane_3_align_1" (func 35)) + (export "v128.load8_lane_4_align_1" (func 36)) + (export "v128.load8_lane_5_align_1" (func 37)) + (export "v128.load8_lane_6_align_1" (func 38)) + (export "v128.load8_lane_7_align_1" (func 39)) + (export "v128.load8_lane_8_align_1" (func 40)) + (export "v128.load8_lane_9_align_1" (func 41)) + (export "v128.load8_lane_10_align_1" (func 42)) + (export "v128.load8_lane_11_align_1" (func 43)) + (export "v128.load8_lane_12_align_1" (func 44)) + (export "v128.load8_lane_13_align_1" (func 45)) + (export "v128.load8_lane_14_align_1" (func 46)) + (export "v128.load8_lane_15_align_1" (func 47)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load_extend.wast/0.print b/tests/snapshots/testsuite/simd_load_extend.wast/0.print new file mode 100644 index 0000000000..4764db8dd5 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load_extend.wast/0.print @@ -0,0 +1,247 @@ +(module + (type (;0;) (func (param i32) (result v128))) + (type (;1;) (func (result v128))) + (func (;0;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_s + ) + (func (;1;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_u + ) + (func (;2;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_s + ) + (func (;3;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_u + ) + (func (;4;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_s + ) + (func (;5;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_u + ) + (func (;6;) (type 1) (result v128) + i32.const 0 + v128.load8x8_s + ) + (func (;7;) (type 1) (result v128) + i32.const 8 + v128.load8x8_u + ) + (func (;8;) (type 1) (result v128) + i32.const 10 + v128.load16x4_s + ) + (func (;9;) (type 1) (result v128) + i32.const 20 + v128.load16x4_u + ) + (func (;10;) (type 1) (result v128) + i32.const 65520 + v128.load32x2_s + ) + (func (;11;) (type 1) (result v128) + i32.const 65526 + v128.load32x2_u + ) + (func (;12;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_s + ) + (func (;13;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_s align=1 + ) + (func (;14;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_s align=1 + ) + (func (;15;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_s offset=1 align=1 + ) + (func (;16;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_s offset=10 align=4 + ) + (func (;17;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_s offset=20 + ) + (func (;18;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_u + ) + (func (;19;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_u align=1 + ) + (func (;20;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_u align=1 + ) + (func (;21;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_u offset=1 align=1 + ) + (func (;22;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_u offset=10 align=4 + ) + (func (;23;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load8x8_u offset=20 + ) + (func (;24;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_s + ) + (func (;25;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_s align=1 + ) + (func (;26;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_s align=1 + ) + (func (;27;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_s offset=1 align=1 + ) + (func (;28;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_s offset=10 align=4 + ) + (func (;29;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_s offset=20 + ) + (func (;30;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_u + ) + (func (;31;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_u align=1 + ) + (func (;32;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_u align=1 + ) + (func (;33;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_u offset=1 align=1 + ) + (func (;34;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_u offset=10 align=4 + ) + (func (;35;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load16x4_u offset=20 + ) + (func (;36;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_s + ) + (func (;37;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_s align=1 + ) + (func (;38;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_s align=1 + ) + (func (;39;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_s offset=1 align=1 + ) + (func (;40;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_s offset=10 align=4 + ) + (func (;41;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_s offset=20 + ) + (func (;42;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_u + ) + (func (;43;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_u align=1 + ) + (func (;44;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_u align=1 + ) + (func (;45;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_u offset=1 align=1 + ) + (func (;46;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_u offset=10 align=4 + ) + (func (;47;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32x2_u offset=20 + ) + (memory (;0;) 1) + (export "v128.load8x8_s" (func 0)) + (export "v128.load8x8_u" (func 1)) + (export "v128.load16x4_s" (func 2)) + (export "v128.load16x4_u" (func 3)) + (export "v128.load32x2_s" (func 4)) + (export "v128.load32x2_u" (func 5)) + (export "v128.load8x8_s_const0" (func 6)) + (export "v128.load8x8_u_const8" (func 7)) + (export "v128.load16x4_s_const10" (func 8)) + (export "v128.load16x4_u_const20" (func 9)) + (export "v128.load32x2_s_const65520" (func 10)) + (export "v128.load32x2_u_const65526" (func 11)) + (export "v128.load8x8_s_offset0" (func 12)) + (export "v128.load8x8_s_align1" (func 13)) + (export "v128.load8x8_s_offset0_align1" (func 14)) + (export "v128.load8x8_s_offset1_align1" (func 15)) + (export "v128.load8x8_s_offset10_align4" (func 16)) + (export "v128.load8x8_s_offset20_align8" (func 17)) + (export "v128.load8x8_u_offset0" (func 18)) + (export "v128.load8x8_u_align1" (func 19)) + (export "v128.load8x8_u_offset0_align1" (func 20)) + (export "v128.load8x8_u_offset1_align1" (func 21)) + (export "v128.load8x8_u_offset10_align4" (func 22)) + (export "v128.load8x8_u_offset20_align8" (func 23)) + (export "v128.load16x4_s_offset0" (func 24)) + (export "v128.load16x4_s_align1" (func 25)) + (export "v128.load16x4_s_offset0_align1" (func 26)) + (export "v128.load16x4_s_offset1_align1" (func 27)) + (export "v128.load16x4_s_offset10_align4" (func 28)) + (export "v128.load16x4_s_offset20_align8" (func 29)) + (export "v128.load16x4_u_offset0" (func 30)) + (export "v128.load16x4_u_align1" (func 31)) + (export "v128.load16x4_u_offset0_align1" (func 32)) + (export "v128.load16x4_u_offset1_align1" (func 33)) + (export "v128.load16x4_u_offset10_align4" (func 34)) + (export "v128.load16x4_u_offset20_align8" (func 35)) + (export "v128.load32x2_s_offset0" (func 36)) + (export "v128.load32x2_s_align1" (func 37)) + (export "v128.load32x2_s_offset0_align1" (func 38)) + (export "v128.load32x2_s_offset1_align1" (func 39)) + (export "v128.load32x2_s_offset10_align4" (func 40)) + (export "v128.load32x2_s_offset20_align8" (func 41)) + (export "v128.load32x2_u_offset0" (func 42)) + (export "v128.load32x2_u_align1" (func 43)) + (export "v128.load32x2_u_offset0_align1" (func 44)) + (export "v128.load32x2_u_offset1_align1" (func 45)) + (export "v128.load32x2_u_offset10_align4" (func 46)) + (export "v128.load32x2_u_offset20_align8" (func 47)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\80\81\82\83\84\85\86\87\88\89") + (data (;1;) (i32.const 65520) "\0a\0b\0c\0d\0e\0f\80\81\82\83\84\85\86\87\88\89") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load_extend.wast/85.print b/tests/snapshots/testsuite/simd_load_extend.wast/85.print new file mode 100644 index 0000000000..621b1b0cba --- /dev/null +++ b/tests/snapshots/testsuite/simd_load_extend.wast/85.print @@ -0,0 +1,144 @@ +(module + (type (;0;) (func (result v128))) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 0 + v128.load8x8_s + end + end + ) + (func (;1;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 1 + v128.load8x8_u + end + end + ) + (func (;2;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 2 + v128.load16x4_s + end + end + ) + (func (;3;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 3 + v128.load16x4_u + end + end + ) + (func (;4;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 4 + v128.load32x2_s + end + end + ) + (func (;5;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 5 + v128.load32x2_u + end + end + ) + (func (;6;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 6 + v128.load8x8_s + br 0 (;@1;) + end + ) + (func (;7;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 7 + v128.load8x8_u + br 0 (;@1;) + end + ) + (func (;8;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 8 + v128.load16x4_s + br 0 (;@1;) + end + ) + (func (;9;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 9 + v128.load16x4_u + br 0 (;@1;) + end + ) + (func (;10;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 10 + v128.load32x2_s + br 0 (;@1;) + end + ) + (func (;11;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 11 + v128.load32x2_u + br 0 (;@1;) + end + ) + (func (;12;) (type 1) (result i32) + i32.const 12 + v128.load8x8_s + i8x16.extract_lane_s 0 + ) + (func (;13;) (type 1) (result i32) + i32.const 13 + v128.load8x8_u + i8x16.extract_lane_s 0 + ) + (func (;14;) (type 1) (result i32) + i32.const 14 + v128.load16x4_s + i8x16.extract_lane_s 0 + ) + (func (;15;) (type 1) (result i32) + i32.const 15 + v128.load16x4_u + i8x16.extract_lane_s 0 + ) + (func (;16;) (type 1) (result i32) + i32.const 16 + v128.load32x2_s + i8x16.extract_lane_s 0 + ) + (func (;17;) (type 1) (result i32) + i32.const 17 + v128.load32x2_u + i8x16.extract_lane_s 0 + ) + (memory (;0;) 1) + (export "v128.load8x8_s-in-block" (func 0)) + (export "v128.load8x8_u-in-block" (func 1)) + (export "v128.load16x4_s-in-block" (func 2)) + (export "v128.load16x4_u-in-block" (func 3)) + (export "v128.load32x2_s-in-block" (func 4)) + (export "v128.load32x2_u-in-block" (func 5)) + (export "v128.load8x8_s-as-br-value" (func 6)) + (export "v128.load8x8_u-as-br-value" (func 7)) + (export "v128.load16x4_s-as-br-value" (func 8)) + (export "v128.load16x4_u-as-br-value" (func 9)) + (export "v128.load32x2_s-as-br-value" (func 10)) + (export "v128.load32x2_u-as-br-value" (func 11)) + (export "v128.load8x8_s-extract_lane_s-operand" (func 12)) + (export "v128.load8x8_u-extract_lane_s-operand" (func 13)) + (export "v128.load16x4_s-extract_lane_s-operand" (func 14)) + (export "v128.load16x4_u-extract_lane_s-operand" (func 15)) + (export "v128.load32x2_s-extract_lane_s-operand" (func 16)) + (export "v128.load32x2_u-extract_lane_s-operand" (func 17)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\80\81\82\83\84\85\86\87\88\89") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load_splat.wast/0.print b/tests/snapshots/testsuite/simd_load_splat.wast/0.print new file mode 100644 index 0000000000..ae15e9e63a --- /dev/null +++ b/tests/snapshots/testsuite/simd_load_splat.wast/0.print @@ -0,0 +1,146 @@ +(module + (type (;0;) (func (param i32) (result v128))) + (func (;0;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load8_splat + ) + (func (;1;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load16_splat + ) + (func (;2;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load32_splat + ) + (func (;3;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load64_splat + ) + (func (;4;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load8_splat + ) + (func (;5;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load8_splat + ) + (func (;6;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load8_splat offset=1 + ) + (func (;7;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load8_splat offset=2 + ) + (func (;8;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load8_splat offset=15 + ) + (func (;9;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load16_splat + ) + (func (;10;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load16_splat align=1 + ) + (func (;11;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load16_splat offset=1 align=1 + ) + (func (;12;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load16_splat offset=2 align=1 + ) + (func (;13;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load16_splat offset=15 + ) + (func (;14;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load32_splat + ) + (func (;15;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load32_splat align=1 + ) + (func (;16;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load32_splat offset=1 align=1 + ) + (func (;17;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load32_splat offset=2 align=2 + ) + (func (;18;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load32_splat offset=15 + ) + (func (;19;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load64_splat + ) + (func (;20;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load64_splat align=1 + ) + (func (;21;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load64_splat offset=1 align=2 + ) + (func (;22;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load64_splat offset=2 align=4 + ) + (func (;23;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load64_splat offset=15 + ) + (func (;24;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load8_splat offset=65536 + ) + (func (;25;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load16_splat offset=65535 + ) + (func (;26;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load32_splat offset=65533 + ) + (func (;27;) (type 0) (param $address i32) (result v128) + local.get $address + v128.load64_splat offset=65529 + ) + (memory (;0;) 1) + (export "v128.load8_splat" (func 0)) + (export "v128.load16_splat" (func 1)) + (export "v128.load32_splat" (func 2)) + (export "v128.load64_splat" (func 3)) + (export "v8x16.offset0" (func 4)) + (export "v8x16.align1" (func 5)) + (export "v8x16.offset1_align1" (func 6)) + (export "v8x16.offset2_align1" (func 7)) + (export "v8x16.offset15_align1" (func 8)) + (export "v16x8.offset0" (func 9)) + (export "v16x8.align1" (func 10)) + (export "v16x8.offset1_align1" (func 11)) + (export "v16x8.offset2_align1" (func 12)) + (export "v16x8.offset15_align2" (func 13)) + (export "v32x4.offset0" (func 14)) + (export "v32x4.align1" (func 15)) + (export "v32x4.offset1_align1" (func 16)) + (export "v32x4.offset2_align2" (func 17)) + (export "v32x4.offset15_align4" (func 18)) + (export "v64x2.offset0" (func 19)) + (export "v64x2.align1" (func 20)) + (export "v64x2.offset1_align2" (func 21)) + (export "v64x2.offset2_align4" (func 22)) + (export "v64x2.offset15_align8" (func 23)) + (export "v8x16.offset65536" (func 24)) + (export "v16x8.offset65535" (func 25)) + (export "v32x4.offset65533" (func 26)) + (export "v64x2.offset65529" (func 27)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") + (data (;1;) (i32.const 65520) "\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load_splat.wast/101.print b/tests/snapshots/testsuite/simd_load_splat.wast/101.print new file mode 100644 index 0000000000..aaa65dda66 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load_splat.wast/101.print @@ -0,0 +1,98 @@ +(module + (type (;0;) (func (result v128))) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 0 + v128.load8_splat + end + end + ) + (func (;1;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 1 + v128.load16_splat + end + end + ) + (func (;2;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 2 + v128.load32_splat + end + end + ) + (func (;3;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 9 + v128.load64_splat + end + end + ) + (func (;4;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 3 + v128.load8_splat + br 0 (;@1;) + end + ) + (func (;5;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 4 + v128.load16_splat + br 0 (;@1;) + end + ) + (func (;6;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 5 + v128.load32_splat + br 0 (;@1;) + end + ) + (func (;7;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 10 + v128.load64_splat + br 0 (;@1;) + end + ) + (func (;8;) (type 1) (result i32) + i32.const 6 + v128.load8_splat + i8x16.extract_lane_s 0 + ) + (func (;9;) (type 1) (result i32) + i32.const 7 + v128.load16_splat + i8x16.extract_lane_s 0 + ) + (func (;10;) (type 1) (result i32) + i32.const 8 + v128.load32_splat + i8x16.extract_lane_s 0 + ) + (func (;11;) (type 1) (result i32) + i32.const 11 + v128.load64_splat + i8x16.extract_lane_s 0 + ) + (memory (;0;) 1) + (export "v128.load8_splat-in-block" (func 0)) + (export "v128.load16_splat-in-block" (func 1)) + (export "v128.load32_splat-in-block" (func 2)) + (export "v128.load64_splat-in-block" (func 3)) + (export "v128.load8_splat-as-br-value" (func 4)) + (export "v128.load16_splat-as-br-value" (func 5)) + (export "v128.load32_splat-as-br-value" (func 6)) + (export "v128.load64_splat-as-br-value" (func 7)) + (export "v128.load8_splat-extract_lane_s-operand" (func 8)) + (export "v128.load16_splat-extract_lane_s-operand" (func 9)) + (export "v128.load32_splat-extract_lane_s-operand" (func 10)) + (export "v128.load64_splat-extract_lane_s-operand" (func 11)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load_zero.wast/0.print b/tests/snapshots/testsuite/simd_load_zero.wast/0.print new file mode 100644 index 0000000000..602e321457 --- /dev/null +++ b/tests/snapshots/testsuite/simd_load_zero.wast/0.print @@ -0,0 +1,82 @@ +(module + (type (;0;) (func (param i32) (result v128))) + (type (;1;) (func (result v128))) + (func (;0;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32_zero + ) + (func (;1;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load64_zero + ) + (func (;2;) (type 1) (result v128) + i32.const 0 + v128.load32_zero + ) + (func (;3;) (type 1) (result v128) + i32.const 8 + v128.load64_zero + ) + (func (;4;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32_zero + ) + (func (;5;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32_zero align=1 + ) + (func (;6;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32_zero align=1 + ) + (func (;7;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32_zero offset=1 align=1 + ) + (func (;8;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load32_zero offset=10 + ) + (func (;9;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load64_zero + ) + (func (;10;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load64_zero align=1 + ) + (func (;11;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load64_zero align=1 + ) + (func (;12;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load64_zero offset=1 align=1 + ) + (func (;13;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load64_zero offset=10 align=4 + ) + (func (;14;) (type 0) (param $0 i32) (result v128) + local.get $0 + v128.load64_zero offset=20 + ) + (memory (;0;) 1) + (export "v128.load32_zero" (func 0)) + (export "v128.load64_zero" (func 1)) + (export "v128.load32_zero_const0" (func 2)) + (export "v128.load64_zero_const8" (func 3)) + (export "v128.load32_zero_offset0" (func 4)) + (export "v128.load32_zero_align1" (func 5)) + (export "v128.load32_zero_offset0_align1" (func 6)) + (export "v128.load32_zero_offset1_align1" (func 7)) + (export "v128.load32_zero_offset10_align4" (func 8)) + (export "v128.load64_zero_offset0" (func 9)) + (export "v128.load64_zero_align1" (func 10)) + (export "v128.load64_zero_offset0_align1" (func 11)) + (export "v128.load64_zero_offset1_align1" (func 12)) + (export "v128.load64_zero_offset10_align4" (func 13)) + (export "v128.load64_zero_offset20_align8" (func 14)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\80\81\82\83\84\85\86\87\88\89") + (data (;1;) (i32.const 65520) "\0a\0b\0c\0d\0e\0f\80\81\82\83\84\85\86\87\88\89") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_load_zero.wast/32.print b/tests/snapshots/testsuite/simd_load_zero.wast/32.print new file mode 100644 index 0000000000..c6c838449f --- /dev/null +++ b/tests/snapshots/testsuite/simd_load_zero.wast/32.print @@ -0,0 +1,53 @@ +(module + (type (;0;) (func (result v128))) + (type (;1;) (func (result i32))) + (type (;2;) (func (result i64))) + (func (;0;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 0 + v128.load32_zero + end + end + ) + (func (;1;) (type 0) (result v128) + block (result v128) ;; label = @1 + block (result v128) ;; label = @2 + i32.const 1 + v128.load64_zero + end + end + ) + (func (;2;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 6 + v128.load32_zero + br 0 (;@1;) + end + ) + (func (;3;) (type 0) (result v128) + block (result v128) ;; label = @1 + i32.const 7 + v128.load64_zero + br 0 (;@1;) + end + ) + (func (;4;) (type 1) (result i32) + i32.const 12 + v128.load32_zero + i32x4.extract_lane 0 + ) + (func (;5;) (type 2) (result i64) + i32.const 13 + v128.load64_zero + i64x2.extract_lane 0 + ) + (memory (;0;) 1) + (export "v128.load32_zero-in-block" (func 0)) + (export "v128.load64_zero-in-block" (func 1)) + (export "v128.load32_zero-as-br-value" (func 2)) + (export "v128.load64_zero-as-br-value" (func 3)) + (export "v128.load32_zero-extract_lane_s-operand" (func 4)) + (export "v128.load64_zero-extract_lane_s-operand" (func 5)) + (data (;0;) (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\80\81\82\83\84\85\86\87\88\89") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_splat.wast/0.print b/tests/snapshots/testsuite/simd_splat.wast/0.print new file mode 100644 index 0000000000..cb4331891d --- /dev/null +++ b/tests/snapshots/testsuite/simd_splat.wast/0.print @@ -0,0 +1,36 @@ +(module + (type (;0;) (func (param i32) (result v128))) + (type (;1;) (func (param f32) (result v128))) + (type (;2;) (func (param i64) (result v128))) + (type (;3;) (func (param f64) (result v128))) + (func (;0;) (type 0) (param i32) (result v128) + local.get 0 + i8x16.splat + ) + (func (;1;) (type 0) (param i32) (result v128) + local.get 0 + i16x8.splat + ) + (func (;2;) (type 0) (param i32) (result v128) + local.get 0 + i32x4.splat + ) + (func (;3;) (type 1) (param f32) (result v128) + local.get 0 + f32x4.splat + ) + (func (;4;) (type 2) (param i64) (result v128) + local.get 0 + i64x2.splat + ) + (func (;5;) (type 3) (param f64) (result v128) + local.get 0 + f64x2.splat + ) + (export "i8x16.splat" (func 0)) + (export "i16x8.splat" (func 1)) + (export "i32x4.splat" (func 2)) + (export "f32x4.splat" (func 3)) + (export "i64x2.splat" (func 4)) + (export "f64x2.splat" (func 5)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_splat.wast/120.print b/tests/snapshots/testsuite/simd_splat.wast/120.print new file mode 100644 index 0000000000..2d99fbd9a7 --- /dev/null +++ b/tests/snapshots/testsuite/simd_splat.wast/120.print @@ -0,0 +1,51 @@ +(module + (type (;0;) (func (param i32) (result v128))) + (type (;1;) (func (param i64) (result v128))) + (type (;2;) (func (param f64) (result v128))) + (func (;0;) (type 0) (param i32) (result v128) + i32.const 0 + local.get 0 + i8x16.splat + v128.store + i32.const 0 + v128.load + ) + (func (;1;) (type 0) (param i32) (result v128) + i32.const 0 + local.get 0 + i16x8.splat + v128.store + i32.const 0 + v128.load + ) + (func (;2;) (type 0) (param i32) (result v128) + i32.const 0 + local.get 0 + i32x4.splat + v128.store + i32.const 0 + v128.load + ) + (func (;3;) (type 1) (param i64) (result v128) + i32.const 0 + local.get 0 + i64x2.splat + v128.store + i32.const 0 + v128.load + ) + (func (;4;) (type 2) (param f64) (result v128) + i32.const 0 + local.get 0 + f64x2.splat + v128.store + i32.const 0 + v128.load + ) + (memory (;0;) 1) + (export "as-v128_store-operand-1" (func 0)) + (export "as-v128_store-operand-2" (func 1)) + (export "as-v128_store-operand-3" (func 2)) + (export "as-v128_store-operand-4" (func 3)) + (export "as-v128_store-operand-5" (func 4)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_splat.wast/126.print b/tests/snapshots/testsuite/simd_splat.wast/126.print new file mode 100644 index 0000000000..bc59891dca --- /dev/null +++ b/tests/snapshots/testsuite/simd_splat.wast/126.print @@ -0,0 +1,347 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param f32) (result f32))) + (type (;2;) (func (param i32 i32) (result v128))) + (type (;3;) (func (param i64) (result i64))) + (type (;4;) (func (param f64) (result f64))) + (type (;5;) (func (param i32 i32 i32) (result v128))) + (type (;6;) (func (param i32 i32 i32 i32) (result v128))) + (type (;7;) (func (param i64 i64 i64 i64) (result v128))) + (type (;8;) (func (param f64 f64 f64 f64) (result v128))) + (type (;9;) (func (param i64) (result i32))) + (type (;10;) (func (param i64 i64) (result v128))) + (type (;11;) (func (param f32 f32) (result v128))) + (type (;12;) (func (param f64 f64) (result v128))) + (type (;13;) (func (param f32) (result v128))) + (type (;14;) (func (param i32) (result v128))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + i8x16.splat + i8x16.extract_lane_s 0 + ) + (func (;1;) (type 0) (param i32) (result i32) + local.get 0 + i8x16.splat + i8x16.extract_lane_s 15 + ) + (func (;2;) (type 0) (param i32) (result i32) + local.get 0 + i16x8.splat + i16x8.extract_lane_s 0 + ) + (func (;3;) (type 0) (param i32) (result i32) + local.get 0 + i16x8.splat + i16x8.extract_lane_s 7 + ) + (func (;4;) (type 0) (param i32) (result i32) + local.get 0 + i32x4.splat + i32x4.extract_lane 0 + ) + (func (;5;) (type 0) (param i32) (result i32) + local.get 0 + i32x4.splat + i32x4.extract_lane 3 + ) + (func (;6;) (type 1) (param f32) (result f32) + local.get 0 + f32x4.splat + f32x4.extract_lane 0 + ) + (func (;7;) (type 1) (param f32) (result f32) + local.get 0 + f32x4.splat + f32x4.extract_lane 3 + ) + (func (;8;) (type 2) (param i32 i32) (result v128) + local.get 0 + i8x16.splat + local.get 1 + i8x16.splat + i8x16.swizzle + ) + (func (;9;) (type 3) (param i64) (result i64) + local.get 0 + i64x2.splat + i64x2.extract_lane 0 + ) + (func (;10;) (type 3) (param i64) (result i64) + local.get 0 + i64x2.splat + i64x2.extract_lane 1 + ) + (func (;11;) (type 4) (param f64) (result f64) + local.get 0 + f64x2.splat + f64x2.extract_lane 0 + ) + (func (;12;) (type 4) (param f64) (result f64) + local.get 0 + f64x2.splat + f64x2.extract_lane 1 + ) + (func (;13;) (type 5) (param i32 i32 i32) (result v128) + local.get 0 + i8x16.splat + local.get 1 + i8x16.splat + local.get 2 + i8x16.splat + i8x16.sub + i8x16.add + ) + (func (;14;) (type 6) (param i32 i32 i32 i32) (result v128) + local.get 0 + i16x8.splat + local.get 1 + i16x8.splat + local.get 2 + i16x8.splat + local.get 3 + i16x8.splat + i16x8.mul + i16x8.sub + i16x8.add + ) + (func (;15;) (type 6) (param i32 i32 i32 i32) (result v128) + local.get 0 + i32x4.splat + local.get 1 + i32x4.splat + local.get 2 + i32x4.splat + local.get 3 + i32x4.splat + i32x4.mul + i32x4.sub + i32x4.add + ) + (func (;16;) (type 7) (param i64 i64 i64 i64) (result v128) + local.get 0 + i64x2.splat + local.get 1 + i64x2.splat + local.get 2 + i64x2.splat + local.get 3 + i64x2.splat + i64x2.mul + i64x2.sub + i64x2.add + ) + (func (;17;) (type 8) (param f64 f64 f64 f64) (result v128) + local.get 0 + f64x2.splat + local.get 1 + f64x2.splat + local.get 2 + f64x2.splat + local.get 3 + f64x2.splat + f64x2.mul + f64x2.sub + f64x2.add + ) + (func (;18;) (type 2) (param i32 i32) (result v128) + local.get 0 + i8x16.splat + local.get 1 + i8x16.splat + i8x16.add_sat_s + ) + (func (;19;) (type 2) (param i32 i32) (result v128) + local.get 0 + i16x8.splat + local.get 1 + i16x8.splat + i16x8.add_sat_s + ) + (func (;20;) (type 2) (param i32 i32) (result v128) + local.get 0 + i8x16.splat + local.get 1 + i8x16.splat + i8x16.sub_sat_u + ) + (func (;21;) (type 2) (param i32 i32) (result v128) + local.get 0 + i16x8.splat + local.get 1 + i16x8.splat + i16x8.sub_sat_u + ) + (func (;22;) (type 2) (param i32 i32) (result v128) + local.get 0 + i8x16.splat + local.get 1 + i8x16.shr_s + ) + (func (;23;) (type 2) (param i32 i32) (result v128) + local.get 0 + i16x8.splat + local.get 1 + i16x8.shr_s + ) + (func (;24;) (type 2) (param i32 i32) (result v128) + local.get 0 + i32x4.splat + local.get 1 + i32x4.shr_s + ) + (func (;25;) (type 2) (param i32 i32) (result v128) + local.get 0 + i8x16.splat + local.get 1 + i8x16.splat + v128.and + ) + (func (;26;) (type 2) (param i32 i32) (result v128) + local.get 0 + i16x8.splat + local.get 1 + i16x8.splat + v128.or + ) + (func (;27;) (type 2) (param i32 i32) (result v128) + local.get 0 + i32x4.splat + local.get 1 + i32x4.splat + v128.xor + ) + (func (;28;) (type 0) (param i32) (result i32) + local.get 0 + i8x16.splat + i8x16.all_true + ) + (func (;29;) (type 0) (param i32) (result i32) + local.get 0 + i16x8.splat + i16x8.all_true + ) + (func (;30;) (type 0) (param i32) (result i32) + local.get 0 + i32x4.splat + i32x4.all_true + ) + (func (;31;) (type 9) (param i64) (result i32) + local.get 0 + i64x2.splat + i32x4.all_true + ) + (func (;32;) (type 2) (param i32 i32) (result v128) + local.get 0 + i8x16.splat + local.get 1 + i8x16.splat + i8x16.eq + ) + (func (;33;) (type 2) (param i32 i32) (result v128) + local.get 0 + i16x8.splat + local.get 1 + i16x8.splat + i16x8.eq + ) + (func (;34;) (type 2) (param i32 i32) (result v128) + local.get 0 + i32x4.splat + local.get 1 + i32x4.splat + i32x4.eq + ) + (func (;35;) (type 10) (param i64 i64) (result v128) + local.get 0 + i64x2.splat + local.get 1 + i64x2.splat + i32x4.eq + ) + (func (;36;) (type 11) (param f32 f32) (result v128) + local.get 0 + f32x4.splat + local.get 1 + f32x4.splat + f32x4.eq + ) + (func (;37;) (type 12) (param f64 f64) (result v128) + local.get 0 + f64x2.splat + local.get 1 + f64x2.splat + f64x2.eq + ) + (func (;38;) (type 13) (param f32) (result v128) + local.get 0 + f32x4.splat + f32x4.abs + ) + (func (;39;) (type 11) (param f32 f32) (result v128) + local.get 0 + f32x4.splat + local.get 1 + f32x4.splat + f32x4.min + ) + (func (;40;) (type 11) (param f32 f32) (result v128) + local.get 0 + f32x4.splat + local.get 1 + f32x4.splat + f32x4.div + ) + (func (;41;) (type 14) (param i32) (result v128) + local.get 0 + i32x4.splat + f32x4.convert_i32x4_s + ) + (func (;42;) (type 13) (param f32) (result v128) + local.get 0 + f32x4.splat + i32x4.trunc_sat_f32x4_s + ) + (export "as-i8x16_extract_lane_s-operand-first" (func 0)) + (export "as-i8x16_extract_lane_s-operand-last" (func 1)) + (export "as-i16x8_extract_lane_s-operand-first" (func 2)) + (export "as-i16x8_extract_lane_s-operand-last" (func 3)) + (export "as-i32x4_extract_lane_s-operand-first" (func 4)) + (export "as-i32x4_extract_lane_s-operand-last" (func 5)) + (export "as-f32x4_extract_lane_s-operand-first" (func 6)) + (export "as-f32x4_extract_lane_s-operand-last" (func 7)) + (export "as-v8x16_swizzle-operands" (func 8)) + (export "as-i64x2_extract_lane-operand-first" (func 9)) + (export "as-i64x2_extract_lane-operand-last" (func 10)) + (export "as-f64x2_extract_lane-operand-first" (func 11)) + (export "as-f64x2_extract_lane-operand-last" (func 12)) + (export "as-i8x16_add_sub-operands" (func 13)) + (export "as-i16x8_add_sub_mul-operands" (func 14)) + (export "as-i32x4_add_sub_mul-operands" (func 15)) + (export "as-i64x2_add_sub_mul-operands" (func 16)) + (export "as-f64x2_add_sub_mul-operands" (func 17)) + (export "as-i8x16_add_sat_s-operands" (func 18)) + (export "as-i16x8_add_sat_s-operands" (func 19)) + (export "as-i8x16_sub_sat_u-operands" (func 20)) + (export "as-i16x8_sub_sat_u-operands" (func 21)) + (export "as-i8x16_shr_s-operand" (func 22)) + (export "as-i16x8_shr_s-operand" (func 23)) + (export "as-i32x4_shr_s-operand" (func 24)) + (export "as-v128_and-operands" (func 25)) + (export "as-v128_or-operands" (func 26)) + (export "as-v128_xor-operands" (func 27)) + (export "as-i8x16_all_true-operand" (func 28)) + (export "as-i16x8_all_true-operand" (func 29)) + (export "as-i32x4_all_true-operand1" (func 30)) + (export "as-i32x4_all_true-operand2" (func 31)) + (export "as-i8x16_eq-operands" (func 32)) + (export "as-i16x8_eq-operands" (func 33)) + (export "as-i32x4_eq-operands1" (func 34)) + (export "as-i32x4_eq-operands2" (func 35)) + (export "as-f32x4_eq-operands" (func 36)) + (export "as-f64x2_eq-operands" (func 37)) + (export "as-f32x4_abs-operand" (func 38)) + (export "as-f32x4_min-operands" (func 39)) + (export "as-f32x4_div-operands" (func 40)) + (export "as-f32x4_convert_s_i32x4-operand" (func 41)) + (export "as-i32x4_trunc_s_f32x4_sat-operand" (func 42)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_splat.wast/170.print b/tests/snapshots/testsuite/simd_splat.wast/170.print new file mode 100644 index 0000000000..487e4e37a8 --- /dev/null +++ b/tests/snapshots/testsuite/simd_splat.wast/170.print @@ -0,0 +1,69 @@ +(module + (type (;0;) (func (param i32) (result v128))) + (type (;1;) (func (param f32) (result v128))) + (type (;2;) (func (param i64) (result v128))) + (type (;3;) (func (param f64) (result v128))) + (func (;0;) (type 0) (param i32) (result v128) + block (result v128) ;; label = @1 + local.get 0 + i8x16.splat + br 0 (;@1;) + end + ) + (func (;1;) (type 0) (param i32) (result v128) + local.get 0 + i16x8.splat + return + ) + (func (;2;) (type 0) (param i32) (result v128) + (local v128) + local.get 0 + i32x4.splat + local.set 1 + local.get 1 + return + ) + (func (;3;) (type 1) (param f32) (result v128) + local.get 0 + f32x4.splat + global.set $g + global.get $g + return + ) + (func (;4;) (type 2) (param i64) (result v128) + block (result v128) ;; label = @1 + local.get 0 + i64x2.splat + br 0 (;@1;) + end + ) + (func (;5;) (type 2) (param i64) (result v128) + local.get 0 + i64x2.splat + return + ) + (func (;6;) (type 2) (param i64) (result v128) + (local v128) + local.get 0 + i64x2.splat + local.set 1 + local.get 1 + return + ) + (func (;7;) (type 3) (param f64) (result v128) + local.get 0 + f64x2.splat + global.set $g + global.get $g + return + ) + (global $g (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (export "as-br-value1" (func 0)) + (export "as-return-value1" (func 1)) + (export "as-local_set-value1" (func 2)) + (export "as-global_set-value1" (func 3)) + (export "as-br-value2" (func 4)) + (export "as-return-value2" (func 5)) + (export "as-local_set-value2" (func 6)) + (export "as-global_set-value2" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_store.wast/0.print b/tests/snapshots/testsuite/simd_store.wast/0.print new file mode 100644 index 0000000000..57984cdbd3 --- /dev/null +++ b/tests/snapshots/testsuite/simd_store.wast/0.print @@ -0,0 +1,68 @@ +(module + (type (;0;) (func (result v128))) + (func (;0;) (type 0) (result v128) + i32.const 0 + v128.const i32x4 0x03020100 0x07060504 0x0b0a0908 0x0f0e0d0c + v128.store + i32.const 0 + v128.load + ) + (func (;1;) (type 0) (result v128) + i32.const 0 + v128.const i32x4 0x00010000 0x00030002 0x00050004 0x00070006 + v128.store + i32.const 0 + v128.load + ) + (func (;2;) (type 0) (result v128) + i32.const 0 + v128.const i32x4 0x30393039 0x30393039 0x30393039 0x30393039 + v128.store + i32.const 0 + v128.load + ) + (func (;3;) (type 0) (result v128) + i32.const 0 + v128.const i32x4 0x12341234 0x12341234 0x12341234 0x12341234 + v128.store + i32.const 0 + v128.load + ) + (func (;4;) (type 0) (result v128) + i32.const 0 + v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003 + v128.store + i32.const 0 + v128.load + ) + (func (;5;) (type 0) (result v128) + i32.const 0 + v128.const i32x4 0x075bcd15 0x075bcd15 0x075bcd15 0x075bcd15 + v128.store + i32.const 0 + v128.load + ) + (func (;6;) (type 0) (result v128) + i32.const 0 + v128.const i32x4 0x12345678 0x12345678 0x12345678 0x12345678 + v128.store + i32.const 0 + v128.load + ) + (func (;7;) (type 0) (result v128) + i32.const 0 + v128.const i32x4 0x00000000 0x3f800000 0x40000000 0x40400000 + v128.store + i32.const 0 + v128.load + ) + (memory (;0;) 1) + (export "v128.store_i8x16" (func 0)) + (export "v128.store_i16x8" (func 1)) + (export "v128.store_i16x8_2" (func 2)) + (export "v128.store_i16x8_3" (func 3)) + (export "v128.store_i32x4" (func 4)) + (export "v128.store_i32x4_2" (func 5)) + (export "v128.store_i32x4_3" (func 6)) + (export "v128.store_f32x4" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_store.wast/9.print b/tests/snapshots/testsuite/simd_store.wast/9.print new file mode 100644 index 0000000000..a3a902e70b --- /dev/null +++ b/tests/snapshots/testsuite/simd_store.wast/9.print @@ -0,0 +1,85 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + end + ) + (func (;1;) (type 0) + loop ;; label = @1 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + end + ) + (func (;2;) (type 0) + block ;; label = @1 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + br 0 (;@1;) + end + ) + (func (;3;) (type 0) + block ;; label = @1 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;4;) (type 0) + block ;; label = @1 + i32.const 6 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + br_if 0 (;@1;) + end + ) + (func (;5;) (type 0) + block ;; label = @1 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + i32.const 1 + br_table 0 (;@1;) + end + ) + (func (;6;) (type 0) + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + return + ) + (func (;7;) (type 0) + i32.const 1 + if ;; label = @1 + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + end + ) + (func (;8;) (type 0) + i32.const 0 + if ;; label = @1 + else + i32.const 0 + v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 + v128.store + end + ) + (memory (;0;) 1) + (export "as-block-value" (func 0)) + (export "as-loop-value" (func 1)) + (export "as-br-value" (func 2)) + (export "as-br_if-value" (func 3)) + (export "as-br_if-value-cond" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-return-value" (func 6)) + (export "as-if-then" (func 7)) + (export "as-if-else" (func 8)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_store16_lane.wast/0.print b/tests/snapshots/testsuite/simd_store16_lane.wast/0.print new file mode 100644 index 0000000000..f572033b41 --- /dev/null +++ b/tests/snapshots/testsuite/simd_store16_lane.wast/0.print @@ -0,0 +1,454 @@ +(module + (type (;0;) (func (param i32 v128) (result i64))) + (type (;1;) (func (param v128) (result i64))) + (func (;0;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 0 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;1;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 1 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;2;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 2 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;3;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 3 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;4;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 4 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;5;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 5 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;6;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 6 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;7;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 7 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;8;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store16_lane 0 + i32.const 0 + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;9;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store16_lane offset=1 1 + i32.const 0 + i64.load offset=1 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;10;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store16_lane offset=2 2 + i32.const 0 + i64.load offset=2 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;11;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store16_lane offset=3 3 + i32.const 0 + i64.load offset=3 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (func (;12;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store16_lane offset=4 4 + i32.const 0 + i64.load offset=4 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=4 + local.get $ret + ) + (func (;13;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store16_lane offset=5 5 + i32.const 0 + i64.load offset=5 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=5 + local.get $ret + ) + (func (;14;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store16_lane offset=6 6 + i32.const 0 + i64.load offset=6 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=6 + local.get $ret + ) + (func (;15;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store16_lane offset=7 7 + i32.const 0 + i64.load offset=7 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=7 + local.get $ret + ) + (func (;16;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane align=1 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;17;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;18;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane align=1 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;19;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;20;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane align=1 2 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;21;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 2 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;22;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane align=1 3 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (func (;23;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 3 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (func (;24;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane align=1 4 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=4 + local.get $ret + ) + (func (;25;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 4 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=4 + local.get $ret + ) + (func (;26;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane align=1 5 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=5 + local.get $ret + ) + (func (;27;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 5 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=5 + local.get $ret + ) + (func (;28;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane align=1 6 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=6 + local.get $ret + ) + (func (;29;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 6 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=6 + local.get $ret + ) + (func (;30;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane align=1 7 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=7 + local.get $ret + ) + (func (;31;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store16_lane 7 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=7 + local.get $ret + ) + (memory (;0;) 1) + (global $zero (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (export "v128.store16_lane_0" (func 0)) + (export "v128.store16_lane_1" (func 1)) + (export "v128.store16_lane_2" (func 2)) + (export "v128.store16_lane_3" (func 3)) + (export "v128.store16_lane_4" (func 4)) + (export "v128.store16_lane_5" (func 5)) + (export "v128.store16_lane_6" (func 6)) + (export "v128.store16_lane_7" (func 7)) + (export "v128.store16_lane_0_offset_0" (func 8)) + (export "v128.store16_lane_1_offset_1" (func 9)) + (export "v128.store16_lane_2_offset_2" (func 10)) + (export "v128.store16_lane_3_offset_3" (func 11)) + (export "v128.store16_lane_4_offset_4" (func 12)) + (export "v128.store16_lane_5_offset_5" (func 13)) + (export "v128.store16_lane_6_offset_6" (func 14)) + (export "v128.store16_lane_7_offset_7" (func 15)) + (export "v128.store16_lane_0_align_1" (func 16)) + (export "v128.store16_lane_0_align_2" (func 17)) + (export "v128.store16_lane_1_align_1" (func 18)) + (export "v128.store16_lane_1_align_2" (func 19)) + (export "v128.store16_lane_2_align_1" (func 20)) + (export "v128.store16_lane_2_align_2" (func 21)) + (export "v128.store16_lane_3_align_1" (func 22)) + (export "v128.store16_lane_3_align_2" (func 23)) + (export "v128.store16_lane_4_align_1" (func 24)) + (export "v128.store16_lane_4_align_2" (func 25)) + (export "v128.store16_lane_5_align_1" (func 26)) + (export "v128.store16_lane_5_align_2" (func 27)) + (export "v128.store16_lane_6_align_1" (func 28)) + (export "v128.store16_lane_6_align_2" (func 29)) + (export "v128.store16_lane_7_align_1" (func 30)) + (export "v128.store16_lane_7_align_2" (func 31)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_store32_lane.wast/0.print b/tests/snapshots/testsuite/simd_store32_lane.wast/0.print new file mode 100644 index 0000000000..3bd18eb65d --- /dev/null +++ b/tests/snapshots/testsuite/simd_store32_lane.wast/0.print @@ -0,0 +1,286 @@ +(module + (type (;0;) (func (param i32 v128) (result i64))) + (type (;1;) (func (param v128) (result i64))) + (func (;0;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane 0 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;1;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane 1 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;2;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane 2 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;3;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane 3 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;4;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store32_lane 0 + i32.const 0 + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;5;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store32_lane offset=1 1 + i32.const 0 + i64.load offset=1 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;6;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store32_lane offset=2 2 + i32.const 0 + i64.load offset=2 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;7;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store32_lane offset=3 3 + i32.const 0 + i64.load offset=3 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (func (;8;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane align=1 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;9;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane align=2 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;10;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;11;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane align=1 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;12;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane align=2 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;13;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;14;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane align=1 2 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;15;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane align=2 2 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;16;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane 2 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;17;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane align=1 3 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (func (;18;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane align=2 3 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (func (;19;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store32_lane 3 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (memory (;0;) 1) + (global $zero (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (export "v128.store32_lane_0" (func 0)) + (export "v128.store32_lane_1" (func 1)) + (export "v128.store32_lane_2" (func 2)) + (export "v128.store32_lane_3" (func 3)) + (export "v128.store32_lane_0_offset_0" (func 4)) + (export "v128.store32_lane_1_offset_1" (func 5)) + (export "v128.store32_lane_2_offset_2" (func 6)) + (export "v128.store32_lane_3_offset_3" (func 7)) + (export "v128.store32_lane_0_align_1" (func 8)) + (export "v128.store32_lane_0_align_2" (func 9)) + (export "v128.store32_lane_0_align_4" (func 10)) + (export "v128.store32_lane_1_align_1" (func 11)) + (export "v128.store32_lane_1_align_2" (func 12)) + (export "v128.store32_lane_1_align_4" (func 13)) + (export "v128.store32_lane_2_align_1" (func 14)) + (export "v128.store32_lane_2_align_2" (func 15)) + (export "v128.store32_lane_2_align_4" (func 16)) + (export "v128.store32_lane_3_align_1" (func 17)) + (export "v128.store32_lane_3_align_2" (func 18)) + (export "v128.store32_lane_3_align_4" (func 19)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_store64_lane.wast/0.print b/tests/snapshots/testsuite/simd_store64_lane.wast/0.print new file mode 100644 index 0000000000..c775fc7e5d --- /dev/null +++ b/tests/snapshots/testsuite/simd_store64_lane.wast/0.print @@ -0,0 +1,174 @@ +(module + (type (;0;) (func (param i32 v128) (result i64))) + (type (;1;) (func (param v128) (result i64))) + (func (;0;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane 0 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;1;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane 1 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;2;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store64_lane 0 + i32.const 0 + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;3;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store64_lane offset=1 1 + i32.const 0 + i64.load offset=1 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;4;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane align=1 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;5;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane align=2 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;6;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane align=4 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;7;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;8;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane align=1 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;9;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane align=2 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;10;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane align=4 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;11;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store64_lane 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (memory (;0;) 1) + (global $zero (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (export "v128.store64_lane_0" (func 0)) + (export "v128.store64_lane_1" (func 1)) + (export "v128.store64_lane_0_offset_0" (func 2)) + (export "v128.store64_lane_1_offset_1" (func 3)) + (export "v128.store64_lane_0_align_1" (func 4)) + (export "v128.store64_lane_0_align_2" (func 5)) + (export "v128.store64_lane_0_align_4" (func 6)) + (export "v128.store64_lane_0_align_8" (func 7)) + (export "v128.store64_lane_1_align_1" (func 8)) + (export "v128.store64_lane_1_align_2" (func 9)) + (export "v128.store64_lane_1_align_4" (func 10)) + (export "v128.store64_lane_1_align_8" (func 11)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/simd_store8_lane.wast/0.print b/tests/snapshots/testsuite/simd_store8_lane.wast/0.print new file mode 100644 index 0000000000..520b6f3246 --- /dev/null +++ b/tests/snapshots/testsuite/simd_store8_lane.wast/0.print @@ -0,0 +1,678 @@ +(module + (type (;0;) (func (param i32 v128) (result i64))) + (type (;1;) (func (param v128) (result i64))) + (func (;0;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 0 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;1;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 1 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;2;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 2 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;3;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 3 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;4;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 4 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;5;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 5 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;6;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 6 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;7;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 7 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;8;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 8 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;9;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 9 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;10;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 10 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;11;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 11 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;12;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 12 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;13;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 13 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;14;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 14 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;15;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 15 + local.get $address + i64.load + local.set $ret + local.get $address + global.get $zero + v128.store + local.get $ret + ) + (func (;16;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane 0 + i32.const 0 + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;17;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=1 1 + i32.const 0 + i64.load offset=1 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;18;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=2 2 + i32.const 0 + i64.load offset=2 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;19;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=3 3 + i32.const 0 + i64.load offset=3 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (func (;20;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=4 4 + i32.const 0 + i64.load offset=4 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=4 + local.get $ret + ) + (func (;21;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=5 5 + i32.const 0 + i64.load offset=5 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=5 + local.get $ret + ) + (func (;22;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=6 6 + i32.const 0 + i64.load offset=6 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=6 + local.get $ret + ) + (func (;23;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=7 7 + i32.const 0 + i64.load offset=7 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=7 + local.get $ret + ) + (func (;24;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=8 8 + i32.const 0 + i64.load offset=8 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=8 + local.get $ret + ) + (func (;25;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=9 9 + i32.const 0 + i64.load offset=9 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=9 + local.get $ret + ) + (func (;26;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=10 10 + i32.const 0 + i64.load offset=10 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=10 + local.get $ret + ) + (func (;27;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=11 11 + i32.const 0 + i64.load offset=11 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=11 + local.get $ret + ) + (func (;28;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=12 12 + i32.const 0 + i64.load offset=12 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=12 + local.get $ret + ) + (func (;29;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=13 13 + i32.const 0 + i64.load offset=13 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=13 + local.get $ret + ) + (func (;30;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=14 14 + i32.const 0 + i64.load offset=14 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=14 + local.get $ret + ) + (func (;31;) (type 1) (param $x v128) (result i64) + (local $ret i64) + i32.const 0 + local.get $x + v128.store8_lane offset=15 15 + i32.const 0 + i64.load offset=15 + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=15 + local.get $ret + ) + (func (;32;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 0 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store + local.get $ret + ) + (func (;33;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 1 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=1 + local.get $ret + ) + (func (;34;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 2 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=2 + local.get $ret + ) + (func (;35;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 3 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=3 + local.get $ret + ) + (func (;36;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 4 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=4 + local.get $ret + ) + (func (;37;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 5 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=5 + local.get $ret + ) + (func (;38;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 6 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=6 + local.get $ret + ) + (func (;39;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 7 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=7 + local.get $ret + ) + (func (;40;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 8 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=8 + local.get $ret + ) + (func (;41;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 9 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=9 + local.get $ret + ) + (func (;42;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 10 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=10 + local.get $ret + ) + (func (;43;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 11 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=11 + local.get $ret + ) + (func (;44;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 12 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=12 + local.get $ret + ) + (func (;45;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 13 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=13 + local.get $ret + ) + (func (;46;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 14 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=14 + local.get $ret + ) + (func (;47;) (type 0) (param $address i32) (param $x v128) (result i64) + (local $ret i64) + local.get $address + local.get $x + v128.store8_lane 15 + local.get $address + i64.load + local.set $ret + i32.const 0 + global.get $zero + v128.store offset=15 + local.get $ret + ) + (memory (;0;) 1) + (global $zero (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (export "v128.store8_lane_0" (func 0)) + (export "v128.store8_lane_1" (func 1)) + (export "v128.store8_lane_2" (func 2)) + (export "v128.store8_lane_3" (func 3)) + (export "v128.store8_lane_4" (func 4)) + (export "v128.store8_lane_5" (func 5)) + (export "v128.store8_lane_6" (func 6)) + (export "v128.store8_lane_7" (func 7)) + (export "v128.store8_lane_8" (func 8)) + (export "v128.store8_lane_9" (func 9)) + (export "v128.store8_lane_10" (func 10)) + (export "v128.store8_lane_11" (func 11)) + (export "v128.store8_lane_12" (func 12)) + (export "v128.store8_lane_13" (func 13)) + (export "v128.store8_lane_14" (func 14)) + (export "v128.store8_lane_15" (func 15)) + (export "v128.store8_lane_0_offset_0" (func 16)) + (export "v128.store8_lane_1_offset_1" (func 17)) + (export "v128.store8_lane_2_offset_2" (func 18)) + (export "v128.store8_lane_3_offset_3" (func 19)) + (export "v128.store8_lane_4_offset_4" (func 20)) + (export "v128.store8_lane_5_offset_5" (func 21)) + (export "v128.store8_lane_6_offset_6" (func 22)) + (export "v128.store8_lane_7_offset_7" (func 23)) + (export "v128.store8_lane_8_offset_8" (func 24)) + (export "v128.store8_lane_9_offset_9" (func 25)) + (export "v128.store8_lane_10_offset_10" (func 26)) + (export "v128.store8_lane_11_offset_11" (func 27)) + (export "v128.store8_lane_12_offset_12" (func 28)) + (export "v128.store8_lane_13_offset_13" (func 29)) + (export "v128.store8_lane_14_offset_14" (func 30)) + (export "v128.store8_lane_15_offset_15" (func 31)) + (export "v128.store8_lane_0_align_1" (func 32)) + (export "v128.store8_lane_1_align_1" (func 33)) + (export "v128.store8_lane_2_align_1" (func 34)) + (export "v128.store8_lane_3_align_1" (func 35)) + (export "v128.store8_lane_4_align_1" (func 36)) + (export "v128.store8_lane_5_align_1" (func 37)) + (export "v128.store8_lane_6_align_1" (func 38)) + (export "v128.store8_lane_7_align_1" (func 39)) + (export "v128.store8_lane_8_align_1" (func 40)) + (export "v128.store8_lane_9_align_1" (func 41)) + (export "v128.store8_lane_10_align_1" (func 42)) + (export "v128.store8_lane_11_align_1" (func 43)) + (export "v128.store8_lane_12_align_1" (func 44)) + (export "v128.store8_lane_13_align_1" (func 45)) + (export "v128.store8_lane_14_align_1" (func 46)) + (export "v128.store8_lane_15_align_1" (func 47)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/skip-stack-guard-page.wast/0.print b/tests/snapshots/testsuite/skip-stack-guard-page.wast/0.print new file mode 100644 index 0000000000..bd7d9741cf --- /dev/null +++ b/tests/snapshots/testsuite/skip-stack-guard-page.wast/0.print @@ -0,0 +1,6359 @@ +(module + (type (;0;) (func (param i32))) + (type (;1;) (func)) + (func $test-guard-page-skip (;0;) (type 0) (param $depth i32) + local.get $depth + i32.const 0 + i32.eq + if ;; label = @1 + call $function-with-many-locals + else + local.get $depth + i32.const 1 + i32.sub + call $test-guard-page-skip + end + ) + (func $function-with-many-locals (;1;) (type 1) + (local i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64) + call $function-with-many-locals + i32.const 0 + i64.load align=1 + local.set 0 + i32.const 0 + i64.load offset=1 align=1 + local.set 1 + i32.const 0 + i64.load offset=2 align=1 + local.set 2 + i32.const 0 + i64.load offset=3 align=1 + local.set 3 + i32.const 0 + i64.load offset=4 align=1 + local.set 4 + i32.const 0 + i64.load offset=5 align=1 + local.set 5 + i32.const 0 + i64.load offset=6 align=1 + local.set 6 + i32.const 0 + i64.load offset=7 align=1 + local.set 7 + i32.const 0 + i64.load offset=8 align=1 + local.set 8 + i32.const 0 + i64.load offset=9 align=1 + local.set 9 + i32.const 0 + i64.load offset=10 align=1 + local.set 10 + i32.const 0 + i64.load offset=11 align=1 + local.set 11 + i32.const 0 + i64.load offset=12 align=1 + local.set 12 + i32.const 0 + i64.load offset=13 align=1 + local.set 13 + i32.const 0 + i64.load offset=14 align=1 + local.set 14 + i32.const 0 + i64.load offset=15 align=1 + local.set 15 + i32.const 0 + i64.load offset=16 align=1 + local.set 16 + i32.const 0 + i64.load offset=17 align=1 + local.set 17 + i32.const 0 + i64.load offset=18 align=1 + local.set 18 + i32.const 0 + i64.load offset=19 align=1 + local.set 19 + i32.const 0 + i64.load offset=20 align=1 + local.set 20 + i32.const 0 + i64.load offset=21 align=1 + local.set 21 + i32.const 0 + i64.load offset=22 align=1 + local.set 22 + i32.const 0 + i64.load offset=23 align=1 + local.set 23 + i32.const 0 + i64.load offset=24 align=1 + local.set 24 + i32.const 0 + i64.load offset=25 align=1 + local.set 25 + i32.const 0 + i64.load offset=26 align=1 + local.set 26 + i32.const 0 + i64.load offset=27 align=1 + local.set 27 + i32.const 0 + i64.load offset=28 align=1 + local.set 28 + i32.const 0 + i64.load offset=29 align=1 + local.set 29 + i32.const 0 + i64.load offset=30 align=1 + local.set 30 + i32.const 0 + i64.load offset=31 align=1 + local.set 31 + i32.const 0 + i64.load offset=32 align=1 + local.set 32 + i32.const 0 + i64.load offset=33 align=1 + local.set 33 + i32.const 0 + i64.load offset=34 align=1 + local.set 34 + i32.const 0 + i64.load offset=35 align=1 + local.set 35 + i32.const 0 + i64.load offset=36 align=1 + local.set 36 + i32.const 0 + i64.load offset=37 align=1 + local.set 37 + i32.const 0 + i64.load offset=38 align=1 + local.set 38 + i32.const 0 + i64.load offset=39 align=1 + local.set 39 + i32.const 0 + i64.load offset=40 align=1 + local.set 40 + i32.const 0 + i64.load offset=41 align=1 + local.set 41 + i32.const 0 + i64.load offset=42 align=1 + local.set 42 + i32.const 0 + i64.load offset=43 align=1 + local.set 43 + i32.const 0 + i64.load offset=44 align=1 + local.set 44 + i32.const 0 + i64.load offset=45 align=1 + local.set 45 + i32.const 0 + i64.load offset=46 align=1 + local.set 46 + i32.const 0 + i64.load offset=47 align=1 + local.set 47 + i32.const 0 + i64.load offset=48 align=1 + local.set 48 + i32.const 0 + i64.load offset=49 align=1 + local.set 49 + i32.const 0 + i64.load offset=50 align=1 + local.set 50 + i32.const 0 + i64.load offset=51 align=1 + local.set 51 + i32.const 0 + i64.load offset=52 align=1 + local.set 52 + i32.const 0 + i64.load offset=53 align=1 + local.set 53 + i32.const 0 + i64.load offset=54 align=1 + local.set 54 + i32.const 0 + i64.load offset=55 align=1 + local.set 55 + i32.const 0 + i64.load offset=56 align=1 + local.set 56 + i32.const 0 + i64.load offset=57 align=1 + local.set 57 + i32.const 0 + i64.load offset=58 align=1 + local.set 58 + i32.const 0 + i64.load offset=59 align=1 + local.set 59 + i32.const 0 + i64.load offset=60 align=1 + local.set 60 + i32.const 0 + i64.load offset=61 align=1 + local.set 61 + i32.const 0 + i64.load offset=62 align=1 + local.set 62 + i32.const 0 + i64.load offset=63 align=1 + local.set 63 + i32.const 0 + i64.load offset=64 align=1 + local.set 64 + i32.const 0 + i64.load offset=65 align=1 + local.set 65 + i32.const 0 + i64.load offset=66 align=1 + local.set 66 + i32.const 0 + i64.load offset=67 align=1 + local.set 67 + i32.const 0 + i64.load offset=68 align=1 + local.set 68 + i32.const 0 + i64.load offset=69 align=1 + local.set 69 + i32.const 0 + i64.load offset=70 align=1 + local.set 70 + i32.const 0 + i64.load offset=71 align=1 + local.set 71 + i32.const 0 + i64.load offset=72 align=1 + local.set 72 + i32.const 0 + i64.load offset=73 align=1 + local.set 73 + i32.const 0 + i64.load offset=74 align=1 + local.set 74 + i32.const 0 + i64.load offset=75 align=1 + local.set 75 + i32.const 0 + i64.load offset=76 align=1 + local.set 76 + i32.const 0 + i64.load offset=77 align=1 + local.set 77 + i32.const 0 + i64.load offset=78 align=1 + local.set 78 + i32.const 0 + i64.load offset=79 align=1 + local.set 79 + i32.const 0 + i64.load offset=80 align=1 + local.set 80 + i32.const 0 + i64.load offset=81 align=1 + local.set 81 + i32.const 0 + i64.load offset=82 align=1 + local.set 82 + i32.const 0 + i64.load offset=83 align=1 + local.set 83 + i32.const 0 + i64.load offset=84 align=1 + local.set 84 + i32.const 0 + i64.load offset=85 align=1 + local.set 85 + i32.const 0 + i64.load offset=86 align=1 + local.set 86 + i32.const 0 + i64.load offset=87 align=1 + local.set 87 + i32.const 0 + i64.load offset=88 align=1 + local.set 88 + i32.const 0 + i64.load offset=89 align=1 + local.set 89 + i32.const 0 + i64.load offset=90 align=1 + local.set 90 + i32.const 0 + i64.load offset=91 align=1 + local.set 91 + i32.const 0 + i64.load offset=92 align=1 + local.set 92 + i32.const 0 + i64.load offset=93 align=1 + local.set 93 + i32.const 0 + i64.load offset=94 align=1 + local.set 94 + i32.const 0 + i64.load offset=95 align=1 + local.set 95 + i32.const 0 + i64.load offset=96 align=1 + local.set 96 + i32.const 0 + i64.load offset=97 align=1 + local.set 97 + i32.const 0 + i64.load offset=98 align=1 + local.set 98 + i32.const 0 + i64.load offset=99 align=1 + local.set 99 + i32.const 0 + i64.load offset=100 align=1 + local.set 100 + i32.const 0 + i64.load offset=101 align=1 + local.set 101 + i32.const 0 + i64.load offset=102 align=1 + local.set 102 + i32.const 0 + i64.load offset=103 align=1 + local.set 103 + i32.const 0 + i64.load offset=104 align=1 + local.set 104 + i32.const 0 + i64.load offset=105 align=1 + local.set 105 + i32.const 0 + i64.load offset=106 align=1 + local.set 106 + i32.const 0 + i64.load offset=107 align=1 + local.set 107 + i32.const 0 + i64.load offset=108 align=1 + local.set 108 + i32.const 0 + i64.load offset=109 align=1 + local.set 109 + i32.const 0 + i64.load offset=110 align=1 + local.set 110 + i32.const 0 + i64.load offset=111 align=1 + local.set 111 + i32.const 0 + i64.load offset=112 align=1 + local.set 112 + i32.const 0 + i64.load offset=113 align=1 + local.set 113 + i32.const 0 + i64.load offset=114 align=1 + local.set 114 + i32.const 0 + i64.load offset=115 align=1 + local.set 115 + i32.const 0 + i64.load offset=116 align=1 + local.set 116 + i32.const 0 + i64.load offset=117 align=1 + local.set 117 + i32.const 0 + i64.load offset=118 align=1 + local.set 118 + i32.const 0 + i64.load offset=119 align=1 + local.set 119 + i32.const 0 + i64.load offset=120 align=1 + local.set 120 + i32.const 0 + i64.load offset=121 align=1 + local.set 121 + i32.const 0 + i64.load offset=122 align=1 + local.set 122 + i32.const 0 + i64.load offset=123 align=1 + local.set 123 + i32.const 0 + i64.load offset=124 align=1 + local.set 124 + i32.const 0 + i64.load offset=125 align=1 + local.set 125 + i32.const 0 + i64.load offset=126 align=1 + local.set 126 + i32.const 0 + i64.load offset=127 align=1 + local.set 127 + i32.const 0 + i64.load offset=128 align=1 + local.set 128 + i32.const 0 + i64.load offset=129 align=1 + local.set 129 + i32.const 0 + i64.load offset=130 align=1 + local.set 130 + i32.const 0 + i64.load offset=131 align=1 + local.set 131 + i32.const 0 + i64.load offset=132 align=1 + local.set 132 + i32.const 0 + i64.load offset=133 align=1 + local.set 133 + i32.const 0 + i64.load offset=134 align=1 + local.set 134 + i32.const 0 + i64.load offset=135 align=1 + local.set 135 + i32.const 0 + i64.load offset=136 align=1 + local.set 136 + i32.const 0 + i64.load offset=137 align=1 + local.set 137 + i32.const 0 + i64.load offset=138 align=1 + local.set 138 + i32.const 0 + i64.load offset=139 align=1 + local.set 139 + i32.const 0 + i64.load offset=140 align=1 + local.set 140 + i32.const 0 + i64.load offset=141 align=1 + local.set 141 + i32.const 0 + i64.load offset=142 align=1 + local.set 142 + i32.const 0 + i64.load offset=143 align=1 + local.set 143 + i32.const 0 + i64.load offset=144 align=1 + local.set 144 + i32.const 0 + i64.load offset=145 align=1 + local.set 145 + i32.const 0 + i64.load offset=146 align=1 + local.set 146 + i32.const 0 + i64.load offset=147 align=1 + local.set 147 + i32.const 0 + i64.load offset=148 align=1 + local.set 148 + i32.const 0 + i64.load offset=149 align=1 + local.set 149 + i32.const 0 + i64.load offset=150 align=1 + local.set 150 + i32.const 0 + i64.load offset=151 align=1 + local.set 151 + i32.const 0 + i64.load offset=152 align=1 + local.set 152 + i32.const 0 + i64.load offset=153 align=1 + local.set 153 + i32.const 0 + i64.load offset=154 align=1 + local.set 154 + i32.const 0 + i64.load offset=155 align=1 + local.set 155 + i32.const 0 + i64.load offset=156 align=1 + local.set 156 + i32.const 0 + i64.load offset=157 align=1 + local.set 157 + i32.const 0 + i64.load offset=158 align=1 + local.set 158 + i32.const 0 + i64.load offset=159 align=1 + local.set 159 + i32.const 0 + i64.load offset=160 align=1 + local.set 160 + i32.const 0 + i64.load offset=161 align=1 + local.set 161 + i32.const 0 + i64.load offset=162 align=1 + local.set 162 + i32.const 0 + i64.load offset=163 align=1 + local.set 163 + i32.const 0 + i64.load offset=164 align=1 + local.set 164 + i32.const 0 + i64.load offset=165 align=1 + local.set 165 + i32.const 0 + i64.load offset=166 align=1 + local.set 166 + i32.const 0 + i64.load offset=167 align=1 + local.set 167 + i32.const 0 + i64.load offset=168 align=1 + local.set 168 + i32.const 0 + i64.load offset=169 align=1 + local.set 169 + i32.const 0 + i64.load offset=170 align=1 + local.set 170 + i32.const 0 + i64.load offset=171 align=1 + local.set 171 + i32.const 0 + i64.load offset=172 align=1 + local.set 172 + i32.const 0 + i64.load offset=173 align=1 + local.set 173 + i32.const 0 + i64.load offset=174 align=1 + local.set 174 + i32.const 0 + i64.load offset=175 align=1 + local.set 175 + i32.const 0 + i64.load offset=176 align=1 + local.set 176 + i32.const 0 + i64.load offset=177 align=1 + local.set 177 + i32.const 0 + i64.load offset=178 align=1 + local.set 178 + i32.const 0 + i64.load offset=179 align=1 + local.set 179 + i32.const 0 + i64.load offset=180 align=1 + local.set 180 + i32.const 0 + i64.load offset=181 align=1 + local.set 181 + i32.const 0 + i64.load offset=182 align=1 + local.set 182 + i32.const 0 + i64.load offset=183 align=1 + local.set 183 + i32.const 0 + i64.load offset=184 align=1 + local.set 184 + i32.const 0 + i64.load offset=185 align=1 + local.set 185 + i32.const 0 + i64.load offset=186 align=1 + local.set 186 + i32.const 0 + i64.load offset=187 align=1 + local.set 187 + i32.const 0 + i64.load offset=188 align=1 + local.set 188 + i32.const 0 + i64.load offset=189 align=1 + local.set 189 + i32.const 0 + i64.load offset=190 align=1 + local.set 190 + i32.const 0 + i64.load offset=191 align=1 + local.set 191 + i32.const 0 + i64.load offset=192 align=1 + local.set 192 + i32.const 0 + i64.load offset=193 align=1 + local.set 193 + i32.const 0 + i64.load offset=194 align=1 + local.set 194 + i32.const 0 + i64.load offset=195 align=1 + local.set 195 + i32.const 0 + i64.load offset=196 align=1 + local.set 196 + i32.const 0 + i64.load offset=197 align=1 + local.set 197 + i32.const 0 + i64.load offset=198 align=1 + local.set 198 + i32.const 0 + i64.load offset=199 align=1 + local.set 199 + i32.const 0 + i64.load offset=200 align=1 + local.set 200 + i32.const 0 + i64.load offset=201 align=1 + local.set 201 + i32.const 0 + i64.load offset=202 align=1 + local.set 202 + i32.const 0 + i64.load offset=203 align=1 + local.set 203 + i32.const 0 + i64.load offset=204 align=1 + local.set 204 + i32.const 0 + i64.load offset=205 align=1 + local.set 205 + i32.const 0 + i64.load offset=206 align=1 + local.set 206 + i32.const 0 + i64.load offset=207 align=1 + local.set 207 + i32.const 0 + i64.load offset=208 align=1 + local.set 208 + i32.const 0 + i64.load offset=209 align=1 + local.set 209 + i32.const 0 + i64.load offset=210 align=1 + local.set 210 + i32.const 0 + i64.load offset=211 align=1 + local.set 211 + i32.const 0 + i64.load offset=212 align=1 + local.set 212 + i32.const 0 + i64.load offset=213 align=1 + local.set 213 + i32.const 0 + i64.load offset=214 align=1 + local.set 214 + i32.const 0 + i64.load offset=215 align=1 + local.set 215 + i32.const 0 + i64.load offset=216 align=1 + local.set 216 + i32.const 0 + i64.load offset=217 align=1 + local.set 217 + i32.const 0 + i64.load offset=218 align=1 + local.set 218 + i32.const 0 + i64.load offset=219 align=1 + local.set 219 + i32.const 0 + i64.load offset=220 align=1 + local.set 220 + i32.const 0 + i64.load offset=221 align=1 + local.set 221 + i32.const 0 + i64.load offset=222 align=1 + local.set 222 + i32.const 0 + i64.load offset=223 align=1 + local.set 223 + i32.const 0 + i64.load offset=224 align=1 + local.set 224 + i32.const 0 + i64.load offset=225 align=1 + local.set 225 + i32.const 0 + i64.load offset=226 align=1 + local.set 226 + i32.const 0 + i64.load offset=227 align=1 + local.set 227 + i32.const 0 + i64.load offset=228 align=1 + local.set 228 + i32.const 0 + i64.load offset=229 align=1 + local.set 229 + i32.const 0 + i64.load offset=230 align=1 + local.set 230 + i32.const 0 + i64.load offset=231 align=1 + local.set 231 + i32.const 0 + i64.load offset=232 align=1 + local.set 232 + i32.const 0 + i64.load offset=233 align=1 + local.set 233 + i32.const 0 + i64.load offset=234 align=1 + local.set 234 + i32.const 0 + i64.load offset=235 align=1 + local.set 235 + i32.const 0 + i64.load offset=236 align=1 + local.set 236 + i32.const 0 + i64.load offset=237 align=1 + local.set 237 + i32.const 0 + i64.load offset=238 align=1 + local.set 238 + i32.const 0 + i64.load offset=239 align=1 + local.set 239 + i32.const 0 + i64.load offset=240 align=1 + local.set 240 + i32.const 0 + i64.load offset=241 align=1 + local.set 241 + i32.const 0 + i64.load offset=242 align=1 + local.set 242 + i32.const 0 + i64.load offset=243 align=1 + local.set 243 + i32.const 0 + i64.load offset=244 align=1 + local.set 244 + i32.const 0 + i64.load offset=245 align=1 + local.set 245 + i32.const 0 + i64.load offset=246 align=1 + local.set 246 + i32.const 0 + i64.load offset=247 align=1 + local.set 247 + i32.const 0 + i64.load offset=248 align=1 + local.set 248 + i32.const 0 + i64.load offset=249 align=1 + local.set 249 + i32.const 0 + i64.load offset=250 align=1 + local.set 250 + i32.const 0 + i64.load offset=251 align=1 + local.set 251 + i32.const 0 + i64.load offset=252 align=1 + local.set 252 + i32.const 0 + i64.load offset=253 align=1 + local.set 253 + i32.const 0 + i64.load offset=254 align=1 + local.set 254 + i32.const 0 + i64.load offset=255 align=1 + local.set 255 + i32.const 0 + i64.load offset=256 align=1 + local.set 256 + i32.const 0 + i64.load offset=257 align=1 + local.set 257 + i32.const 0 + i64.load offset=258 align=1 + local.set 258 + i32.const 0 + i64.load offset=259 align=1 + local.set 259 + i32.const 0 + i64.load offset=260 align=1 + local.set 260 + i32.const 0 + i64.load offset=261 align=1 + local.set 261 + i32.const 0 + i64.load offset=262 align=1 + local.set 262 + i32.const 0 + i64.load offset=263 align=1 + local.set 263 + i32.const 0 + i64.load offset=264 align=1 + local.set 264 + i32.const 0 + i64.load offset=265 align=1 + local.set 265 + i32.const 0 + i64.load offset=266 align=1 + local.set 266 + i32.const 0 + i64.load offset=267 align=1 + local.set 267 + i32.const 0 + i64.load offset=268 align=1 + local.set 268 + i32.const 0 + i64.load offset=269 align=1 + local.set 269 + i32.const 0 + i64.load offset=270 align=1 + local.set 270 + i32.const 0 + i64.load offset=271 align=1 + local.set 271 + i32.const 0 + i64.load offset=272 align=1 + local.set 272 + i32.const 0 + i64.load offset=273 align=1 + local.set 273 + i32.const 0 + i64.load offset=274 align=1 + local.set 274 + i32.const 0 + i64.load offset=275 align=1 + local.set 275 + i32.const 0 + i64.load offset=276 align=1 + local.set 276 + i32.const 0 + i64.load offset=277 align=1 + local.set 277 + i32.const 0 + i64.load offset=278 align=1 + local.set 278 + i32.const 0 + i64.load offset=279 align=1 + local.set 279 + i32.const 0 + i64.load offset=280 align=1 + local.set 280 + i32.const 0 + i64.load offset=281 align=1 + local.set 281 + i32.const 0 + i64.load offset=282 align=1 + local.set 282 + i32.const 0 + i64.load offset=283 align=1 + local.set 283 + i32.const 0 + i64.load offset=284 align=1 + local.set 284 + i32.const 0 + i64.load offset=285 align=1 + local.set 285 + i32.const 0 + i64.load offset=286 align=1 + local.set 286 + i32.const 0 + i64.load offset=287 align=1 + local.set 287 + i32.const 0 + i64.load offset=288 align=1 + local.set 288 + i32.const 0 + i64.load offset=289 align=1 + local.set 289 + i32.const 0 + i64.load offset=290 align=1 + local.set 290 + i32.const 0 + i64.load offset=291 align=1 + local.set 291 + i32.const 0 + i64.load offset=292 align=1 + local.set 292 + i32.const 0 + i64.load offset=293 align=1 + local.set 293 + i32.const 0 + i64.load offset=294 align=1 + local.set 294 + i32.const 0 + i64.load offset=295 align=1 + local.set 295 + i32.const 0 + i64.load offset=296 align=1 + local.set 296 + i32.const 0 + i64.load offset=297 align=1 + local.set 297 + i32.const 0 + i64.load offset=298 align=1 + local.set 298 + i32.const 0 + i64.load offset=299 align=1 + local.set 299 + i32.const 0 + i64.load offset=300 align=1 + local.set 300 + i32.const 0 + i64.load offset=301 align=1 + local.set 301 + i32.const 0 + i64.load offset=302 align=1 + local.set 302 + i32.const 0 + i64.load offset=303 align=1 + local.set 303 + i32.const 0 + i64.load offset=304 align=1 + local.set 304 + i32.const 0 + i64.load offset=305 align=1 + local.set 305 + i32.const 0 + i64.load offset=306 align=1 + local.set 306 + i32.const 0 + i64.load offset=307 align=1 + local.set 307 + i32.const 0 + i64.load offset=308 align=1 + local.set 308 + i32.const 0 + i64.load offset=309 align=1 + local.set 309 + i32.const 0 + i64.load offset=310 align=1 + local.set 310 + i32.const 0 + i64.load offset=311 align=1 + local.set 311 + i32.const 0 + i64.load offset=312 align=1 + local.set 312 + i32.const 0 + i64.load offset=313 align=1 + local.set 313 + i32.const 0 + i64.load offset=314 align=1 + local.set 314 + i32.const 0 + i64.load offset=315 align=1 + local.set 315 + i32.const 0 + i64.load offset=316 align=1 + local.set 316 + i32.const 0 + i64.load offset=317 align=1 + local.set 317 + i32.const 0 + i64.load offset=318 align=1 + local.set 318 + i32.const 0 + i64.load offset=319 align=1 + local.set 319 + i32.const 0 + i64.load offset=320 align=1 + local.set 320 + i32.const 0 + i64.load offset=321 align=1 + local.set 321 + i32.const 0 + i64.load offset=322 align=1 + local.set 322 + i32.const 0 + i64.load offset=323 align=1 + local.set 323 + i32.const 0 + i64.load offset=324 align=1 + local.set 324 + i32.const 0 + i64.load offset=325 align=1 + local.set 325 + i32.const 0 + i64.load offset=326 align=1 + local.set 326 + i32.const 0 + i64.load offset=327 align=1 + local.set 327 + i32.const 0 + i64.load offset=328 align=1 + local.set 328 + i32.const 0 + i64.load offset=329 align=1 + local.set 329 + i32.const 0 + i64.load offset=330 align=1 + local.set 330 + i32.const 0 + i64.load offset=331 align=1 + local.set 331 + i32.const 0 + i64.load offset=332 align=1 + local.set 332 + i32.const 0 + i64.load offset=333 align=1 + local.set 333 + i32.const 0 + i64.load offset=334 align=1 + local.set 334 + i32.const 0 + i64.load offset=335 align=1 + local.set 335 + i32.const 0 + i64.load offset=336 align=1 + local.set 336 + i32.const 0 + i64.load offset=337 align=1 + local.set 337 + i32.const 0 + i64.load offset=338 align=1 + local.set 338 + i32.const 0 + i64.load offset=339 align=1 + local.set 339 + i32.const 0 + i64.load offset=340 align=1 + local.set 340 + i32.const 0 + i64.load offset=341 align=1 + local.set 341 + i32.const 0 + i64.load offset=342 align=1 + local.set 342 + i32.const 0 + i64.load offset=343 align=1 + local.set 343 + i32.const 0 + i64.load offset=344 align=1 + local.set 344 + i32.const 0 + i64.load offset=345 align=1 + local.set 345 + i32.const 0 + i64.load offset=346 align=1 + local.set 346 + i32.const 0 + i64.load offset=347 align=1 + local.set 347 + i32.const 0 + i64.load offset=348 align=1 + local.set 348 + i32.const 0 + i64.load offset=349 align=1 + local.set 349 + i32.const 0 + i64.load offset=350 align=1 + local.set 350 + i32.const 0 + i64.load offset=351 align=1 + local.set 351 + i32.const 0 + i64.load offset=352 align=1 + local.set 352 + i32.const 0 + i64.load offset=353 align=1 + local.set 353 + i32.const 0 + i64.load offset=354 align=1 + local.set 354 + i32.const 0 + i64.load offset=355 align=1 + local.set 355 + i32.const 0 + i64.load offset=356 align=1 + local.set 356 + i32.const 0 + i64.load offset=357 align=1 + local.set 357 + i32.const 0 + i64.load offset=358 align=1 + local.set 358 + i32.const 0 + i64.load offset=359 align=1 + local.set 359 + i32.const 0 + i64.load offset=360 align=1 + local.set 360 + i32.const 0 + i64.load offset=361 align=1 + local.set 361 + i32.const 0 + i64.load offset=362 align=1 + local.set 362 + i32.const 0 + i64.load offset=363 align=1 + local.set 363 + i32.const 0 + i64.load offset=364 align=1 + local.set 364 + i32.const 0 + i64.load offset=365 align=1 + local.set 365 + i32.const 0 + i64.load offset=366 align=1 + local.set 366 + i32.const 0 + i64.load offset=367 align=1 + local.set 367 + i32.const 0 + i64.load offset=368 align=1 + local.set 368 + i32.const 0 + i64.load offset=369 align=1 + local.set 369 + i32.const 0 + i64.load offset=370 align=1 + local.set 370 + i32.const 0 + i64.load offset=371 align=1 + local.set 371 + i32.const 0 + i64.load offset=372 align=1 + local.set 372 + i32.const 0 + i64.load offset=373 align=1 + local.set 373 + i32.const 0 + i64.load offset=374 align=1 + local.set 374 + i32.const 0 + i64.load offset=375 align=1 + local.set 375 + i32.const 0 + i64.load offset=376 align=1 + local.set 376 + i32.const 0 + i64.load offset=377 align=1 + local.set 377 + i32.const 0 + i64.load offset=378 align=1 + local.set 378 + i32.const 0 + i64.load offset=379 align=1 + local.set 379 + i32.const 0 + i64.load offset=380 align=1 + local.set 380 + i32.const 0 + i64.load offset=381 align=1 + local.set 381 + i32.const 0 + i64.load offset=382 align=1 + local.set 382 + i32.const 0 + i64.load offset=383 align=1 + local.set 383 + i32.const 0 + i64.load offset=384 align=1 + local.set 384 + i32.const 0 + i64.load offset=385 align=1 + local.set 385 + i32.const 0 + i64.load offset=386 align=1 + local.set 386 + i32.const 0 + i64.load offset=387 align=1 + local.set 387 + i32.const 0 + i64.load offset=388 align=1 + local.set 388 + i32.const 0 + i64.load offset=389 align=1 + local.set 389 + i32.const 0 + i64.load offset=390 align=1 + local.set 390 + i32.const 0 + i64.load offset=391 align=1 + local.set 391 + i32.const 0 + i64.load offset=392 align=1 + local.set 392 + i32.const 0 + i64.load offset=393 align=1 + local.set 393 + i32.const 0 + i64.load offset=394 align=1 + local.set 394 + i32.const 0 + i64.load offset=395 align=1 + local.set 395 + i32.const 0 + i64.load offset=396 align=1 + local.set 396 + i32.const 0 + i64.load offset=397 align=1 + local.set 397 + i32.const 0 + i64.load offset=398 align=1 + local.set 398 + i32.const 0 + i64.load offset=399 align=1 + local.set 399 + i32.const 0 + i64.load offset=400 align=1 + local.set 400 + i32.const 0 + i64.load offset=401 align=1 + local.set 401 + i32.const 0 + i64.load offset=402 align=1 + local.set 402 + i32.const 0 + i64.load offset=403 align=1 + local.set 403 + i32.const 0 + i64.load offset=404 align=1 + local.set 404 + i32.const 0 + i64.load offset=405 align=1 + local.set 405 + i32.const 0 + i64.load offset=406 align=1 + local.set 406 + i32.const 0 + i64.load offset=407 align=1 + local.set 407 + i32.const 0 + i64.load offset=408 align=1 + local.set 408 + i32.const 0 + i64.load offset=409 align=1 + local.set 409 + i32.const 0 + i64.load offset=410 align=1 + local.set 410 + i32.const 0 + i64.load offset=411 align=1 + local.set 411 + i32.const 0 + i64.load offset=412 align=1 + local.set 412 + i32.const 0 + i64.load offset=413 align=1 + local.set 413 + i32.const 0 + i64.load offset=414 align=1 + local.set 414 + i32.const 0 + i64.load offset=415 align=1 + local.set 415 + i32.const 0 + i64.load offset=416 align=1 + local.set 416 + i32.const 0 + i64.load offset=417 align=1 + local.set 417 + i32.const 0 + i64.load offset=418 align=1 + local.set 418 + i32.const 0 + i64.load offset=419 align=1 + local.set 419 + i32.const 0 + i64.load offset=420 align=1 + local.set 420 + i32.const 0 + i64.load offset=421 align=1 + local.set 421 + i32.const 0 + i64.load offset=422 align=1 + local.set 422 + i32.const 0 + i64.load offset=423 align=1 + local.set 423 + i32.const 0 + i64.load offset=424 align=1 + local.set 424 + i32.const 0 + i64.load offset=425 align=1 + local.set 425 + i32.const 0 + i64.load offset=426 align=1 + local.set 426 + i32.const 0 + i64.load offset=427 align=1 + local.set 427 + i32.const 0 + i64.load offset=428 align=1 + local.set 428 + i32.const 0 + i64.load offset=429 align=1 + local.set 429 + i32.const 0 + i64.load offset=430 align=1 + local.set 430 + i32.const 0 + i64.load offset=431 align=1 + local.set 431 + i32.const 0 + i64.load offset=432 align=1 + local.set 432 + i32.const 0 + i64.load offset=433 align=1 + local.set 433 + i32.const 0 + i64.load offset=434 align=1 + local.set 434 + i32.const 0 + i64.load offset=435 align=1 + local.set 435 + i32.const 0 + i64.load offset=436 align=1 + local.set 436 + i32.const 0 + i64.load offset=437 align=1 + local.set 437 + i32.const 0 + i64.load offset=438 align=1 + local.set 438 + i32.const 0 + i64.load offset=439 align=1 + local.set 439 + i32.const 0 + i64.load offset=440 align=1 + local.set 440 + i32.const 0 + i64.load offset=441 align=1 + local.set 441 + i32.const 0 + i64.load offset=442 align=1 + local.set 442 + i32.const 0 + i64.load offset=443 align=1 + local.set 443 + i32.const 0 + i64.load offset=444 align=1 + local.set 444 + i32.const 0 + i64.load offset=445 align=1 + local.set 445 + i32.const 0 + i64.load offset=446 align=1 + local.set 446 + i32.const 0 + i64.load offset=447 align=1 + local.set 447 + i32.const 0 + i64.load offset=448 align=1 + local.set 448 + i32.const 0 + i64.load offset=449 align=1 + local.set 449 + i32.const 0 + i64.load offset=450 align=1 + local.set 450 + i32.const 0 + i64.load offset=451 align=1 + local.set 451 + i32.const 0 + i64.load offset=452 align=1 + local.set 452 + i32.const 0 + i64.load offset=453 align=1 + local.set 453 + i32.const 0 + i64.load offset=454 align=1 + local.set 454 + i32.const 0 + i64.load offset=455 align=1 + local.set 455 + i32.const 0 + i64.load offset=456 align=1 + local.set 456 + i32.const 0 + i64.load offset=457 align=1 + local.set 457 + i32.const 0 + i64.load offset=458 align=1 + local.set 458 + i32.const 0 + i64.load offset=459 align=1 + local.set 459 + i32.const 0 + i64.load offset=460 align=1 + local.set 460 + i32.const 0 + i64.load offset=461 align=1 + local.set 461 + i32.const 0 + i64.load offset=462 align=1 + local.set 462 + i32.const 0 + i64.load offset=463 align=1 + local.set 463 + i32.const 0 + i64.load offset=464 align=1 + local.set 464 + i32.const 0 + i64.load offset=465 align=1 + local.set 465 + i32.const 0 + i64.load offset=466 align=1 + local.set 466 + i32.const 0 + i64.load offset=467 align=1 + local.set 467 + i32.const 0 + i64.load offset=468 align=1 + local.set 468 + i32.const 0 + i64.load offset=469 align=1 + local.set 469 + i32.const 0 + i64.load offset=470 align=1 + local.set 470 + i32.const 0 + i64.load offset=471 align=1 + local.set 471 + i32.const 0 + i64.load offset=472 align=1 + local.set 472 + i32.const 0 + i64.load offset=473 align=1 + local.set 473 + i32.const 0 + i64.load offset=474 align=1 + local.set 474 + i32.const 0 + i64.load offset=475 align=1 + local.set 475 + i32.const 0 + i64.load offset=476 align=1 + local.set 476 + i32.const 0 + i64.load offset=477 align=1 + local.set 477 + i32.const 0 + i64.load offset=478 align=1 + local.set 478 + i32.const 0 + i64.load offset=479 align=1 + local.set 479 + i32.const 0 + i64.load offset=480 align=1 + local.set 480 + i32.const 0 + i64.load offset=481 align=1 + local.set 481 + i32.const 0 + i64.load offset=482 align=1 + local.set 482 + i32.const 0 + i64.load offset=483 align=1 + local.set 483 + i32.const 0 + i64.load offset=484 align=1 + local.set 484 + i32.const 0 + i64.load offset=485 align=1 + local.set 485 + i32.const 0 + i64.load offset=486 align=1 + local.set 486 + i32.const 0 + i64.load offset=487 align=1 + local.set 487 + i32.const 0 + i64.load offset=488 align=1 + local.set 488 + i32.const 0 + i64.load offset=489 align=1 + local.set 489 + i32.const 0 + i64.load offset=490 align=1 + local.set 490 + i32.const 0 + i64.load offset=491 align=1 + local.set 491 + i32.const 0 + i64.load offset=492 align=1 + local.set 492 + i32.const 0 + i64.load offset=493 align=1 + local.set 493 + i32.const 0 + i64.load offset=494 align=1 + local.set 494 + i32.const 0 + i64.load offset=495 align=1 + local.set 495 + i32.const 0 + i64.load offset=496 align=1 + local.set 496 + i32.const 0 + i64.load offset=497 align=1 + local.set 497 + i32.const 0 + i64.load offset=498 align=1 + local.set 498 + i32.const 0 + i64.load offset=499 align=1 + local.set 499 + i32.const 0 + i64.load offset=500 align=1 + local.set 500 + i32.const 0 + i64.load offset=501 align=1 + local.set 501 + i32.const 0 + i64.load offset=502 align=1 + local.set 502 + i32.const 0 + i64.load offset=503 align=1 + local.set 503 + i32.const 0 + i64.load offset=504 align=1 + local.set 504 + i32.const 0 + i64.load offset=505 align=1 + local.set 505 + i32.const 0 + i64.load offset=506 align=1 + local.set 506 + i32.const 0 + i64.load offset=507 align=1 + local.set 507 + i32.const 0 + i64.load offset=508 align=1 + local.set 508 + i32.const 0 + i64.load offset=509 align=1 + local.set 509 + i32.const 0 + i64.load offset=510 align=1 + local.set 510 + i32.const 0 + i64.load offset=511 align=1 + local.set 511 + i32.const 0 + i64.load offset=512 align=1 + local.set 512 + i32.const 0 + i64.load offset=513 align=1 + local.set 513 + i32.const 0 + i64.load offset=514 align=1 + local.set 514 + i32.const 0 + i64.load offset=515 align=1 + local.set 515 + i32.const 0 + i64.load offset=516 align=1 + local.set 516 + i32.const 0 + i64.load offset=517 align=1 + local.set 517 + i32.const 0 + i64.load offset=518 align=1 + local.set 518 + i32.const 0 + i64.load offset=519 align=1 + local.set 519 + i32.const 0 + i64.load offset=520 align=1 + local.set 520 + i32.const 0 + i64.load offset=521 align=1 + local.set 521 + i32.const 0 + i64.load offset=522 align=1 + local.set 522 + i32.const 0 + i64.load offset=523 align=1 + local.set 523 + i32.const 0 + i64.load offset=524 align=1 + local.set 524 + i32.const 0 + i64.load offset=525 align=1 + local.set 525 + i32.const 0 + i64.load offset=526 align=1 + local.set 526 + i32.const 0 + i64.load offset=527 align=1 + local.set 527 + i32.const 0 + i64.load offset=528 align=1 + local.set 528 + i32.const 0 + i64.load offset=529 align=1 + local.set 529 + i32.const 0 + i64.load offset=530 align=1 + local.set 530 + i32.const 0 + i64.load offset=531 align=1 + local.set 531 + i32.const 0 + i64.load offset=532 align=1 + local.set 532 + i32.const 0 + i64.load offset=533 align=1 + local.set 533 + i32.const 0 + i64.load offset=534 align=1 + local.set 534 + i32.const 0 + i64.load offset=535 align=1 + local.set 535 + i32.const 0 + i64.load offset=536 align=1 + local.set 536 + i32.const 0 + i64.load offset=537 align=1 + local.set 537 + i32.const 0 + i64.load offset=538 align=1 + local.set 538 + i32.const 0 + i64.load offset=539 align=1 + local.set 539 + i32.const 0 + i64.load offset=540 align=1 + local.set 540 + i32.const 0 + i64.load offset=541 align=1 + local.set 541 + i32.const 0 + i64.load offset=542 align=1 + local.set 542 + i32.const 0 + i64.load offset=543 align=1 + local.set 543 + i32.const 0 + i64.load offset=544 align=1 + local.set 544 + i32.const 0 + i64.load offset=545 align=1 + local.set 545 + i32.const 0 + i64.load offset=546 align=1 + local.set 546 + i32.const 0 + i64.load offset=547 align=1 + local.set 547 + i32.const 0 + i64.load offset=548 align=1 + local.set 548 + i32.const 0 + i64.load offset=549 align=1 + local.set 549 + i32.const 0 + i64.load offset=550 align=1 + local.set 550 + i32.const 0 + i64.load offset=551 align=1 + local.set 551 + i32.const 0 + i64.load offset=552 align=1 + local.set 552 + i32.const 0 + i64.load offset=553 align=1 + local.set 553 + i32.const 0 + i64.load offset=554 align=1 + local.set 554 + i32.const 0 + i64.load offset=555 align=1 + local.set 555 + i32.const 0 + i64.load offset=556 align=1 + local.set 556 + i32.const 0 + i64.load offset=557 align=1 + local.set 557 + i32.const 0 + i64.load offset=558 align=1 + local.set 558 + i32.const 0 + i64.load offset=559 align=1 + local.set 559 + i32.const 0 + i64.load offset=560 align=1 + local.set 560 + i32.const 0 + i64.load offset=561 align=1 + local.set 561 + i32.const 0 + i64.load offset=562 align=1 + local.set 562 + i32.const 0 + i64.load offset=563 align=1 + local.set 563 + i32.const 0 + i64.load offset=564 align=1 + local.set 564 + i32.const 0 + i64.load offset=565 align=1 + local.set 565 + i32.const 0 + i64.load offset=566 align=1 + local.set 566 + i32.const 0 + i64.load offset=567 align=1 + local.set 567 + i32.const 0 + i64.load offset=568 align=1 + local.set 568 + i32.const 0 + i64.load offset=569 align=1 + local.set 569 + i32.const 0 + i64.load offset=570 align=1 + local.set 570 + i32.const 0 + i64.load offset=571 align=1 + local.set 571 + i32.const 0 + i64.load offset=572 align=1 + local.set 572 + i32.const 0 + i64.load offset=573 align=1 + local.set 573 + i32.const 0 + i64.load offset=574 align=1 + local.set 574 + i32.const 0 + i64.load offset=575 align=1 + local.set 575 + i32.const 0 + i64.load offset=576 align=1 + local.set 576 + i32.const 0 + i64.load offset=577 align=1 + local.set 577 + i32.const 0 + i64.load offset=578 align=1 + local.set 578 + i32.const 0 + i64.load offset=579 align=1 + local.set 579 + i32.const 0 + i64.load offset=580 align=1 + local.set 580 + i32.const 0 + i64.load offset=581 align=1 + local.set 581 + i32.const 0 + i64.load offset=582 align=1 + local.set 582 + i32.const 0 + i64.load offset=583 align=1 + local.set 583 + i32.const 0 + i64.load offset=584 align=1 + local.set 584 + i32.const 0 + i64.load offset=585 align=1 + local.set 585 + i32.const 0 + i64.load offset=586 align=1 + local.set 586 + i32.const 0 + i64.load offset=587 align=1 + local.set 587 + i32.const 0 + i64.load offset=588 align=1 + local.set 588 + i32.const 0 + i64.load offset=589 align=1 + local.set 589 + i32.const 0 + i64.load offset=590 align=1 + local.set 590 + i32.const 0 + i64.load offset=591 align=1 + local.set 591 + i32.const 0 + i64.load offset=592 align=1 + local.set 592 + i32.const 0 + i64.load offset=593 align=1 + local.set 593 + i32.const 0 + i64.load offset=594 align=1 + local.set 594 + i32.const 0 + i64.load offset=595 align=1 + local.set 595 + i32.const 0 + i64.load offset=596 align=1 + local.set 596 + i32.const 0 + i64.load offset=597 align=1 + local.set 597 + i32.const 0 + i64.load offset=598 align=1 + local.set 598 + i32.const 0 + i64.load offset=599 align=1 + local.set 599 + i32.const 0 + i64.load offset=600 align=1 + local.set 600 + i32.const 0 + i64.load offset=601 align=1 + local.set 601 + i32.const 0 + i64.load offset=602 align=1 + local.set 602 + i32.const 0 + i64.load offset=603 align=1 + local.set 603 + i32.const 0 + i64.load offset=604 align=1 + local.set 604 + i32.const 0 + i64.load offset=605 align=1 + local.set 605 + i32.const 0 + i64.load offset=606 align=1 + local.set 606 + i32.const 0 + i64.load offset=607 align=1 + local.set 607 + i32.const 0 + i64.load offset=608 align=1 + local.set 608 + i32.const 0 + i64.load offset=609 align=1 + local.set 609 + i32.const 0 + i64.load offset=610 align=1 + local.set 610 + i32.const 0 + i64.load offset=611 align=1 + local.set 611 + i32.const 0 + i64.load offset=612 align=1 + local.set 612 + i32.const 0 + i64.load offset=613 align=1 + local.set 613 + i32.const 0 + i64.load offset=614 align=1 + local.set 614 + i32.const 0 + i64.load offset=615 align=1 + local.set 615 + i32.const 0 + i64.load offset=616 align=1 + local.set 616 + i32.const 0 + i64.load offset=617 align=1 + local.set 617 + i32.const 0 + i64.load offset=618 align=1 + local.set 618 + i32.const 0 + i64.load offset=619 align=1 + local.set 619 + i32.const 0 + i64.load offset=620 align=1 + local.set 620 + i32.const 0 + i64.load offset=621 align=1 + local.set 621 + i32.const 0 + i64.load offset=622 align=1 + local.set 622 + i32.const 0 + i64.load offset=623 align=1 + local.set 623 + i32.const 0 + i64.load offset=624 align=1 + local.set 624 + i32.const 0 + i64.load offset=625 align=1 + local.set 625 + i32.const 0 + i64.load offset=626 align=1 + local.set 626 + i32.const 0 + i64.load offset=627 align=1 + local.set 627 + i32.const 0 + i64.load offset=628 align=1 + local.set 628 + i32.const 0 + i64.load offset=629 align=1 + local.set 629 + i32.const 0 + i64.load offset=630 align=1 + local.set 630 + i32.const 0 + i64.load offset=631 align=1 + local.set 631 + i32.const 0 + i64.load offset=632 align=1 + local.set 632 + i32.const 0 + i64.load offset=633 align=1 + local.set 633 + i32.const 0 + i64.load offset=634 align=1 + local.set 634 + i32.const 0 + i64.load offset=635 align=1 + local.set 635 + i32.const 0 + i64.load offset=636 align=1 + local.set 636 + i32.const 0 + i64.load offset=637 align=1 + local.set 637 + i32.const 0 + i64.load offset=638 align=1 + local.set 638 + i32.const 0 + i64.load offset=639 align=1 + local.set 639 + i32.const 0 + i64.load offset=640 align=1 + local.set 640 + i32.const 0 + i64.load offset=641 align=1 + local.set 641 + i32.const 0 + i64.load offset=642 align=1 + local.set 642 + i32.const 0 + i64.load offset=643 align=1 + local.set 643 + i32.const 0 + i64.load offset=644 align=1 + local.set 644 + i32.const 0 + i64.load offset=645 align=1 + local.set 645 + i32.const 0 + i64.load offset=646 align=1 + local.set 646 + i32.const 0 + i64.load offset=647 align=1 + local.set 647 + i32.const 0 + i64.load offset=648 align=1 + local.set 648 + i32.const 0 + i64.load offset=649 align=1 + local.set 649 + i32.const 0 + i64.load offset=650 align=1 + local.set 650 + i32.const 0 + i64.load offset=651 align=1 + local.set 651 + i32.const 0 + i64.load offset=652 align=1 + local.set 652 + i32.const 0 + i64.load offset=653 align=1 + local.set 653 + i32.const 0 + i64.load offset=654 align=1 + local.set 654 + i32.const 0 + i64.load offset=655 align=1 + local.set 655 + i32.const 0 + i64.load offset=656 align=1 + local.set 656 + i32.const 0 + i64.load offset=657 align=1 + local.set 657 + i32.const 0 + i64.load offset=658 align=1 + local.set 658 + i32.const 0 + i64.load offset=659 align=1 + local.set 659 + i32.const 0 + i64.load offset=660 align=1 + local.set 660 + i32.const 0 + i64.load offset=661 align=1 + local.set 661 + i32.const 0 + i64.load offset=662 align=1 + local.set 662 + i32.const 0 + i64.load offset=663 align=1 + local.set 663 + i32.const 0 + i64.load offset=664 align=1 + local.set 664 + i32.const 0 + i64.load offset=665 align=1 + local.set 665 + i32.const 0 + i64.load offset=666 align=1 + local.set 666 + i32.const 0 + i64.load offset=667 align=1 + local.set 667 + i32.const 0 + i64.load offset=668 align=1 + local.set 668 + i32.const 0 + i64.load offset=669 align=1 + local.set 669 + i32.const 0 + i64.load offset=670 align=1 + local.set 670 + i32.const 0 + i64.load offset=671 align=1 + local.set 671 + i32.const 0 + i64.load offset=672 align=1 + local.set 672 + i32.const 0 + i64.load offset=673 align=1 + local.set 673 + i32.const 0 + i64.load offset=674 align=1 + local.set 674 + i32.const 0 + i64.load offset=675 align=1 + local.set 675 + i32.const 0 + i64.load offset=676 align=1 + local.set 676 + i32.const 0 + i64.load offset=677 align=1 + local.set 677 + i32.const 0 + i64.load offset=678 align=1 + local.set 678 + i32.const 0 + i64.load offset=679 align=1 + local.set 679 + i32.const 0 + i64.load offset=680 align=1 + local.set 680 + i32.const 0 + i64.load offset=681 align=1 + local.set 681 + i32.const 0 + i64.load offset=682 align=1 + local.set 682 + i32.const 0 + i64.load offset=683 align=1 + local.set 683 + i32.const 0 + i64.load offset=684 align=1 + local.set 684 + i32.const 0 + i64.load offset=685 align=1 + local.set 685 + i32.const 0 + i64.load offset=686 align=1 + local.set 686 + i32.const 0 + i64.load offset=687 align=1 + local.set 687 + i32.const 0 + i64.load offset=688 align=1 + local.set 688 + i32.const 0 + i64.load offset=689 align=1 + local.set 689 + i32.const 0 + i64.load offset=690 align=1 + local.set 690 + i32.const 0 + i64.load offset=691 align=1 + local.set 691 + i32.const 0 + i64.load offset=692 align=1 + local.set 692 + i32.const 0 + i64.load offset=693 align=1 + local.set 693 + i32.const 0 + i64.load offset=694 align=1 + local.set 694 + i32.const 0 + i64.load offset=695 align=1 + local.set 695 + i32.const 0 + i64.load offset=696 align=1 + local.set 696 + i32.const 0 + i64.load offset=697 align=1 + local.set 697 + i32.const 0 + i64.load offset=698 align=1 + local.set 698 + i32.const 0 + i64.load offset=699 align=1 + local.set 699 + i32.const 0 + i64.load offset=700 align=1 + local.set 700 + i32.const 0 + i64.load offset=701 align=1 + local.set 701 + i32.const 0 + i64.load offset=702 align=1 + local.set 702 + i32.const 0 + i64.load offset=703 align=1 + local.set 703 + i32.const 0 + i64.load offset=704 align=1 + local.set 704 + i32.const 0 + i64.load offset=705 align=1 + local.set 705 + i32.const 0 + i64.load offset=706 align=1 + local.set 706 + i32.const 0 + i64.load offset=707 align=1 + local.set 707 + i32.const 0 + i64.load offset=708 align=1 + local.set 708 + i32.const 0 + i64.load offset=709 align=1 + local.set 709 + i32.const 0 + i64.load offset=710 align=1 + local.set 710 + i32.const 0 + i64.load offset=711 align=1 + local.set 711 + i32.const 0 + i64.load offset=712 align=1 + local.set 712 + i32.const 0 + i64.load offset=713 align=1 + local.set 713 + i32.const 0 + i64.load offset=714 align=1 + local.set 714 + i32.const 0 + i64.load offset=715 align=1 + local.set 715 + i32.const 0 + i64.load offset=716 align=1 + local.set 716 + i32.const 0 + i64.load offset=717 align=1 + local.set 717 + i32.const 0 + i64.load offset=718 align=1 + local.set 718 + i32.const 0 + i64.load offset=719 align=1 + local.set 719 + i32.const 0 + i64.load offset=720 align=1 + local.set 720 + i32.const 0 + i64.load offset=721 align=1 + local.set 721 + i32.const 0 + i64.load offset=722 align=1 + local.set 722 + i32.const 0 + i64.load offset=723 align=1 + local.set 723 + i32.const 0 + i64.load offset=724 align=1 + local.set 724 + i32.const 0 + i64.load offset=725 align=1 + local.set 725 + i32.const 0 + i64.load offset=726 align=1 + local.set 726 + i32.const 0 + i64.load offset=727 align=1 + local.set 727 + i32.const 0 + i64.load offset=728 align=1 + local.set 728 + i32.const 0 + i64.load offset=729 align=1 + local.set 729 + i32.const 0 + i64.load offset=730 align=1 + local.set 730 + i32.const 0 + i64.load offset=731 align=1 + local.set 731 + i32.const 0 + i64.load offset=732 align=1 + local.set 732 + i32.const 0 + i64.load offset=733 align=1 + local.set 733 + i32.const 0 + i64.load offset=734 align=1 + local.set 734 + i32.const 0 + i64.load offset=735 align=1 + local.set 735 + i32.const 0 + i64.load offset=736 align=1 + local.set 736 + i32.const 0 + i64.load offset=737 align=1 + local.set 737 + i32.const 0 + i64.load offset=738 align=1 + local.set 738 + i32.const 0 + i64.load offset=739 align=1 + local.set 739 + i32.const 0 + i64.load offset=740 align=1 + local.set 740 + i32.const 0 + i64.load offset=741 align=1 + local.set 741 + i32.const 0 + i64.load offset=742 align=1 + local.set 742 + i32.const 0 + i64.load offset=743 align=1 + local.set 743 + i32.const 0 + i64.load offset=744 align=1 + local.set 744 + i32.const 0 + i64.load offset=745 align=1 + local.set 745 + i32.const 0 + i64.load offset=746 align=1 + local.set 746 + i32.const 0 + i64.load offset=747 align=1 + local.set 747 + i32.const 0 + i64.load offset=748 align=1 + local.set 748 + i32.const 0 + i64.load offset=749 align=1 + local.set 749 + i32.const 0 + i64.load offset=750 align=1 + local.set 750 + i32.const 0 + i64.load offset=751 align=1 + local.set 751 + i32.const 0 + i64.load offset=752 align=1 + local.set 752 + i32.const 0 + i64.load offset=753 align=1 + local.set 753 + i32.const 0 + i64.load offset=754 align=1 + local.set 754 + i32.const 0 + i64.load offset=755 align=1 + local.set 755 + i32.const 0 + i64.load offset=756 align=1 + local.set 756 + i32.const 0 + i64.load offset=757 align=1 + local.set 757 + i32.const 0 + i64.load offset=758 align=1 + local.set 758 + i32.const 0 + i64.load offset=759 align=1 + local.set 759 + i32.const 0 + i64.load offset=760 align=1 + local.set 760 + i32.const 0 + i64.load offset=761 align=1 + local.set 761 + i32.const 0 + i64.load offset=762 align=1 + local.set 762 + i32.const 0 + i64.load offset=763 align=1 + local.set 763 + i32.const 0 + i64.load offset=764 align=1 + local.set 764 + i32.const 0 + i64.load offset=765 align=1 + local.set 765 + i32.const 0 + i64.load offset=766 align=1 + local.set 766 + i32.const 0 + i64.load offset=767 align=1 + local.set 767 + i32.const 0 + i64.load offset=768 align=1 + local.set 768 + i32.const 0 + i64.load offset=769 align=1 + local.set 769 + i32.const 0 + i64.load offset=770 align=1 + local.set 770 + i32.const 0 + i64.load offset=771 align=1 + local.set 771 + i32.const 0 + i64.load offset=772 align=1 + local.set 772 + i32.const 0 + i64.load offset=773 align=1 + local.set 773 + i32.const 0 + i64.load offset=774 align=1 + local.set 774 + i32.const 0 + i64.load offset=775 align=1 + local.set 775 + i32.const 0 + i64.load offset=776 align=1 + local.set 776 + i32.const 0 + i64.load offset=777 align=1 + local.set 777 + i32.const 0 + i64.load offset=778 align=1 + local.set 778 + i32.const 0 + i64.load offset=779 align=1 + local.set 779 + i32.const 0 + i64.load offset=780 align=1 + local.set 780 + i32.const 0 + i64.load offset=781 align=1 + local.set 781 + i32.const 0 + i64.load offset=782 align=1 + local.set 782 + i32.const 0 + i64.load offset=783 align=1 + local.set 783 + i32.const 0 + i64.load offset=784 align=1 + local.set 784 + i32.const 0 + i64.load offset=785 align=1 + local.set 785 + i32.const 0 + i64.load offset=786 align=1 + local.set 786 + i32.const 0 + i64.load offset=787 align=1 + local.set 787 + i32.const 0 + i64.load offset=788 align=1 + local.set 788 + i32.const 0 + i64.load offset=789 align=1 + local.set 789 + i32.const 0 + i64.load offset=790 align=1 + local.set 790 + i32.const 0 + i64.load offset=791 align=1 + local.set 791 + i32.const 0 + i64.load offset=792 align=1 + local.set 792 + i32.const 0 + i64.load offset=793 align=1 + local.set 793 + i32.const 0 + i64.load offset=794 align=1 + local.set 794 + i32.const 0 + i64.load offset=795 align=1 + local.set 795 + i32.const 0 + i64.load offset=796 align=1 + local.set 796 + i32.const 0 + i64.load offset=797 align=1 + local.set 797 + i32.const 0 + i64.load offset=798 align=1 + local.set 798 + i32.const 0 + i64.load offset=799 align=1 + local.set 799 + i32.const 0 + i64.load offset=800 align=1 + local.set 800 + i32.const 0 + i64.load offset=801 align=1 + local.set 801 + i32.const 0 + i64.load offset=802 align=1 + local.set 802 + i32.const 0 + i64.load offset=803 align=1 + local.set 803 + i32.const 0 + i64.load offset=804 align=1 + local.set 804 + i32.const 0 + i64.load offset=805 align=1 + local.set 805 + i32.const 0 + i64.load offset=806 align=1 + local.set 806 + i32.const 0 + i64.load offset=807 align=1 + local.set 807 + i32.const 0 + i64.load offset=808 align=1 + local.set 808 + i32.const 0 + i64.load offset=809 align=1 + local.set 809 + i32.const 0 + i64.load offset=810 align=1 + local.set 810 + i32.const 0 + i64.load offset=811 align=1 + local.set 811 + i32.const 0 + i64.load offset=812 align=1 + local.set 812 + i32.const 0 + i64.load offset=813 align=1 + local.set 813 + i32.const 0 + i64.load offset=814 align=1 + local.set 814 + i32.const 0 + i64.load offset=815 align=1 + local.set 815 + i32.const 0 + i64.load offset=816 align=1 + local.set 816 + i32.const 0 + i64.load offset=817 align=1 + local.set 817 + i32.const 0 + i64.load offset=818 align=1 + local.set 818 + i32.const 0 + i64.load offset=819 align=1 + local.set 819 + i32.const 0 + i64.load offset=820 align=1 + local.set 820 + i32.const 0 + i64.load offset=821 align=1 + local.set 821 + i32.const 0 + i64.load offset=822 align=1 + local.set 822 + i32.const 0 + i64.load offset=823 align=1 + local.set 823 + i32.const 0 + i64.load offset=824 align=1 + local.set 824 + i32.const 0 + i64.load offset=825 align=1 + local.set 825 + i32.const 0 + i64.load offset=826 align=1 + local.set 826 + i32.const 0 + i64.load offset=827 align=1 + local.set 827 + i32.const 0 + i64.load offset=828 align=1 + local.set 828 + i32.const 0 + i64.load offset=829 align=1 + local.set 829 + i32.const 0 + i64.load offset=830 align=1 + local.set 830 + i32.const 0 + i64.load offset=831 align=1 + local.set 831 + i32.const 0 + i64.load offset=832 align=1 + local.set 832 + i32.const 0 + i64.load offset=833 align=1 + local.set 833 + i32.const 0 + i64.load offset=834 align=1 + local.set 834 + i32.const 0 + i64.load offset=835 align=1 + local.set 835 + i32.const 0 + i64.load offset=836 align=1 + local.set 836 + i32.const 0 + i64.load offset=837 align=1 + local.set 837 + i32.const 0 + i64.load offset=838 align=1 + local.set 838 + i32.const 0 + i64.load offset=839 align=1 + local.set 839 + i32.const 0 + i64.load offset=840 align=1 + local.set 840 + i32.const 0 + i64.load offset=841 align=1 + local.set 841 + i32.const 0 + i64.load offset=842 align=1 + local.set 842 + i32.const 0 + i64.load offset=843 align=1 + local.set 843 + i32.const 0 + i64.load offset=844 align=1 + local.set 844 + i32.const 0 + i64.load offset=845 align=1 + local.set 845 + i32.const 0 + i64.load offset=846 align=1 + local.set 846 + i32.const 0 + i64.load offset=847 align=1 + local.set 847 + i32.const 0 + i64.load offset=848 align=1 + local.set 848 + i32.const 0 + i64.load offset=849 align=1 + local.set 849 + i32.const 0 + i64.load offset=850 align=1 + local.set 850 + i32.const 0 + i64.load offset=851 align=1 + local.set 851 + i32.const 0 + i64.load offset=852 align=1 + local.set 852 + i32.const 0 + i64.load offset=853 align=1 + local.set 853 + i32.const 0 + i64.load offset=854 align=1 + local.set 854 + i32.const 0 + i64.load offset=855 align=1 + local.set 855 + i32.const 0 + i64.load offset=856 align=1 + local.set 856 + i32.const 0 + i64.load offset=857 align=1 + local.set 857 + i32.const 0 + i64.load offset=858 align=1 + local.set 858 + i32.const 0 + i64.load offset=859 align=1 + local.set 859 + i32.const 0 + i64.load offset=860 align=1 + local.set 860 + i32.const 0 + i64.load offset=861 align=1 + local.set 861 + i32.const 0 + i64.load offset=862 align=1 + local.set 862 + i32.const 0 + i64.load offset=863 align=1 + local.set 863 + i32.const 0 + i64.load offset=864 align=1 + local.set 864 + i32.const 0 + i64.load offset=865 align=1 + local.set 865 + i32.const 0 + i64.load offset=866 align=1 + local.set 866 + i32.const 0 + i64.load offset=867 align=1 + local.set 867 + i32.const 0 + i64.load offset=868 align=1 + local.set 868 + i32.const 0 + i64.load offset=869 align=1 + local.set 869 + i32.const 0 + i64.load offset=870 align=1 + local.set 870 + i32.const 0 + i64.load offset=871 align=1 + local.set 871 + i32.const 0 + i64.load offset=872 align=1 + local.set 872 + i32.const 0 + i64.load offset=873 align=1 + local.set 873 + i32.const 0 + i64.load offset=874 align=1 + local.set 874 + i32.const 0 + i64.load offset=875 align=1 + local.set 875 + i32.const 0 + i64.load offset=876 align=1 + local.set 876 + i32.const 0 + i64.load offset=877 align=1 + local.set 877 + i32.const 0 + i64.load offset=878 align=1 + local.set 878 + i32.const 0 + i64.load offset=879 align=1 + local.set 879 + i32.const 0 + i64.load offset=880 align=1 + local.set 880 + i32.const 0 + i64.load offset=881 align=1 + local.set 881 + i32.const 0 + i64.load offset=882 align=1 + local.set 882 + i32.const 0 + i64.load offset=883 align=1 + local.set 883 + i32.const 0 + i64.load offset=884 align=1 + local.set 884 + i32.const 0 + i64.load offset=885 align=1 + local.set 885 + i32.const 0 + i64.load offset=886 align=1 + local.set 886 + i32.const 0 + i64.load offset=887 align=1 + local.set 887 + i32.const 0 + i64.load offset=888 align=1 + local.set 888 + i32.const 0 + i64.load offset=889 align=1 + local.set 889 + i32.const 0 + i64.load offset=890 align=1 + local.set 890 + i32.const 0 + i64.load offset=891 align=1 + local.set 891 + i32.const 0 + i64.load offset=892 align=1 + local.set 892 + i32.const 0 + i64.load offset=893 align=1 + local.set 893 + i32.const 0 + i64.load offset=894 align=1 + local.set 894 + i32.const 0 + i64.load offset=895 align=1 + local.set 895 + i32.const 0 + i64.load offset=896 align=1 + local.set 896 + i32.const 0 + i64.load offset=897 align=1 + local.set 897 + i32.const 0 + i64.load offset=898 align=1 + local.set 898 + i32.const 0 + i64.load offset=899 align=1 + local.set 899 + i32.const 0 + i64.load offset=900 align=1 + local.set 900 + i32.const 0 + i64.load offset=901 align=1 + local.set 901 + i32.const 0 + i64.load offset=902 align=1 + local.set 902 + i32.const 0 + i64.load offset=903 align=1 + local.set 903 + i32.const 0 + i64.load offset=904 align=1 + local.set 904 + i32.const 0 + i64.load offset=905 align=1 + local.set 905 + i32.const 0 + i64.load offset=906 align=1 + local.set 906 + i32.const 0 + i64.load offset=907 align=1 + local.set 907 + i32.const 0 + i64.load offset=908 align=1 + local.set 908 + i32.const 0 + i64.load offset=909 align=1 + local.set 909 + i32.const 0 + i64.load offset=910 align=1 + local.set 910 + i32.const 0 + i64.load offset=911 align=1 + local.set 911 + i32.const 0 + i64.load offset=912 align=1 + local.set 912 + i32.const 0 + i64.load offset=913 align=1 + local.set 913 + i32.const 0 + i64.load offset=914 align=1 + local.set 914 + i32.const 0 + i64.load offset=915 align=1 + local.set 915 + i32.const 0 + i64.load offset=916 align=1 + local.set 916 + i32.const 0 + i64.load offset=917 align=1 + local.set 917 + i32.const 0 + i64.load offset=918 align=1 + local.set 918 + i32.const 0 + i64.load offset=919 align=1 + local.set 919 + i32.const 0 + i64.load offset=920 align=1 + local.set 920 + i32.const 0 + i64.load offset=921 align=1 + local.set 921 + i32.const 0 + i64.load offset=922 align=1 + local.set 922 + i32.const 0 + i64.load offset=923 align=1 + local.set 923 + i32.const 0 + i64.load offset=924 align=1 + local.set 924 + i32.const 0 + i64.load offset=925 align=1 + local.set 925 + i32.const 0 + i64.load offset=926 align=1 + local.set 926 + i32.const 0 + i64.load offset=927 align=1 + local.set 927 + i32.const 0 + i64.load offset=928 align=1 + local.set 928 + i32.const 0 + i64.load offset=929 align=1 + local.set 929 + i32.const 0 + i64.load offset=930 align=1 + local.set 930 + i32.const 0 + i64.load offset=931 align=1 + local.set 931 + i32.const 0 + i64.load offset=932 align=1 + local.set 932 + i32.const 0 + i64.load offset=933 align=1 + local.set 933 + i32.const 0 + i64.load offset=934 align=1 + local.set 934 + i32.const 0 + i64.load offset=935 align=1 + local.set 935 + i32.const 0 + i64.load offset=936 align=1 + local.set 936 + i32.const 0 + i64.load offset=937 align=1 + local.set 937 + i32.const 0 + i64.load offset=938 align=1 + local.set 938 + i32.const 0 + i64.load offset=939 align=1 + local.set 939 + i32.const 0 + i64.load offset=940 align=1 + local.set 940 + i32.const 0 + i64.load offset=941 align=1 + local.set 941 + i32.const 0 + i64.load offset=942 align=1 + local.set 942 + i32.const 0 + i64.load offset=943 align=1 + local.set 943 + i32.const 0 + i64.load offset=944 align=1 + local.set 944 + i32.const 0 + i64.load offset=945 align=1 + local.set 945 + i32.const 0 + i64.load offset=946 align=1 + local.set 946 + i32.const 0 + i64.load offset=947 align=1 + local.set 947 + i32.const 0 + i64.load offset=948 align=1 + local.set 948 + i32.const 0 + i64.load offset=949 align=1 + local.set 949 + i32.const 0 + i64.load offset=950 align=1 + local.set 950 + i32.const 0 + i64.load offset=951 align=1 + local.set 951 + i32.const 0 + i64.load offset=952 align=1 + local.set 952 + i32.const 0 + i64.load offset=953 align=1 + local.set 953 + i32.const 0 + i64.load offset=954 align=1 + local.set 954 + i32.const 0 + i64.load offset=955 align=1 + local.set 955 + i32.const 0 + i64.load offset=956 align=1 + local.set 956 + i32.const 0 + i64.load offset=957 align=1 + local.set 957 + i32.const 0 + i64.load offset=958 align=1 + local.set 958 + i32.const 0 + i64.load offset=959 align=1 + local.set 959 + i32.const 0 + i64.load offset=960 align=1 + local.set 960 + i32.const 0 + i64.load offset=961 align=1 + local.set 961 + i32.const 0 + i64.load offset=962 align=1 + local.set 962 + i32.const 0 + i64.load offset=963 align=1 + local.set 963 + i32.const 0 + i64.load offset=964 align=1 + local.set 964 + i32.const 0 + i64.load offset=965 align=1 + local.set 965 + i32.const 0 + i64.load offset=966 align=1 + local.set 966 + i32.const 0 + i64.load offset=967 align=1 + local.set 967 + i32.const 0 + i64.load offset=968 align=1 + local.set 968 + i32.const 0 + i64.load offset=969 align=1 + local.set 969 + i32.const 0 + i64.load offset=970 align=1 + local.set 970 + i32.const 0 + i64.load offset=971 align=1 + local.set 971 + i32.const 0 + i64.load offset=972 align=1 + local.set 972 + i32.const 0 + i64.load offset=973 align=1 + local.set 973 + i32.const 0 + i64.load offset=974 align=1 + local.set 974 + i32.const 0 + i64.load offset=975 align=1 + local.set 975 + i32.const 0 + i64.load offset=976 align=1 + local.set 976 + i32.const 0 + i64.load offset=977 align=1 + local.set 977 + i32.const 0 + i64.load offset=978 align=1 + local.set 978 + i32.const 0 + i64.load offset=979 align=1 + local.set 979 + i32.const 0 + i64.load offset=980 align=1 + local.set 980 + i32.const 0 + i64.load offset=981 align=1 + local.set 981 + i32.const 0 + i64.load offset=982 align=1 + local.set 982 + i32.const 0 + i64.load offset=983 align=1 + local.set 983 + i32.const 0 + i64.load offset=984 align=1 + local.set 984 + i32.const 0 + i64.load offset=985 align=1 + local.set 985 + i32.const 0 + i64.load offset=986 align=1 + local.set 986 + i32.const 0 + i64.load offset=987 align=1 + local.set 987 + i32.const 0 + i64.load offset=988 align=1 + local.set 988 + i32.const 0 + i64.load offset=989 align=1 + local.set 989 + i32.const 0 + i64.load offset=990 align=1 + local.set 990 + i32.const 0 + i64.load offset=991 align=1 + local.set 991 + i32.const 0 + i64.load offset=992 align=1 + local.set 992 + i32.const 0 + i64.load offset=993 align=1 + local.set 993 + i32.const 0 + i64.load offset=994 align=1 + local.set 994 + i32.const 0 + i64.load offset=995 align=1 + local.set 995 + i32.const 0 + i64.load offset=996 align=1 + local.set 996 + i32.const 0 + i64.load offset=997 align=1 + local.set 997 + i32.const 0 + i64.load offset=998 align=1 + local.set 998 + i32.const 0 + i64.load offset=999 align=1 + local.set 999 + i32.const 0 + i64.load offset=1000 align=1 + local.set 1000 + i32.const 0 + i64.load offset=1001 align=1 + local.set 1001 + i32.const 0 + i64.load offset=1002 align=1 + local.set 1002 + i32.const 0 + i64.load offset=1003 align=1 + local.set 1003 + i32.const 0 + i64.load offset=1004 align=1 + local.set 1004 + i32.const 0 + i64.load offset=1005 align=1 + local.set 1005 + i32.const 0 + i64.load offset=1006 align=1 + local.set 1006 + i32.const 0 + i64.load offset=1007 align=1 + local.set 1007 + i32.const 0 + i64.load offset=1008 align=1 + local.set 1008 + i32.const 0 + i64.load offset=1009 align=1 + local.set 1009 + i32.const 0 + i64.load offset=1010 align=1 + local.set 1010 + i32.const 0 + i64.load offset=1011 align=1 + local.set 1011 + i32.const 0 + i64.load offset=1012 align=1 + local.set 1012 + i32.const 0 + i64.load offset=1013 align=1 + local.set 1013 + i32.const 0 + i64.load offset=1014 align=1 + local.set 1014 + i32.const 0 + i64.load offset=1015 align=1 + local.set 1015 + i32.const 0 + i64.load offset=1016 align=1 + local.set 1016 + i32.const 0 + i64.load offset=1017 align=1 + local.set 1017 + i32.const 0 + i64.load offset=1018 align=1 + local.set 1018 + i32.const 0 + i64.load offset=1019 align=1 + local.set 1019 + i32.const 0 + i64.load offset=1020 align=1 + local.set 1020 + i32.const 0 + i64.load offset=1021 align=1 + local.set 1021 + i32.const 0 + i64.load offset=1022 align=1 + local.set 1022 + i32.const 0 + i64.load offset=1023 align=1 + local.set 1023 + i32.const 0 + i64.load offset=1024 align=1 + local.set 1024 + i32.const 0 + i64.load offset=1025 align=1 + local.set 1025 + i32.const 0 + i64.load offset=1026 align=1 + local.set 1026 + i32.const 0 + i64.load offset=1027 align=1 + local.set 1027 + i32.const 0 + i64.load offset=1028 align=1 + local.set 1028 + i32.const 0 + i64.load offset=1029 align=1 + local.set 1029 + i32.const 0 + i64.load offset=1030 align=1 + local.set 1030 + i32.const 0 + i64.load offset=1031 align=1 + local.set 1031 + i32.const 0 + i64.load offset=1032 align=1 + local.set 1032 + i32.const 0 + i64.load offset=1033 align=1 + local.set 1033 + i32.const 0 + i64.load offset=1034 align=1 + local.set 1034 + i32.const 0 + i64.load offset=1035 align=1 + local.set 1035 + i32.const 0 + i64.load offset=1036 align=1 + local.set 1036 + i32.const 0 + i64.load offset=1037 align=1 + local.set 1037 + i32.const 0 + i64.load offset=1038 align=1 + local.set 1038 + i32.const 0 + i64.load offset=1039 align=1 + local.set 1039 + i32.const 0 + i64.load offset=1040 align=1 + local.set 1040 + i32.const 0 + i64.load offset=1041 align=1 + local.set 1041 + i32.const 0 + i64.load offset=1042 align=1 + local.set 1042 + i32.const 0 + i64.load offset=1043 align=1 + local.set 1043 + i32.const 0 + i64.load offset=1044 align=1 + local.set 1044 + i32.const 0 + i64.load offset=1045 align=1 + local.set 1045 + i32.const 0 + i64.load offset=1046 align=1 + local.set 1046 + i32.const 0 + i64.load offset=1047 align=1 + local.set 1047 + i32.const 0 + i64.load offset=1048 align=1 + local.set 1048 + i32.const 0 + i64.load offset=1049 align=1 + local.set 1049 + i32.const 0 + i64.load offset=1050 align=1 + local.set 1050 + i32.const 0 + i64.load offset=1051 align=1 + local.set 1051 + i32.const 0 + i64.load offset=1052 align=1 + local.set 1052 + i32.const 0 + i64.load offset=1053 align=1 + local.set 1053 + i32.const 0 + i64.load offset=1054 align=1 + local.set 1054 + i32.const 0 + i64.load offset=1055 align=1 + local.set 1055 + i32.const 0 + local.get 0 + i64.store align=1 + i32.const 0 + local.get 1 + i64.store offset=1 align=1 + i32.const 0 + local.get 2 + i64.store offset=2 align=1 + i32.const 0 + local.get 3 + i64.store offset=3 align=1 + i32.const 0 + local.get 4 + i64.store offset=4 align=1 + i32.const 0 + local.get 5 + i64.store offset=5 align=1 + i32.const 0 + local.get 6 + i64.store offset=6 align=1 + i32.const 0 + local.get 7 + i64.store offset=7 align=1 + i32.const 0 + local.get 8 + i64.store offset=8 align=1 + i32.const 0 + local.get 9 + i64.store offset=9 align=1 + i32.const 0 + local.get 10 + i64.store offset=10 align=1 + i32.const 0 + local.get 11 + i64.store offset=11 align=1 + i32.const 0 + local.get 12 + i64.store offset=12 align=1 + i32.const 0 + local.get 13 + i64.store offset=13 align=1 + i32.const 0 + local.get 14 + i64.store offset=14 align=1 + i32.const 0 + local.get 15 + i64.store offset=15 align=1 + i32.const 0 + local.get 16 + i64.store offset=16 align=1 + i32.const 0 + local.get 17 + i64.store offset=17 align=1 + i32.const 0 + local.get 18 + i64.store offset=18 align=1 + i32.const 0 + local.get 19 + i64.store offset=19 align=1 + i32.const 0 + local.get 20 + i64.store offset=20 align=1 + i32.const 0 + local.get 21 + i64.store offset=21 align=1 + i32.const 0 + local.get 22 + i64.store offset=22 align=1 + i32.const 0 + local.get 23 + i64.store offset=23 align=1 + i32.const 0 + local.get 24 + i64.store offset=24 align=1 + i32.const 0 + local.get 25 + i64.store offset=25 align=1 + i32.const 0 + local.get 26 + i64.store offset=26 align=1 + i32.const 0 + local.get 27 + i64.store offset=27 align=1 + i32.const 0 + local.get 28 + i64.store offset=28 align=1 + i32.const 0 + local.get 29 + i64.store offset=29 align=1 + i32.const 0 + local.get 30 + i64.store offset=30 align=1 + i32.const 0 + local.get 31 + i64.store offset=31 align=1 + i32.const 0 + local.get 32 + i64.store offset=32 align=1 + i32.const 0 + local.get 33 + i64.store offset=33 align=1 + i32.const 0 + local.get 34 + i64.store offset=34 align=1 + i32.const 0 + local.get 35 + i64.store offset=35 align=1 + i32.const 0 + local.get 36 + i64.store offset=36 align=1 + i32.const 0 + local.get 37 + i64.store offset=37 align=1 + i32.const 0 + local.get 38 + i64.store offset=38 align=1 + i32.const 0 + local.get 39 + i64.store offset=39 align=1 + i32.const 0 + local.get 40 + i64.store offset=40 align=1 + i32.const 0 + local.get 41 + i64.store offset=41 align=1 + i32.const 0 + local.get 42 + i64.store offset=42 align=1 + i32.const 0 + local.get 43 + i64.store offset=43 align=1 + i32.const 0 + local.get 44 + i64.store offset=44 align=1 + i32.const 0 + local.get 45 + i64.store offset=45 align=1 + i32.const 0 + local.get 46 + i64.store offset=46 align=1 + i32.const 0 + local.get 47 + i64.store offset=47 align=1 + i32.const 0 + local.get 48 + i64.store offset=48 align=1 + i32.const 0 + local.get 49 + i64.store offset=49 align=1 + i32.const 0 + local.get 50 + i64.store offset=50 align=1 + i32.const 0 + local.get 51 + i64.store offset=51 align=1 + i32.const 0 + local.get 52 + i64.store offset=52 align=1 + i32.const 0 + local.get 53 + i64.store offset=53 align=1 + i32.const 0 + local.get 54 + i64.store offset=54 align=1 + i32.const 0 + local.get 55 + i64.store offset=55 align=1 + i32.const 0 + local.get 56 + i64.store offset=56 align=1 + i32.const 0 + local.get 57 + i64.store offset=57 align=1 + i32.const 0 + local.get 58 + i64.store offset=58 align=1 + i32.const 0 + local.get 59 + i64.store offset=59 align=1 + i32.const 0 + local.get 60 + i64.store offset=60 align=1 + i32.const 0 + local.get 61 + i64.store offset=61 align=1 + i32.const 0 + local.get 62 + i64.store offset=62 align=1 + i32.const 0 + local.get 63 + i64.store offset=63 align=1 + i32.const 0 + local.get 64 + i64.store offset=64 align=1 + i32.const 0 + local.get 65 + i64.store offset=65 align=1 + i32.const 0 + local.get 66 + i64.store offset=66 align=1 + i32.const 0 + local.get 67 + i64.store offset=67 align=1 + i32.const 0 + local.get 68 + i64.store offset=68 align=1 + i32.const 0 + local.get 69 + i64.store offset=69 align=1 + i32.const 0 + local.get 70 + i64.store offset=70 align=1 + i32.const 0 + local.get 71 + i64.store offset=71 align=1 + i32.const 0 + local.get 72 + i64.store offset=72 align=1 + i32.const 0 + local.get 73 + i64.store offset=73 align=1 + i32.const 0 + local.get 74 + i64.store offset=74 align=1 + i32.const 0 + local.get 75 + i64.store offset=75 align=1 + i32.const 0 + local.get 76 + i64.store offset=76 align=1 + i32.const 0 + local.get 77 + i64.store offset=77 align=1 + i32.const 0 + local.get 78 + i64.store offset=78 align=1 + i32.const 0 + local.get 79 + i64.store offset=79 align=1 + i32.const 0 + local.get 80 + i64.store offset=80 align=1 + i32.const 0 + local.get 81 + i64.store offset=81 align=1 + i32.const 0 + local.get 82 + i64.store offset=82 align=1 + i32.const 0 + local.get 83 + i64.store offset=83 align=1 + i32.const 0 + local.get 84 + i64.store offset=84 align=1 + i32.const 0 + local.get 85 + i64.store offset=85 align=1 + i32.const 0 + local.get 86 + i64.store offset=86 align=1 + i32.const 0 + local.get 87 + i64.store offset=87 align=1 + i32.const 0 + local.get 88 + i64.store offset=88 align=1 + i32.const 0 + local.get 89 + i64.store offset=89 align=1 + i32.const 0 + local.get 90 + i64.store offset=90 align=1 + i32.const 0 + local.get 91 + i64.store offset=91 align=1 + i32.const 0 + local.get 92 + i64.store offset=92 align=1 + i32.const 0 + local.get 93 + i64.store offset=93 align=1 + i32.const 0 + local.get 94 + i64.store offset=94 align=1 + i32.const 0 + local.get 95 + i64.store offset=95 align=1 + i32.const 0 + local.get 96 + i64.store offset=96 align=1 + i32.const 0 + local.get 97 + i64.store offset=97 align=1 + i32.const 0 + local.get 98 + i64.store offset=98 align=1 + i32.const 0 + local.get 99 + i64.store offset=99 align=1 + i32.const 0 + local.get 100 + i64.store offset=100 align=1 + i32.const 0 + local.get 101 + i64.store offset=101 align=1 + i32.const 0 + local.get 102 + i64.store offset=102 align=1 + i32.const 0 + local.get 103 + i64.store offset=103 align=1 + i32.const 0 + local.get 104 + i64.store offset=104 align=1 + i32.const 0 + local.get 105 + i64.store offset=105 align=1 + i32.const 0 + local.get 106 + i64.store offset=106 align=1 + i32.const 0 + local.get 107 + i64.store offset=107 align=1 + i32.const 0 + local.get 108 + i64.store offset=108 align=1 + i32.const 0 + local.get 109 + i64.store offset=109 align=1 + i32.const 0 + local.get 110 + i64.store offset=110 align=1 + i32.const 0 + local.get 111 + i64.store offset=111 align=1 + i32.const 0 + local.get 112 + i64.store offset=112 align=1 + i32.const 0 + local.get 113 + i64.store offset=113 align=1 + i32.const 0 + local.get 114 + i64.store offset=114 align=1 + i32.const 0 + local.get 115 + i64.store offset=115 align=1 + i32.const 0 + local.get 116 + i64.store offset=116 align=1 + i32.const 0 + local.get 117 + i64.store offset=117 align=1 + i32.const 0 + local.get 118 + i64.store offset=118 align=1 + i32.const 0 + local.get 119 + i64.store offset=119 align=1 + i32.const 0 + local.get 120 + i64.store offset=120 align=1 + i32.const 0 + local.get 121 + i64.store offset=121 align=1 + i32.const 0 + local.get 122 + i64.store offset=122 align=1 + i32.const 0 + local.get 123 + i64.store offset=123 align=1 + i32.const 0 + local.get 124 + i64.store offset=124 align=1 + i32.const 0 + local.get 125 + i64.store offset=125 align=1 + i32.const 0 + local.get 126 + i64.store offset=126 align=1 + i32.const 0 + local.get 127 + i64.store offset=127 align=1 + i32.const 0 + local.get 128 + i64.store offset=128 align=1 + i32.const 0 + local.get 129 + i64.store offset=129 align=1 + i32.const 0 + local.get 130 + i64.store offset=130 align=1 + i32.const 0 + local.get 131 + i64.store offset=131 align=1 + i32.const 0 + local.get 132 + i64.store offset=132 align=1 + i32.const 0 + local.get 133 + i64.store offset=133 align=1 + i32.const 0 + local.get 134 + i64.store offset=134 align=1 + i32.const 0 + local.get 135 + i64.store offset=135 align=1 + i32.const 0 + local.get 136 + i64.store offset=136 align=1 + i32.const 0 + local.get 137 + i64.store offset=137 align=1 + i32.const 0 + local.get 138 + i64.store offset=138 align=1 + i32.const 0 + local.get 139 + i64.store offset=139 align=1 + i32.const 0 + local.get 140 + i64.store offset=140 align=1 + i32.const 0 + local.get 141 + i64.store offset=141 align=1 + i32.const 0 + local.get 142 + i64.store offset=142 align=1 + i32.const 0 + local.get 143 + i64.store offset=143 align=1 + i32.const 0 + local.get 144 + i64.store offset=144 align=1 + i32.const 0 + local.get 145 + i64.store offset=145 align=1 + i32.const 0 + local.get 146 + i64.store offset=146 align=1 + i32.const 0 + local.get 147 + i64.store offset=147 align=1 + i32.const 0 + local.get 148 + i64.store offset=148 align=1 + i32.const 0 + local.get 149 + i64.store offset=149 align=1 + i32.const 0 + local.get 150 + i64.store offset=150 align=1 + i32.const 0 + local.get 151 + i64.store offset=151 align=1 + i32.const 0 + local.get 152 + i64.store offset=152 align=1 + i32.const 0 + local.get 153 + i64.store offset=153 align=1 + i32.const 0 + local.get 154 + i64.store offset=154 align=1 + i32.const 0 + local.get 155 + i64.store offset=155 align=1 + i32.const 0 + local.get 156 + i64.store offset=156 align=1 + i32.const 0 + local.get 157 + i64.store offset=157 align=1 + i32.const 0 + local.get 158 + i64.store offset=158 align=1 + i32.const 0 + local.get 159 + i64.store offset=159 align=1 + i32.const 0 + local.get 160 + i64.store offset=160 align=1 + i32.const 0 + local.get 161 + i64.store offset=161 align=1 + i32.const 0 + local.get 162 + i64.store offset=162 align=1 + i32.const 0 + local.get 163 + i64.store offset=163 align=1 + i32.const 0 + local.get 164 + i64.store offset=164 align=1 + i32.const 0 + local.get 165 + i64.store offset=165 align=1 + i32.const 0 + local.get 166 + i64.store offset=166 align=1 + i32.const 0 + local.get 167 + i64.store offset=167 align=1 + i32.const 0 + local.get 168 + i64.store offset=168 align=1 + i32.const 0 + local.get 169 + i64.store offset=169 align=1 + i32.const 0 + local.get 170 + i64.store offset=170 align=1 + i32.const 0 + local.get 171 + i64.store offset=171 align=1 + i32.const 0 + local.get 172 + i64.store offset=172 align=1 + i32.const 0 + local.get 173 + i64.store offset=173 align=1 + i32.const 0 + local.get 174 + i64.store offset=174 align=1 + i32.const 0 + local.get 175 + i64.store offset=175 align=1 + i32.const 0 + local.get 176 + i64.store offset=176 align=1 + i32.const 0 + local.get 177 + i64.store offset=177 align=1 + i32.const 0 + local.get 178 + i64.store offset=178 align=1 + i32.const 0 + local.get 179 + i64.store offset=179 align=1 + i32.const 0 + local.get 180 + i64.store offset=180 align=1 + i32.const 0 + local.get 181 + i64.store offset=181 align=1 + i32.const 0 + local.get 182 + i64.store offset=182 align=1 + i32.const 0 + local.get 183 + i64.store offset=183 align=1 + i32.const 0 + local.get 184 + i64.store offset=184 align=1 + i32.const 0 + local.get 185 + i64.store offset=185 align=1 + i32.const 0 + local.get 186 + i64.store offset=186 align=1 + i32.const 0 + local.get 187 + i64.store offset=187 align=1 + i32.const 0 + local.get 188 + i64.store offset=188 align=1 + i32.const 0 + local.get 189 + i64.store offset=189 align=1 + i32.const 0 + local.get 190 + i64.store offset=190 align=1 + i32.const 0 + local.get 191 + i64.store offset=191 align=1 + i32.const 0 + local.get 192 + i64.store offset=192 align=1 + i32.const 0 + local.get 193 + i64.store offset=193 align=1 + i32.const 0 + local.get 194 + i64.store offset=194 align=1 + i32.const 0 + local.get 195 + i64.store offset=195 align=1 + i32.const 0 + local.get 196 + i64.store offset=196 align=1 + i32.const 0 + local.get 197 + i64.store offset=197 align=1 + i32.const 0 + local.get 198 + i64.store offset=198 align=1 + i32.const 0 + local.get 199 + i64.store offset=199 align=1 + i32.const 0 + local.get 200 + i64.store offset=200 align=1 + i32.const 0 + local.get 201 + i64.store offset=201 align=1 + i32.const 0 + local.get 202 + i64.store offset=202 align=1 + i32.const 0 + local.get 203 + i64.store offset=203 align=1 + i32.const 0 + local.get 204 + i64.store offset=204 align=1 + i32.const 0 + local.get 205 + i64.store offset=205 align=1 + i32.const 0 + local.get 206 + i64.store offset=206 align=1 + i32.const 0 + local.get 207 + i64.store offset=207 align=1 + i32.const 0 + local.get 208 + i64.store offset=208 align=1 + i32.const 0 + local.get 209 + i64.store offset=209 align=1 + i32.const 0 + local.get 210 + i64.store offset=210 align=1 + i32.const 0 + local.get 211 + i64.store offset=211 align=1 + i32.const 0 + local.get 212 + i64.store offset=212 align=1 + i32.const 0 + local.get 213 + i64.store offset=213 align=1 + i32.const 0 + local.get 214 + i64.store offset=214 align=1 + i32.const 0 + local.get 215 + i64.store offset=215 align=1 + i32.const 0 + local.get 216 + i64.store offset=216 align=1 + i32.const 0 + local.get 217 + i64.store offset=217 align=1 + i32.const 0 + local.get 218 + i64.store offset=218 align=1 + i32.const 0 + local.get 219 + i64.store offset=219 align=1 + i32.const 0 + local.get 220 + i64.store offset=220 align=1 + i32.const 0 + local.get 221 + i64.store offset=221 align=1 + i32.const 0 + local.get 222 + i64.store offset=222 align=1 + i32.const 0 + local.get 223 + i64.store offset=223 align=1 + i32.const 0 + local.get 224 + i64.store offset=224 align=1 + i32.const 0 + local.get 225 + i64.store offset=225 align=1 + i32.const 0 + local.get 226 + i64.store offset=226 align=1 + i32.const 0 + local.get 227 + i64.store offset=227 align=1 + i32.const 0 + local.get 228 + i64.store offset=228 align=1 + i32.const 0 + local.get 229 + i64.store offset=229 align=1 + i32.const 0 + local.get 230 + i64.store offset=230 align=1 + i32.const 0 + local.get 231 + i64.store offset=231 align=1 + i32.const 0 + local.get 232 + i64.store offset=232 align=1 + i32.const 0 + local.get 233 + i64.store offset=233 align=1 + i32.const 0 + local.get 234 + i64.store offset=234 align=1 + i32.const 0 + local.get 235 + i64.store offset=235 align=1 + i32.const 0 + local.get 236 + i64.store offset=236 align=1 + i32.const 0 + local.get 237 + i64.store offset=237 align=1 + i32.const 0 + local.get 238 + i64.store offset=238 align=1 + i32.const 0 + local.get 239 + i64.store offset=239 align=1 + i32.const 0 + local.get 240 + i64.store offset=240 align=1 + i32.const 0 + local.get 241 + i64.store offset=241 align=1 + i32.const 0 + local.get 242 + i64.store offset=242 align=1 + i32.const 0 + local.get 243 + i64.store offset=243 align=1 + i32.const 0 + local.get 244 + i64.store offset=244 align=1 + i32.const 0 + local.get 245 + i64.store offset=245 align=1 + i32.const 0 + local.get 246 + i64.store offset=246 align=1 + i32.const 0 + local.get 247 + i64.store offset=247 align=1 + i32.const 0 + local.get 248 + i64.store offset=248 align=1 + i32.const 0 + local.get 249 + i64.store offset=249 align=1 + i32.const 0 + local.get 250 + i64.store offset=250 align=1 + i32.const 0 + local.get 251 + i64.store offset=251 align=1 + i32.const 0 + local.get 252 + i64.store offset=252 align=1 + i32.const 0 + local.get 253 + i64.store offset=253 align=1 + i32.const 0 + local.get 254 + i64.store offset=254 align=1 + i32.const 0 + local.get 255 + i64.store offset=255 align=1 + i32.const 0 + local.get 256 + i64.store offset=256 align=1 + i32.const 0 + local.get 257 + i64.store offset=257 align=1 + i32.const 0 + local.get 258 + i64.store offset=258 align=1 + i32.const 0 + local.get 259 + i64.store offset=259 align=1 + i32.const 0 + local.get 260 + i64.store offset=260 align=1 + i32.const 0 + local.get 261 + i64.store offset=261 align=1 + i32.const 0 + local.get 262 + i64.store offset=262 align=1 + i32.const 0 + local.get 263 + i64.store offset=263 align=1 + i32.const 0 + local.get 264 + i64.store offset=264 align=1 + i32.const 0 + local.get 265 + i64.store offset=265 align=1 + i32.const 0 + local.get 266 + i64.store offset=266 align=1 + i32.const 0 + local.get 267 + i64.store offset=267 align=1 + i32.const 0 + local.get 268 + i64.store offset=268 align=1 + i32.const 0 + local.get 269 + i64.store offset=269 align=1 + i32.const 0 + local.get 270 + i64.store offset=270 align=1 + i32.const 0 + local.get 271 + i64.store offset=271 align=1 + i32.const 0 + local.get 272 + i64.store offset=272 align=1 + i32.const 0 + local.get 273 + i64.store offset=273 align=1 + i32.const 0 + local.get 274 + i64.store offset=274 align=1 + i32.const 0 + local.get 275 + i64.store offset=275 align=1 + i32.const 0 + local.get 276 + i64.store offset=276 align=1 + i32.const 0 + local.get 277 + i64.store offset=277 align=1 + i32.const 0 + local.get 278 + i64.store offset=278 align=1 + i32.const 0 + local.get 279 + i64.store offset=279 align=1 + i32.const 0 + local.get 280 + i64.store offset=280 align=1 + i32.const 0 + local.get 281 + i64.store offset=281 align=1 + i32.const 0 + local.get 282 + i64.store offset=282 align=1 + i32.const 0 + local.get 283 + i64.store offset=283 align=1 + i32.const 0 + local.get 284 + i64.store offset=284 align=1 + i32.const 0 + local.get 285 + i64.store offset=285 align=1 + i32.const 0 + local.get 286 + i64.store offset=286 align=1 + i32.const 0 + local.get 287 + i64.store offset=287 align=1 + i32.const 0 + local.get 288 + i64.store offset=288 align=1 + i32.const 0 + local.get 289 + i64.store offset=289 align=1 + i32.const 0 + local.get 290 + i64.store offset=290 align=1 + i32.const 0 + local.get 291 + i64.store offset=291 align=1 + i32.const 0 + local.get 292 + i64.store offset=292 align=1 + i32.const 0 + local.get 293 + i64.store offset=293 align=1 + i32.const 0 + local.get 294 + i64.store offset=294 align=1 + i32.const 0 + local.get 295 + i64.store offset=295 align=1 + i32.const 0 + local.get 296 + i64.store offset=296 align=1 + i32.const 0 + local.get 297 + i64.store offset=297 align=1 + i32.const 0 + local.get 298 + i64.store offset=298 align=1 + i32.const 0 + local.get 299 + i64.store offset=299 align=1 + i32.const 0 + local.get 300 + i64.store offset=300 align=1 + i32.const 0 + local.get 301 + i64.store offset=301 align=1 + i32.const 0 + local.get 302 + i64.store offset=302 align=1 + i32.const 0 + local.get 303 + i64.store offset=303 align=1 + i32.const 0 + local.get 304 + i64.store offset=304 align=1 + i32.const 0 + local.get 305 + i64.store offset=305 align=1 + i32.const 0 + local.get 306 + i64.store offset=306 align=1 + i32.const 0 + local.get 307 + i64.store offset=307 align=1 + i32.const 0 + local.get 308 + i64.store offset=308 align=1 + i32.const 0 + local.get 309 + i64.store offset=309 align=1 + i32.const 0 + local.get 310 + i64.store offset=310 align=1 + i32.const 0 + local.get 311 + i64.store offset=311 align=1 + i32.const 0 + local.get 312 + i64.store offset=312 align=1 + i32.const 0 + local.get 313 + i64.store offset=313 align=1 + i32.const 0 + local.get 314 + i64.store offset=314 align=1 + i32.const 0 + local.get 315 + i64.store offset=315 align=1 + i32.const 0 + local.get 316 + i64.store offset=316 align=1 + i32.const 0 + local.get 317 + i64.store offset=317 align=1 + i32.const 0 + local.get 318 + i64.store offset=318 align=1 + i32.const 0 + local.get 319 + i64.store offset=319 align=1 + i32.const 0 + local.get 320 + i64.store offset=320 align=1 + i32.const 0 + local.get 321 + i64.store offset=321 align=1 + i32.const 0 + local.get 322 + i64.store offset=322 align=1 + i32.const 0 + local.get 323 + i64.store offset=323 align=1 + i32.const 0 + local.get 324 + i64.store offset=324 align=1 + i32.const 0 + local.get 325 + i64.store offset=325 align=1 + i32.const 0 + local.get 326 + i64.store offset=326 align=1 + i32.const 0 + local.get 327 + i64.store offset=327 align=1 + i32.const 0 + local.get 328 + i64.store offset=328 align=1 + i32.const 0 + local.get 329 + i64.store offset=329 align=1 + i32.const 0 + local.get 330 + i64.store offset=330 align=1 + i32.const 0 + local.get 331 + i64.store offset=331 align=1 + i32.const 0 + local.get 332 + i64.store offset=332 align=1 + i32.const 0 + local.get 333 + i64.store offset=333 align=1 + i32.const 0 + local.get 334 + i64.store offset=334 align=1 + i32.const 0 + local.get 335 + i64.store offset=335 align=1 + i32.const 0 + local.get 336 + i64.store offset=336 align=1 + i32.const 0 + local.get 337 + i64.store offset=337 align=1 + i32.const 0 + local.get 338 + i64.store offset=338 align=1 + i32.const 0 + local.get 339 + i64.store offset=339 align=1 + i32.const 0 + local.get 340 + i64.store offset=340 align=1 + i32.const 0 + local.get 341 + i64.store offset=341 align=1 + i32.const 0 + local.get 342 + i64.store offset=342 align=1 + i32.const 0 + local.get 343 + i64.store offset=343 align=1 + i32.const 0 + local.get 344 + i64.store offset=344 align=1 + i32.const 0 + local.get 345 + i64.store offset=345 align=1 + i32.const 0 + local.get 346 + i64.store offset=346 align=1 + i32.const 0 + local.get 347 + i64.store offset=347 align=1 + i32.const 0 + local.get 348 + i64.store offset=348 align=1 + i32.const 0 + local.get 349 + i64.store offset=349 align=1 + i32.const 0 + local.get 350 + i64.store offset=350 align=1 + i32.const 0 + local.get 351 + i64.store offset=351 align=1 + i32.const 0 + local.get 352 + i64.store offset=352 align=1 + i32.const 0 + local.get 353 + i64.store offset=353 align=1 + i32.const 0 + local.get 354 + i64.store offset=354 align=1 + i32.const 0 + local.get 355 + i64.store offset=355 align=1 + i32.const 0 + local.get 356 + i64.store offset=356 align=1 + i32.const 0 + local.get 357 + i64.store offset=357 align=1 + i32.const 0 + local.get 358 + i64.store offset=358 align=1 + i32.const 0 + local.get 359 + i64.store offset=359 align=1 + i32.const 0 + local.get 360 + i64.store offset=360 align=1 + i32.const 0 + local.get 361 + i64.store offset=361 align=1 + i32.const 0 + local.get 362 + i64.store offset=362 align=1 + i32.const 0 + local.get 363 + i64.store offset=363 align=1 + i32.const 0 + local.get 364 + i64.store offset=364 align=1 + i32.const 0 + local.get 365 + i64.store offset=365 align=1 + i32.const 0 + local.get 366 + i64.store offset=366 align=1 + i32.const 0 + local.get 367 + i64.store offset=367 align=1 + i32.const 0 + local.get 368 + i64.store offset=368 align=1 + i32.const 0 + local.get 369 + i64.store offset=369 align=1 + i32.const 0 + local.get 370 + i64.store offset=370 align=1 + i32.const 0 + local.get 371 + i64.store offset=371 align=1 + i32.const 0 + local.get 372 + i64.store offset=372 align=1 + i32.const 0 + local.get 373 + i64.store offset=373 align=1 + i32.const 0 + local.get 374 + i64.store offset=374 align=1 + i32.const 0 + local.get 375 + i64.store offset=375 align=1 + i32.const 0 + local.get 376 + i64.store offset=376 align=1 + i32.const 0 + local.get 377 + i64.store offset=377 align=1 + i32.const 0 + local.get 378 + i64.store offset=378 align=1 + i32.const 0 + local.get 379 + i64.store offset=379 align=1 + i32.const 0 + local.get 380 + i64.store offset=380 align=1 + i32.const 0 + local.get 381 + i64.store offset=381 align=1 + i32.const 0 + local.get 382 + i64.store offset=382 align=1 + i32.const 0 + local.get 383 + i64.store offset=383 align=1 + i32.const 0 + local.get 384 + i64.store offset=384 align=1 + i32.const 0 + local.get 385 + i64.store offset=385 align=1 + i32.const 0 + local.get 386 + i64.store offset=386 align=1 + i32.const 0 + local.get 387 + i64.store offset=387 align=1 + i32.const 0 + local.get 388 + i64.store offset=388 align=1 + i32.const 0 + local.get 389 + i64.store offset=389 align=1 + i32.const 0 + local.get 390 + i64.store offset=390 align=1 + i32.const 0 + local.get 391 + i64.store offset=391 align=1 + i32.const 0 + local.get 392 + i64.store offset=392 align=1 + i32.const 0 + local.get 393 + i64.store offset=393 align=1 + i32.const 0 + local.get 394 + i64.store offset=394 align=1 + i32.const 0 + local.get 395 + i64.store offset=395 align=1 + i32.const 0 + local.get 396 + i64.store offset=396 align=1 + i32.const 0 + local.get 397 + i64.store offset=397 align=1 + i32.const 0 + local.get 398 + i64.store offset=398 align=1 + i32.const 0 + local.get 399 + i64.store offset=399 align=1 + i32.const 0 + local.get 400 + i64.store offset=400 align=1 + i32.const 0 + local.get 401 + i64.store offset=401 align=1 + i32.const 0 + local.get 402 + i64.store offset=402 align=1 + i32.const 0 + local.get 403 + i64.store offset=403 align=1 + i32.const 0 + local.get 404 + i64.store offset=404 align=1 + i32.const 0 + local.get 405 + i64.store offset=405 align=1 + i32.const 0 + local.get 406 + i64.store offset=406 align=1 + i32.const 0 + local.get 407 + i64.store offset=407 align=1 + i32.const 0 + local.get 408 + i64.store offset=408 align=1 + i32.const 0 + local.get 409 + i64.store offset=409 align=1 + i32.const 0 + local.get 410 + i64.store offset=410 align=1 + i32.const 0 + local.get 411 + i64.store offset=411 align=1 + i32.const 0 + local.get 412 + i64.store offset=412 align=1 + i32.const 0 + local.get 413 + i64.store offset=413 align=1 + i32.const 0 + local.get 414 + i64.store offset=414 align=1 + i32.const 0 + local.get 415 + i64.store offset=415 align=1 + i32.const 0 + local.get 416 + i64.store offset=416 align=1 + i32.const 0 + local.get 417 + i64.store offset=417 align=1 + i32.const 0 + local.get 418 + i64.store offset=418 align=1 + i32.const 0 + local.get 419 + i64.store offset=419 align=1 + i32.const 0 + local.get 420 + i64.store offset=420 align=1 + i32.const 0 + local.get 421 + i64.store offset=421 align=1 + i32.const 0 + local.get 422 + i64.store offset=422 align=1 + i32.const 0 + local.get 423 + i64.store offset=423 align=1 + i32.const 0 + local.get 424 + i64.store offset=424 align=1 + i32.const 0 + local.get 425 + i64.store offset=425 align=1 + i32.const 0 + local.get 426 + i64.store offset=426 align=1 + i32.const 0 + local.get 427 + i64.store offset=427 align=1 + i32.const 0 + local.get 428 + i64.store offset=428 align=1 + i32.const 0 + local.get 429 + i64.store offset=429 align=1 + i32.const 0 + local.get 430 + i64.store offset=430 align=1 + i32.const 0 + local.get 431 + i64.store offset=431 align=1 + i32.const 0 + local.get 432 + i64.store offset=432 align=1 + i32.const 0 + local.get 433 + i64.store offset=433 align=1 + i32.const 0 + local.get 434 + i64.store offset=434 align=1 + i32.const 0 + local.get 435 + i64.store offset=435 align=1 + i32.const 0 + local.get 436 + i64.store offset=436 align=1 + i32.const 0 + local.get 437 + i64.store offset=437 align=1 + i32.const 0 + local.get 438 + i64.store offset=438 align=1 + i32.const 0 + local.get 439 + i64.store offset=439 align=1 + i32.const 0 + local.get 440 + i64.store offset=440 align=1 + i32.const 0 + local.get 441 + i64.store offset=441 align=1 + i32.const 0 + local.get 442 + i64.store offset=442 align=1 + i32.const 0 + local.get 443 + i64.store offset=443 align=1 + i32.const 0 + local.get 444 + i64.store offset=444 align=1 + i32.const 0 + local.get 445 + i64.store offset=445 align=1 + i32.const 0 + local.get 446 + i64.store offset=446 align=1 + i32.const 0 + local.get 447 + i64.store offset=447 align=1 + i32.const 0 + local.get 448 + i64.store offset=448 align=1 + i32.const 0 + local.get 449 + i64.store offset=449 align=1 + i32.const 0 + local.get 450 + i64.store offset=450 align=1 + i32.const 0 + local.get 451 + i64.store offset=451 align=1 + i32.const 0 + local.get 452 + i64.store offset=452 align=1 + i32.const 0 + local.get 453 + i64.store offset=453 align=1 + i32.const 0 + local.get 454 + i64.store offset=454 align=1 + i32.const 0 + local.get 455 + i64.store offset=455 align=1 + i32.const 0 + local.get 456 + i64.store offset=456 align=1 + i32.const 0 + local.get 457 + i64.store offset=457 align=1 + i32.const 0 + local.get 458 + i64.store offset=458 align=1 + i32.const 0 + local.get 459 + i64.store offset=459 align=1 + i32.const 0 + local.get 460 + i64.store offset=460 align=1 + i32.const 0 + local.get 461 + i64.store offset=461 align=1 + i32.const 0 + local.get 462 + i64.store offset=462 align=1 + i32.const 0 + local.get 463 + i64.store offset=463 align=1 + i32.const 0 + local.get 464 + i64.store offset=464 align=1 + i32.const 0 + local.get 465 + i64.store offset=465 align=1 + i32.const 0 + local.get 466 + i64.store offset=466 align=1 + i32.const 0 + local.get 467 + i64.store offset=467 align=1 + i32.const 0 + local.get 468 + i64.store offset=468 align=1 + i32.const 0 + local.get 469 + i64.store offset=469 align=1 + i32.const 0 + local.get 470 + i64.store offset=470 align=1 + i32.const 0 + local.get 471 + i64.store offset=471 align=1 + i32.const 0 + local.get 472 + i64.store offset=472 align=1 + i32.const 0 + local.get 473 + i64.store offset=473 align=1 + i32.const 0 + local.get 474 + i64.store offset=474 align=1 + i32.const 0 + local.get 475 + i64.store offset=475 align=1 + i32.const 0 + local.get 476 + i64.store offset=476 align=1 + i32.const 0 + local.get 477 + i64.store offset=477 align=1 + i32.const 0 + local.get 478 + i64.store offset=478 align=1 + i32.const 0 + local.get 479 + i64.store offset=479 align=1 + i32.const 0 + local.get 480 + i64.store offset=480 align=1 + i32.const 0 + local.get 481 + i64.store offset=481 align=1 + i32.const 0 + local.get 482 + i64.store offset=482 align=1 + i32.const 0 + local.get 483 + i64.store offset=483 align=1 + i32.const 0 + local.get 484 + i64.store offset=484 align=1 + i32.const 0 + local.get 485 + i64.store offset=485 align=1 + i32.const 0 + local.get 486 + i64.store offset=486 align=1 + i32.const 0 + local.get 487 + i64.store offset=487 align=1 + i32.const 0 + local.get 488 + i64.store offset=488 align=1 + i32.const 0 + local.get 489 + i64.store offset=489 align=1 + i32.const 0 + local.get 490 + i64.store offset=490 align=1 + i32.const 0 + local.get 491 + i64.store offset=491 align=1 + i32.const 0 + local.get 492 + i64.store offset=492 align=1 + i32.const 0 + local.get 493 + i64.store offset=493 align=1 + i32.const 0 + local.get 494 + i64.store offset=494 align=1 + i32.const 0 + local.get 495 + i64.store offset=495 align=1 + i32.const 0 + local.get 496 + i64.store offset=496 align=1 + i32.const 0 + local.get 497 + i64.store offset=497 align=1 + i32.const 0 + local.get 498 + i64.store offset=498 align=1 + i32.const 0 + local.get 499 + i64.store offset=499 align=1 + i32.const 0 + local.get 500 + i64.store offset=500 align=1 + i32.const 0 + local.get 501 + i64.store offset=501 align=1 + i32.const 0 + local.get 502 + i64.store offset=502 align=1 + i32.const 0 + local.get 503 + i64.store offset=503 align=1 + i32.const 0 + local.get 504 + i64.store offset=504 align=1 + i32.const 0 + local.get 505 + i64.store offset=505 align=1 + i32.const 0 + local.get 506 + i64.store offset=506 align=1 + i32.const 0 + local.get 507 + i64.store offset=507 align=1 + i32.const 0 + local.get 508 + i64.store offset=508 align=1 + i32.const 0 + local.get 509 + i64.store offset=509 align=1 + i32.const 0 + local.get 510 + i64.store offset=510 align=1 + i32.const 0 + local.get 511 + i64.store offset=511 align=1 + i32.const 0 + local.get 512 + i64.store offset=512 align=1 + i32.const 0 + local.get 513 + i64.store offset=513 align=1 + i32.const 0 + local.get 514 + i64.store offset=514 align=1 + i32.const 0 + local.get 515 + i64.store offset=515 align=1 + i32.const 0 + local.get 516 + i64.store offset=516 align=1 + i32.const 0 + local.get 517 + i64.store offset=517 align=1 + i32.const 0 + local.get 518 + i64.store offset=518 align=1 + i32.const 0 + local.get 519 + i64.store offset=519 align=1 + i32.const 0 + local.get 520 + i64.store offset=520 align=1 + i32.const 0 + local.get 521 + i64.store offset=521 align=1 + i32.const 0 + local.get 522 + i64.store offset=522 align=1 + i32.const 0 + local.get 523 + i64.store offset=523 align=1 + i32.const 0 + local.get 524 + i64.store offset=524 align=1 + i32.const 0 + local.get 525 + i64.store offset=525 align=1 + i32.const 0 + local.get 526 + i64.store offset=526 align=1 + i32.const 0 + local.get 527 + i64.store offset=527 align=1 + i32.const 0 + local.get 528 + i64.store offset=528 align=1 + i32.const 0 + local.get 529 + i64.store offset=529 align=1 + i32.const 0 + local.get 530 + i64.store offset=530 align=1 + i32.const 0 + local.get 531 + i64.store offset=531 align=1 + i32.const 0 + local.get 532 + i64.store offset=532 align=1 + i32.const 0 + local.get 533 + i64.store offset=533 align=1 + i32.const 0 + local.get 534 + i64.store offset=534 align=1 + i32.const 0 + local.get 535 + i64.store offset=535 align=1 + i32.const 0 + local.get 536 + i64.store offset=536 align=1 + i32.const 0 + local.get 537 + i64.store offset=537 align=1 + i32.const 0 + local.get 538 + i64.store offset=538 align=1 + i32.const 0 + local.get 539 + i64.store offset=539 align=1 + i32.const 0 + local.get 540 + i64.store offset=540 align=1 + i32.const 0 + local.get 541 + i64.store offset=541 align=1 + i32.const 0 + local.get 542 + i64.store offset=542 align=1 + i32.const 0 + local.get 543 + i64.store offset=543 align=1 + i32.const 0 + local.get 544 + i64.store offset=544 align=1 + i32.const 0 + local.get 545 + i64.store offset=545 align=1 + i32.const 0 + local.get 546 + i64.store offset=546 align=1 + i32.const 0 + local.get 547 + i64.store offset=547 align=1 + i32.const 0 + local.get 548 + i64.store offset=548 align=1 + i32.const 0 + local.get 549 + i64.store offset=549 align=1 + i32.const 0 + local.get 550 + i64.store offset=550 align=1 + i32.const 0 + local.get 551 + i64.store offset=551 align=1 + i32.const 0 + local.get 552 + i64.store offset=552 align=1 + i32.const 0 + local.get 553 + i64.store offset=553 align=1 + i32.const 0 + local.get 554 + i64.store offset=554 align=1 + i32.const 0 + local.get 555 + i64.store offset=555 align=1 + i32.const 0 + local.get 556 + i64.store offset=556 align=1 + i32.const 0 + local.get 557 + i64.store offset=557 align=1 + i32.const 0 + local.get 558 + i64.store offset=558 align=1 + i32.const 0 + local.get 559 + i64.store offset=559 align=1 + i32.const 0 + local.get 560 + i64.store offset=560 align=1 + i32.const 0 + local.get 561 + i64.store offset=561 align=1 + i32.const 0 + local.get 562 + i64.store offset=562 align=1 + i32.const 0 + local.get 563 + i64.store offset=563 align=1 + i32.const 0 + local.get 564 + i64.store offset=564 align=1 + i32.const 0 + local.get 565 + i64.store offset=565 align=1 + i32.const 0 + local.get 566 + i64.store offset=566 align=1 + i32.const 0 + local.get 567 + i64.store offset=567 align=1 + i32.const 0 + local.get 568 + i64.store offset=568 align=1 + i32.const 0 + local.get 569 + i64.store offset=569 align=1 + i32.const 0 + local.get 570 + i64.store offset=570 align=1 + i32.const 0 + local.get 571 + i64.store offset=571 align=1 + i32.const 0 + local.get 572 + i64.store offset=572 align=1 + i32.const 0 + local.get 573 + i64.store offset=573 align=1 + i32.const 0 + local.get 574 + i64.store offset=574 align=1 + i32.const 0 + local.get 575 + i64.store offset=575 align=1 + i32.const 0 + local.get 576 + i64.store offset=576 align=1 + i32.const 0 + local.get 577 + i64.store offset=577 align=1 + i32.const 0 + local.get 578 + i64.store offset=578 align=1 + i32.const 0 + local.get 579 + i64.store offset=579 align=1 + i32.const 0 + local.get 580 + i64.store offset=580 align=1 + i32.const 0 + local.get 581 + i64.store offset=581 align=1 + i32.const 0 + local.get 582 + i64.store offset=582 align=1 + i32.const 0 + local.get 583 + i64.store offset=583 align=1 + i32.const 0 + local.get 584 + i64.store offset=584 align=1 + i32.const 0 + local.get 585 + i64.store offset=585 align=1 + i32.const 0 + local.get 586 + i64.store offset=586 align=1 + i32.const 0 + local.get 587 + i64.store offset=587 align=1 + i32.const 0 + local.get 588 + i64.store offset=588 align=1 + i32.const 0 + local.get 589 + i64.store offset=589 align=1 + i32.const 0 + local.get 590 + i64.store offset=590 align=1 + i32.const 0 + local.get 591 + i64.store offset=591 align=1 + i32.const 0 + local.get 592 + i64.store offset=592 align=1 + i32.const 0 + local.get 593 + i64.store offset=593 align=1 + i32.const 0 + local.get 594 + i64.store offset=594 align=1 + i32.const 0 + local.get 595 + i64.store offset=595 align=1 + i32.const 0 + local.get 596 + i64.store offset=596 align=1 + i32.const 0 + local.get 597 + i64.store offset=597 align=1 + i32.const 0 + local.get 598 + i64.store offset=598 align=1 + i32.const 0 + local.get 599 + i64.store offset=599 align=1 + i32.const 0 + local.get 600 + i64.store offset=600 align=1 + i32.const 0 + local.get 601 + i64.store offset=601 align=1 + i32.const 0 + local.get 602 + i64.store offset=602 align=1 + i32.const 0 + local.get 603 + i64.store offset=603 align=1 + i32.const 0 + local.get 604 + i64.store offset=604 align=1 + i32.const 0 + local.get 605 + i64.store offset=605 align=1 + i32.const 0 + local.get 606 + i64.store offset=606 align=1 + i32.const 0 + local.get 607 + i64.store offset=607 align=1 + i32.const 0 + local.get 608 + i64.store offset=608 align=1 + i32.const 0 + local.get 609 + i64.store offset=609 align=1 + i32.const 0 + local.get 610 + i64.store offset=610 align=1 + i32.const 0 + local.get 611 + i64.store offset=611 align=1 + i32.const 0 + local.get 612 + i64.store offset=612 align=1 + i32.const 0 + local.get 613 + i64.store offset=613 align=1 + i32.const 0 + local.get 614 + i64.store offset=614 align=1 + i32.const 0 + local.get 615 + i64.store offset=615 align=1 + i32.const 0 + local.get 616 + i64.store offset=616 align=1 + i32.const 0 + local.get 617 + i64.store offset=617 align=1 + i32.const 0 + local.get 618 + i64.store offset=618 align=1 + i32.const 0 + local.get 619 + i64.store offset=619 align=1 + i32.const 0 + local.get 620 + i64.store offset=620 align=1 + i32.const 0 + local.get 621 + i64.store offset=621 align=1 + i32.const 0 + local.get 622 + i64.store offset=622 align=1 + i32.const 0 + local.get 623 + i64.store offset=623 align=1 + i32.const 0 + local.get 624 + i64.store offset=624 align=1 + i32.const 0 + local.get 625 + i64.store offset=625 align=1 + i32.const 0 + local.get 626 + i64.store offset=626 align=1 + i32.const 0 + local.get 627 + i64.store offset=627 align=1 + i32.const 0 + local.get 628 + i64.store offset=628 align=1 + i32.const 0 + local.get 629 + i64.store offset=629 align=1 + i32.const 0 + local.get 630 + i64.store offset=630 align=1 + i32.const 0 + local.get 631 + i64.store offset=631 align=1 + i32.const 0 + local.get 632 + i64.store offset=632 align=1 + i32.const 0 + local.get 633 + i64.store offset=633 align=1 + i32.const 0 + local.get 634 + i64.store offset=634 align=1 + i32.const 0 + local.get 635 + i64.store offset=635 align=1 + i32.const 0 + local.get 636 + i64.store offset=636 align=1 + i32.const 0 + local.get 637 + i64.store offset=637 align=1 + i32.const 0 + local.get 638 + i64.store offset=638 align=1 + i32.const 0 + local.get 639 + i64.store offset=639 align=1 + i32.const 0 + local.get 640 + i64.store offset=640 align=1 + i32.const 0 + local.get 641 + i64.store offset=641 align=1 + i32.const 0 + local.get 642 + i64.store offset=642 align=1 + i32.const 0 + local.get 643 + i64.store offset=643 align=1 + i32.const 0 + local.get 644 + i64.store offset=644 align=1 + i32.const 0 + local.get 645 + i64.store offset=645 align=1 + i32.const 0 + local.get 646 + i64.store offset=646 align=1 + i32.const 0 + local.get 647 + i64.store offset=647 align=1 + i32.const 0 + local.get 648 + i64.store offset=648 align=1 + i32.const 0 + local.get 649 + i64.store offset=649 align=1 + i32.const 0 + local.get 650 + i64.store offset=650 align=1 + i32.const 0 + local.get 651 + i64.store offset=651 align=1 + i32.const 0 + local.get 652 + i64.store offset=652 align=1 + i32.const 0 + local.get 653 + i64.store offset=653 align=1 + i32.const 0 + local.get 654 + i64.store offset=654 align=1 + i32.const 0 + local.get 655 + i64.store offset=655 align=1 + i32.const 0 + local.get 656 + i64.store offset=656 align=1 + i32.const 0 + local.get 657 + i64.store offset=657 align=1 + i32.const 0 + local.get 658 + i64.store offset=658 align=1 + i32.const 0 + local.get 659 + i64.store offset=659 align=1 + i32.const 0 + local.get 660 + i64.store offset=660 align=1 + i32.const 0 + local.get 661 + i64.store offset=661 align=1 + i32.const 0 + local.get 662 + i64.store offset=662 align=1 + i32.const 0 + local.get 663 + i64.store offset=663 align=1 + i32.const 0 + local.get 664 + i64.store offset=664 align=1 + i32.const 0 + local.get 665 + i64.store offset=665 align=1 + i32.const 0 + local.get 666 + i64.store offset=666 align=1 + i32.const 0 + local.get 667 + i64.store offset=667 align=1 + i32.const 0 + local.get 668 + i64.store offset=668 align=1 + i32.const 0 + local.get 669 + i64.store offset=669 align=1 + i32.const 0 + local.get 670 + i64.store offset=670 align=1 + i32.const 0 + local.get 671 + i64.store offset=671 align=1 + i32.const 0 + local.get 672 + i64.store offset=672 align=1 + i32.const 0 + local.get 673 + i64.store offset=673 align=1 + i32.const 0 + local.get 674 + i64.store offset=674 align=1 + i32.const 0 + local.get 675 + i64.store offset=675 align=1 + i32.const 0 + local.get 676 + i64.store offset=676 align=1 + i32.const 0 + local.get 677 + i64.store offset=677 align=1 + i32.const 0 + local.get 678 + i64.store offset=678 align=1 + i32.const 0 + local.get 679 + i64.store offset=679 align=1 + i32.const 0 + local.get 680 + i64.store offset=680 align=1 + i32.const 0 + local.get 681 + i64.store offset=681 align=1 + i32.const 0 + local.get 682 + i64.store offset=682 align=1 + i32.const 0 + local.get 683 + i64.store offset=683 align=1 + i32.const 0 + local.get 684 + i64.store offset=684 align=1 + i32.const 0 + local.get 685 + i64.store offset=685 align=1 + i32.const 0 + local.get 686 + i64.store offset=686 align=1 + i32.const 0 + local.get 687 + i64.store offset=687 align=1 + i32.const 0 + local.get 688 + i64.store offset=688 align=1 + i32.const 0 + local.get 689 + i64.store offset=689 align=1 + i32.const 0 + local.get 690 + i64.store offset=690 align=1 + i32.const 0 + local.get 691 + i64.store offset=691 align=1 + i32.const 0 + local.get 692 + i64.store offset=692 align=1 + i32.const 0 + local.get 693 + i64.store offset=693 align=1 + i32.const 0 + local.get 694 + i64.store offset=694 align=1 + i32.const 0 + local.get 695 + i64.store offset=695 align=1 + i32.const 0 + local.get 696 + i64.store offset=696 align=1 + i32.const 0 + local.get 697 + i64.store offset=697 align=1 + i32.const 0 + local.get 698 + i64.store offset=698 align=1 + i32.const 0 + local.get 699 + i64.store offset=699 align=1 + i32.const 0 + local.get 700 + i64.store offset=700 align=1 + i32.const 0 + local.get 701 + i64.store offset=701 align=1 + i32.const 0 + local.get 702 + i64.store offset=702 align=1 + i32.const 0 + local.get 703 + i64.store offset=703 align=1 + i32.const 0 + local.get 704 + i64.store offset=704 align=1 + i32.const 0 + local.get 705 + i64.store offset=705 align=1 + i32.const 0 + local.get 706 + i64.store offset=706 align=1 + i32.const 0 + local.get 707 + i64.store offset=707 align=1 + i32.const 0 + local.get 708 + i64.store offset=708 align=1 + i32.const 0 + local.get 709 + i64.store offset=709 align=1 + i32.const 0 + local.get 710 + i64.store offset=710 align=1 + i32.const 0 + local.get 711 + i64.store offset=711 align=1 + i32.const 0 + local.get 712 + i64.store offset=712 align=1 + i32.const 0 + local.get 713 + i64.store offset=713 align=1 + i32.const 0 + local.get 714 + i64.store offset=714 align=1 + i32.const 0 + local.get 715 + i64.store offset=715 align=1 + i32.const 0 + local.get 716 + i64.store offset=716 align=1 + i32.const 0 + local.get 717 + i64.store offset=717 align=1 + i32.const 0 + local.get 718 + i64.store offset=718 align=1 + i32.const 0 + local.get 719 + i64.store offset=719 align=1 + i32.const 0 + local.get 720 + i64.store offset=720 align=1 + i32.const 0 + local.get 721 + i64.store offset=721 align=1 + i32.const 0 + local.get 722 + i64.store offset=722 align=1 + i32.const 0 + local.get 723 + i64.store offset=723 align=1 + i32.const 0 + local.get 724 + i64.store offset=724 align=1 + i32.const 0 + local.get 725 + i64.store offset=725 align=1 + i32.const 0 + local.get 726 + i64.store offset=726 align=1 + i32.const 0 + local.get 727 + i64.store offset=727 align=1 + i32.const 0 + local.get 728 + i64.store offset=728 align=1 + i32.const 0 + local.get 729 + i64.store offset=729 align=1 + i32.const 0 + local.get 730 + i64.store offset=730 align=1 + i32.const 0 + local.get 731 + i64.store offset=731 align=1 + i32.const 0 + local.get 732 + i64.store offset=732 align=1 + i32.const 0 + local.get 733 + i64.store offset=733 align=1 + i32.const 0 + local.get 734 + i64.store offset=734 align=1 + i32.const 0 + local.get 735 + i64.store offset=735 align=1 + i32.const 0 + local.get 736 + i64.store offset=736 align=1 + i32.const 0 + local.get 737 + i64.store offset=737 align=1 + i32.const 0 + local.get 738 + i64.store offset=738 align=1 + i32.const 0 + local.get 739 + i64.store offset=739 align=1 + i32.const 0 + local.get 740 + i64.store offset=740 align=1 + i32.const 0 + local.get 741 + i64.store offset=741 align=1 + i32.const 0 + local.get 742 + i64.store offset=742 align=1 + i32.const 0 + local.get 743 + i64.store offset=743 align=1 + i32.const 0 + local.get 744 + i64.store offset=744 align=1 + i32.const 0 + local.get 745 + i64.store offset=745 align=1 + i32.const 0 + local.get 746 + i64.store offset=746 align=1 + i32.const 0 + local.get 747 + i64.store offset=747 align=1 + i32.const 0 + local.get 748 + i64.store offset=748 align=1 + i32.const 0 + local.get 749 + i64.store offset=749 align=1 + i32.const 0 + local.get 750 + i64.store offset=750 align=1 + i32.const 0 + local.get 751 + i64.store offset=751 align=1 + i32.const 0 + local.get 752 + i64.store offset=752 align=1 + i32.const 0 + local.get 753 + i64.store offset=753 align=1 + i32.const 0 + local.get 754 + i64.store offset=754 align=1 + i32.const 0 + local.get 755 + i64.store offset=755 align=1 + i32.const 0 + local.get 756 + i64.store offset=756 align=1 + i32.const 0 + local.get 757 + i64.store offset=757 align=1 + i32.const 0 + local.get 758 + i64.store offset=758 align=1 + i32.const 0 + local.get 759 + i64.store offset=759 align=1 + i32.const 0 + local.get 760 + i64.store offset=760 align=1 + i32.const 0 + local.get 761 + i64.store offset=761 align=1 + i32.const 0 + local.get 762 + i64.store offset=762 align=1 + i32.const 0 + local.get 763 + i64.store offset=763 align=1 + i32.const 0 + local.get 764 + i64.store offset=764 align=1 + i32.const 0 + local.get 765 + i64.store offset=765 align=1 + i32.const 0 + local.get 766 + i64.store offset=766 align=1 + i32.const 0 + local.get 767 + i64.store offset=767 align=1 + i32.const 0 + local.get 768 + i64.store offset=768 align=1 + i32.const 0 + local.get 769 + i64.store offset=769 align=1 + i32.const 0 + local.get 770 + i64.store offset=770 align=1 + i32.const 0 + local.get 771 + i64.store offset=771 align=1 + i32.const 0 + local.get 772 + i64.store offset=772 align=1 + i32.const 0 + local.get 773 + i64.store offset=773 align=1 + i32.const 0 + local.get 774 + i64.store offset=774 align=1 + i32.const 0 + local.get 775 + i64.store offset=775 align=1 + i32.const 0 + local.get 776 + i64.store offset=776 align=1 + i32.const 0 + local.get 777 + i64.store offset=777 align=1 + i32.const 0 + local.get 778 + i64.store offset=778 align=1 + i32.const 0 + local.get 779 + i64.store offset=779 align=1 + i32.const 0 + local.get 780 + i64.store offset=780 align=1 + i32.const 0 + local.get 781 + i64.store offset=781 align=1 + i32.const 0 + local.get 782 + i64.store offset=782 align=1 + i32.const 0 + local.get 783 + i64.store offset=783 align=1 + i32.const 0 + local.get 784 + i64.store offset=784 align=1 + i32.const 0 + local.get 785 + i64.store offset=785 align=1 + i32.const 0 + local.get 786 + i64.store offset=786 align=1 + i32.const 0 + local.get 787 + i64.store offset=787 align=1 + i32.const 0 + local.get 788 + i64.store offset=788 align=1 + i32.const 0 + local.get 789 + i64.store offset=789 align=1 + i32.const 0 + local.get 790 + i64.store offset=790 align=1 + i32.const 0 + local.get 791 + i64.store offset=791 align=1 + i32.const 0 + local.get 792 + i64.store offset=792 align=1 + i32.const 0 + local.get 793 + i64.store offset=793 align=1 + i32.const 0 + local.get 794 + i64.store offset=794 align=1 + i32.const 0 + local.get 795 + i64.store offset=795 align=1 + i32.const 0 + local.get 796 + i64.store offset=796 align=1 + i32.const 0 + local.get 797 + i64.store offset=797 align=1 + i32.const 0 + local.get 798 + i64.store offset=798 align=1 + i32.const 0 + local.get 799 + i64.store offset=799 align=1 + i32.const 0 + local.get 800 + i64.store offset=800 align=1 + i32.const 0 + local.get 801 + i64.store offset=801 align=1 + i32.const 0 + local.get 802 + i64.store offset=802 align=1 + i32.const 0 + local.get 803 + i64.store offset=803 align=1 + i32.const 0 + local.get 804 + i64.store offset=804 align=1 + i32.const 0 + local.get 805 + i64.store offset=805 align=1 + i32.const 0 + local.get 806 + i64.store offset=806 align=1 + i32.const 0 + local.get 807 + i64.store offset=807 align=1 + i32.const 0 + local.get 808 + i64.store offset=808 align=1 + i32.const 0 + local.get 809 + i64.store offset=809 align=1 + i32.const 0 + local.get 810 + i64.store offset=810 align=1 + i32.const 0 + local.get 811 + i64.store offset=811 align=1 + i32.const 0 + local.get 812 + i64.store offset=812 align=1 + i32.const 0 + local.get 813 + i64.store offset=813 align=1 + i32.const 0 + local.get 814 + i64.store offset=814 align=1 + i32.const 0 + local.get 815 + i64.store offset=815 align=1 + i32.const 0 + local.get 816 + i64.store offset=816 align=1 + i32.const 0 + local.get 817 + i64.store offset=817 align=1 + i32.const 0 + local.get 818 + i64.store offset=818 align=1 + i32.const 0 + local.get 819 + i64.store offset=819 align=1 + i32.const 0 + local.get 820 + i64.store offset=820 align=1 + i32.const 0 + local.get 821 + i64.store offset=821 align=1 + i32.const 0 + local.get 822 + i64.store offset=822 align=1 + i32.const 0 + local.get 823 + i64.store offset=823 align=1 + i32.const 0 + local.get 824 + i64.store offset=824 align=1 + i32.const 0 + local.get 825 + i64.store offset=825 align=1 + i32.const 0 + local.get 826 + i64.store offset=826 align=1 + i32.const 0 + local.get 827 + i64.store offset=827 align=1 + i32.const 0 + local.get 828 + i64.store offset=828 align=1 + i32.const 0 + local.get 829 + i64.store offset=829 align=1 + i32.const 0 + local.get 830 + i64.store offset=830 align=1 + i32.const 0 + local.get 831 + i64.store offset=831 align=1 + i32.const 0 + local.get 832 + i64.store offset=832 align=1 + i32.const 0 + local.get 833 + i64.store offset=833 align=1 + i32.const 0 + local.get 834 + i64.store offset=834 align=1 + i32.const 0 + local.get 835 + i64.store offset=835 align=1 + i32.const 0 + local.get 836 + i64.store offset=836 align=1 + i32.const 0 + local.get 837 + i64.store offset=837 align=1 + i32.const 0 + local.get 838 + i64.store offset=838 align=1 + i32.const 0 + local.get 839 + i64.store offset=839 align=1 + i32.const 0 + local.get 840 + i64.store offset=840 align=1 + i32.const 0 + local.get 841 + i64.store offset=841 align=1 + i32.const 0 + local.get 842 + i64.store offset=842 align=1 + i32.const 0 + local.get 843 + i64.store offset=843 align=1 + i32.const 0 + local.get 844 + i64.store offset=844 align=1 + i32.const 0 + local.get 845 + i64.store offset=845 align=1 + i32.const 0 + local.get 846 + i64.store offset=846 align=1 + i32.const 0 + local.get 847 + i64.store offset=847 align=1 + i32.const 0 + local.get 848 + i64.store offset=848 align=1 + i32.const 0 + local.get 849 + i64.store offset=849 align=1 + i32.const 0 + local.get 850 + i64.store offset=850 align=1 + i32.const 0 + local.get 851 + i64.store offset=851 align=1 + i32.const 0 + local.get 852 + i64.store offset=852 align=1 + i32.const 0 + local.get 853 + i64.store offset=853 align=1 + i32.const 0 + local.get 854 + i64.store offset=854 align=1 + i32.const 0 + local.get 855 + i64.store offset=855 align=1 + i32.const 0 + local.get 856 + i64.store offset=856 align=1 + i32.const 0 + local.get 857 + i64.store offset=857 align=1 + i32.const 0 + local.get 858 + i64.store offset=858 align=1 + i32.const 0 + local.get 859 + i64.store offset=859 align=1 + i32.const 0 + local.get 860 + i64.store offset=860 align=1 + i32.const 0 + local.get 861 + i64.store offset=861 align=1 + i32.const 0 + local.get 862 + i64.store offset=862 align=1 + i32.const 0 + local.get 863 + i64.store offset=863 align=1 + i32.const 0 + local.get 864 + i64.store offset=864 align=1 + i32.const 0 + local.get 865 + i64.store offset=865 align=1 + i32.const 0 + local.get 866 + i64.store offset=866 align=1 + i32.const 0 + local.get 867 + i64.store offset=867 align=1 + i32.const 0 + local.get 868 + i64.store offset=868 align=1 + i32.const 0 + local.get 869 + i64.store offset=869 align=1 + i32.const 0 + local.get 870 + i64.store offset=870 align=1 + i32.const 0 + local.get 871 + i64.store offset=871 align=1 + i32.const 0 + local.get 872 + i64.store offset=872 align=1 + i32.const 0 + local.get 873 + i64.store offset=873 align=1 + i32.const 0 + local.get 874 + i64.store offset=874 align=1 + i32.const 0 + local.get 875 + i64.store offset=875 align=1 + i32.const 0 + local.get 876 + i64.store offset=876 align=1 + i32.const 0 + local.get 877 + i64.store offset=877 align=1 + i32.const 0 + local.get 878 + i64.store offset=878 align=1 + i32.const 0 + local.get 879 + i64.store offset=879 align=1 + i32.const 0 + local.get 880 + i64.store offset=880 align=1 + i32.const 0 + local.get 881 + i64.store offset=881 align=1 + i32.const 0 + local.get 882 + i64.store offset=882 align=1 + i32.const 0 + local.get 883 + i64.store offset=883 align=1 + i32.const 0 + local.get 884 + i64.store offset=884 align=1 + i32.const 0 + local.get 885 + i64.store offset=885 align=1 + i32.const 0 + local.get 886 + i64.store offset=886 align=1 + i32.const 0 + local.get 887 + i64.store offset=887 align=1 + i32.const 0 + local.get 888 + i64.store offset=888 align=1 + i32.const 0 + local.get 889 + i64.store offset=889 align=1 + i32.const 0 + local.get 890 + i64.store offset=890 align=1 + i32.const 0 + local.get 891 + i64.store offset=891 align=1 + i32.const 0 + local.get 892 + i64.store offset=892 align=1 + i32.const 0 + local.get 893 + i64.store offset=893 align=1 + i32.const 0 + local.get 894 + i64.store offset=894 align=1 + i32.const 0 + local.get 895 + i64.store offset=895 align=1 + i32.const 0 + local.get 896 + i64.store offset=896 align=1 + i32.const 0 + local.get 897 + i64.store offset=897 align=1 + i32.const 0 + local.get 898 + i64.store offset=898 align=1 + i32.const 0 + local.get 899 + i64.store offset=899 align=1 + i32.const 0 + local.get 900 + i64.store offset=900 align=1 + i32.const 0 + local.get 901 + i64.store offset=901 align=1 + i32.const 0 + local.get 902 + i64.store offset=902 align=1 + i32.const 0 + local.get 903 + i64.store offset=903 align=1 + i32.const 0 + local.get 904 + i64.store offset=904 align=1 + i32.const 0 + local.get 905 + i64.store offset=905 align=1 + i32.const 0 + local.get 906 + i64.store offset=906 align=1 + i32.const 0 + local.get 907 + i64.store offset=907 align=1 + i32.const 0 + local.get 908 + i64.store offset=908 align=1 + i32.const 0 + local.get 909 + i64.store offset=909 align=1 + i32.const 0 + local.get 910 + i64.store offset=910 align=1 + i32.const 0 + local.get 911 + i64.store offset=911 align=1 + i32.const 0 + local.get 912 + i64.store offset=912 align=1 + i32.const 0 + local.get 913 + i64.store offset=913 align=1 + i32.const 0 + local.get 914 + i64.store offset=914 align=1 + i32.const 0 + local.get 915 + i64.store offset=915 align=1 + i32.const 0 + local.get 916 + i64.store offset=916 align=1 + i32.const 0 + local.get 917 + i64.store offset=917 align=1 + i32.const 0 + local.get 918 + i64.store offset=918 align=1 + i32.const 0 + local.get 919 + i64.store offset=919 align=1 + i32.const 0 + local.get 920 + i64.store offset=920 align=1 + i32.const 0 + local.get 921 + i64.store offset=921 align=1 + i32.const 0 + local.get 922 + i64.store offset=922 align=1 + i32.const 0 + local.get 923 + i64.store offset=923 align=1 + i32.const 0 + local.get 924 + i64.store offset=924 align=1 + i32.const 0 + local.get 925 + i64.store offset=925 align=1 + i32.const 0 + local.get 926 + i64.store offset=926 align=1 + i32.const 0 + local.get 927 + i64.store offset=927 align=1 + i32.const 0 + local.get 928 + i64.store offset=928 align=1 + i32.const 0 + local.get 929 + i64.store offset=929 align=1 + i32.const 0 + local.get 930 + i64.store offset=930 align=1 + i32.const 0 + local.get 931 + i64.store offset=931 align=1 + i32.const 0 + local.get 932 + i64.store offset=932 align=1 + i32.const 0 + local.get 933 + i64.store offset=933 align=1 + i32.const 0 + local.get 934 + i64.store offset=934 align=1 + i32.const 0 + local.get 935 + i64.store offset=935 align=1 + i32.const 0 + local.get 936 + i64.store offset=936 align=1 + i32.const 0 + local.get 937 + i64.store offset=937 align=1 + i32.const 0 + local.get 938 + i64.store offset=938 align=1 + i32.const 0 + local.get 939 + i64.store offset=939 align=1 + i32.const 0 + local.get 940 + i64.store offset=940 align=1 + i32.const 0 + local.get 941 + i64.store offset=941 align=1 + i32.const 0 + local.get 942 + i64.store offset=942 align=1 + i32.const 0 + local.get 943 + i64.store offset=943 align=1 + i32.const 0 + local.get 944 + i64.store offset=944 align=1 + i32.const 0 + local.get 945 + i64.store offset=945 align=1 + i32.const 0 + local.get 946 + i64.store offset=946 align=1 + i32.const 0 + local.get 947 + i64.store offset=947 align=1 + i32.const 0 + local.get 948 + i64.store offset=948 align=1 + i32.const 0 + local.get 949 + i64.store offset=949 align=1 + i32.const 0 + local.get 950 + i64.store offset=950 align=1 + i32.const 0 + local.get 951 + i64.store offset=951 align=1 + i32.const 0 + local.get 952 + i64.store offset=952 align=1 + i32.const 0 + local.get 953 + i64.store offset=953 align=1 + i32.const 0 + local.get 954 + i64.store offset=954 align=1 + i32.const 0 + local.get 955 + i64.store offset=955 align=1 + i32.const 0 + local.get 956 + i64.store offset=956 align=1 + i32.const 0 + local.get 957 + i64.store offset=957 align=1 + i32.const 0 + local.get 958 + i64.store offset=958 align=1 + i32.const 0 + local.get 959 + i64.store offset=959 align=1 + i32.const 0 + local.get 960 + i64.store offset=960 align=1 + i32.const 0 + local.get 961 + i64.store offset=961 align=1 + i32.const 0 + local.get 962 + i64.store offset=962 align=1 + i32.const 0 + local.get 963 + i64.store offset=963 align=1 + i32.const 0 + local.get 964 + i64.store offset=964 align=1 + i32.const 0 + local.get 965 + i64.store offset=965 align=1 + i32.const 0 + local.get 966 + i64.store offset=966 align=1 + i32.const 0 + local.get 967 + i64.store offset=967 align=1 + i32.const 0 + local.get 968 + i64.store offset=968 align=1 + i32.const 0 + local.get 969 + i64.store offset=969 align=1 + i32.const 0 + local.get 970 + i64.store offset=970 align=1 + i32.const 0 + local.get 971 + i64.store offset=971 align=1 + i32.const 0 + local.get 972 + i64.store offset=972 align=1 + i32.const 0 + local.get 973 + i64.store offset=973 align=1 + i32.const 0 + local.get 974 + i64.store offset=974 align=1 + i32.const 0 + local.get 975 + i64.store offset=975 align=1 + i32.const 0 + local.get 976 + i64.store offset=976 align=1 + i32.const 0 + local.get 977 + i64.store offset=977 align=1 + i32.const 0 + local.get 978 + i64.store offset=978 align=1 + i32.const 0 + local.get 979 + i64.store offset=979 align=1 + i32.const 0 + local.get 980 + i64.store offset=980 align=1 + i32.const 0 + local.get 981 + i64.store offset=981 align=1 + i32.const 0 + local.get 982 + i64.store offset=982 align=1 + i32.const 0 + local.get 983 + i64.store offset=983 align=1 + i32.const 0 + local.get 984 + i64.store offset=984 align=1 + i32.const 0 + local.get 985 + i64.store offset=985 align=1 + i32.const 0 + local.get 986 + i64.store offset=986 align=1 + i32.const 0 + local.get 987 + i64.store offset=987 align=1 + i32.const 0 + local.get 988 + i64.store offset=988 align=1 + i32.const 0 + local.get 989 + i64.store offset=989 align=1 + i32.const 0 + local.get 990 + i64.store offset=990 align=1 + i32.const 0 + local.get 991 + i64.store offset=991 align=1 + i32.const 0 + local.get 992 + i64.store offset=992 align=1 + i32.const 0 + local.get 993 + i64.store offset=993 align=1 + i32.const 0 + local.get 994 + i64.store offset=994 align=1 + i32.const 0 + local.get 995 + i64.store offset=995 align=1 + i32.const 0 + local.get 996 + i64.store offset=996 align=1 + i32.const 0 + local.get 997 + i64.store offset=997 align=1 + i32.const 0 + local.get 998 + i64.store offset=998 align=1 + i32.const 0 + local.get 999 + i64.store offset=999 align=1 + i32.const 0 + local.get 1000 + i64.store offset=1000 align=1 + i32.const 0 + local.get 1001 + i64.store offset=1001 align=1 + i32.const 0 + local.get 1002 + i64.store offset=1002 align=1 + i32.const 0 + local.get 1003 + i64.store offset=1003 align=1 + i32.const 0 + local.get 1004 + i64.store offset=1004 align=1 + i32.const 0 + local.get 1005 + i64.store offset=1005 align=1 + i32.const 0 + local.get 1006 + i64.store offset=1006 align=1 + i32.const 0 + local.get 1007 + i64.store offset=1007 align=1 + i32.const 0 + local.get 1008 + i64.store offset=1008 align=1 + i32.const 0 + local.get 1009 + i64.store offset=1009 align=1 + i32.const 0 + local.get 1010 + i64.store offset=1010 align=1 + i32.const 0 + local.get 1011 + i64.store offset=1011 align=1 + i32.const 0 + local.get 1012 + i64.store offset=1012 align=1 + i32.const 0 + local.get 1013 + i64.store offset=1013 align=1 + i32.const 0 + local.get 1014 + i64.store offset=1014 align=1 + i32.const 0 + local.get 1015 + i64.store offset=1015 align=1 + i32.const 0 + local.get 1016 + i64.store offset=1016 align=1 + i32.const 0 + local.get 1017 + i64.store offset=1017 align=1 + i32.const 0 + local.get 1018 + i64.store offset=1018 align=1 + i32.const 0 + local.get 1019 + i64.store offset=1019 align=1 + i32.const 0 + local.get 1020 + i64.store offset=1020 align=1 + i32.const 0 + local.get 1021 + i64.store offset=1021 align=1 + i32.const 0 + local.get 1022 + i64.store offset=1022 align=1 + i32.const 0 + local.get 1023 + i64.store offset=1023 align=1 + i32.const 0 + local.get 1024 + i64.store offset=1024 align=1 + i32.const 0 + local.get 1025 + i64.store offset=1025 align=1 + i32.const 0 + local.get 1026 + i64.store offset=1026 align=1 + i32.const 0 + local.get 1027 + i64.store offset=1027 align=1 + i32.const 0 + local.get 1028 + i64.store offset=1028 align=1 + i32.const 0 + local.get 1029 + i64.store offset=1029 align=1 + i32.const 0 + local.get 1030 + i64.store offset=1030 align=1 + i32.const 0 + local.get 1031 + i64.store offset=1031 align=1 + i32.const 0 + local.get 1032 + i64.store offset=1032 align=1 + i32.const 0 + local.get 1033 + i64.store offset=1033 align=1 + i32.const 0 + local.get 1034 + i64.store offset=1034 align=1 + i32.const 0 + local.get 1035 + i64.store offset=1035 align=1 + i32.const 0 + local.get 1036 + i64.store offset=1036 align=1 + i32.const 0 + local.get 1037 + i64.store offset=1037 align=1 + i32.const 0 + local.get 1038 + i64.store offset=1038 align=1 + i32.const 0 + local.get 1039 + i64.store offset=1039 align=1 + i32.const 0 + local.get 1040 + i64.store offset=1040 align=1 + i32.const 0 + local.get 1041 + i64.store offset=1041 align=1 + i32.const 0 + local.get 1042 + i64.store offset=1042 align=1 + i32.const 0 + local.get 1043 + i64.store offset=1043 align=1 + i32.const 0 + local.get 1044 + i64.store offset=1044 align=1 + i32.const 0 + local.get 1045 + i64.store offset=1045 align=1 + i32.const 0 + local.get 1046 + i64.store offset=1046 align=1 + i32.const 0 + local.get 1047 + i64.store offset=1047 align=1 + i32.const 0 + local.get 1048 + i64.store offset=1048 align=1 + i32.const 0 + local.get 1049 + i64.store offset=1049 align=1 + i32.const 0 + local.get 1050 + i64.store offset=1050 align=1 + i32.const 0 + local.get 1051 + i64.store offset=1051 align=1 + i32.const 0 + local.get 1052 + i64.store offset=1052 align=1 + i32.const 0 + local.get 1053 + i64.store offset=1053 align=1 + i32.const 0 + local.get 1054 + i64.store offset=1054 align=1 + i32.const 0 + local.get 1055 + i64.store offset=1055 align=1 + ) + (memory (;0;) 1) + (export "test-guard-page-skip" (func $test-guard-page-skip)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/stack.wast/0.print b/tests/snapshots/testsuite/stack.wast/0.print new file mode 100644 index 0000000000..a69f432067 --- /dev/null +++ b/tests/snapshots/testsuite/stack.wast/0.print @@ -0,0 +1,170 @@ +(module + (type (;0;) (func (param i64) (result i64))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func (;0;) (type 0) (param $n i64) (result i64) + (local $i i64) (local $res i64) + local.get $n + local.set $i + i64.const 1 + local.set $res + block $done ;; label = @1 + loop $loop ;; label = @2 + local.get $i + i64.const 0 + i64.eq + if ;; label = @3 + br 2 (;@1;) + else + local.get $i + local.get $res + i64.mul + local.set $res + local.get $i + i64.const 1 + i64.sub + local.set $i + end + br 0 (;@2;) + end + end + local.get $res + ) + (func (;1;) (type 0) (param $n i64) (result i64) + (local $i i64) (local $res i64) + local.get $n + local.set $i + i64.const 1 + local.set $res + block $done ;; label = @1 + loop $loop ;; label = @2 + local.get $i + i64.const 0 + i64.eq + if ;; label = @3 + br 2 (;@1;) + else + local.get $i + local.get $res + i64.mul + local.set $res + local.get $i + i64.const 1 + i64.sub + local.set $i + end + br 0 (;@2;) + end + end + local.get $res + ) + (func (;2;) (type 0) (param $n i64) (result i64) + (local $i i64) (local $res i64) + local.get $n + local.set $i + i64.const 1 + local.set $res + block $done ;; label = @1 + loop $loop ;; label = @2 + local.get $i + i64.const 0 + i64.eq + if $body ;; label = @3 + br 2 (;@1;) + else + local.get $i + local.get $res + i64.mul + local.set $res + local.get $i + i64.const 1 + i64.sub + local.set $i + end + br 0 (;@2;) + end + end + local.get $res + ) + (func (;3;) (type 0) (param $n i64) (result i64) + (local $i i64) (local $res i64) + local.get $n + local.set $i + i64.const 1 + local.set $res + block $done ;; label = @1 + loop $loop ;; label = @2 + local.get $i + i64.const 0 + i64.eq + if ;; label = @3 + br 2 (;@1;) + else + local.get $i + local.get $res + i64.mul + local.set $res + local.get $i + i64.const 1 + i64.sub + local.set $i + end + br 0 (;@2;) + end + end + local.get $res + ) + (func (;4;) (type 0) (param $n i64) (result i64) + (local $i i64) (local $res i64) + local.get $n + local.set $i + i64.const 1 + local.set $res + block $done ;; label = @1 + loop $loop ;; label = @2 + local.get $i + i64.const 0 + i64.eq + if ;; label = @3 + br 2 (;@1;) + else + local.get $i + local.get $res + i64.mul + local.set $res + local.get $i + i64.const 1 + i64.sub + local.set $i + end + br 0 (;@2;) + end + end + local.get $res + ) + (func $add_one_to_global (;5;) (type 1) (result i32) + (local i32) + i32.const 1 + global.get $temp + i32.add + global.set $temp + global.get $temp + ) + (func $add_one_to_global_and_drop (;6;) (type 2) + call $add_one_to_global + drop + ) + (func (;7;) (type 1) (result i32) + call $add_one_to_global + call $add_one_to_global + call $add_one_to_global_and_drop + i32.add + ) + (global $temp (;0;) (mut i32) i32.const 0) + (export "fac-expr" (func 0)) + (export "fac-stack" (func 1)) + (export "fac-stack-raw" (func 2)) + (export "fac-mixed" (func 3)) + (export "fac-mixed-raw" (func 4)) + (export "not-quite-a-tree" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/stack.wast/6.print b/tests/snapshots/testsuite/stack.wast/6.print new file mode 100644 index 0000000000..cf5bcedfbd --- /dev/null +++ b/tests/snapshots/testsuite/stack.wast/6.print @@ -0,0 +1,226 @@ +(module + (type $proc (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (result i32))) + (func (;0;) (type $proc) + block ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + loop ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + else + i32.const 0 + call_indirect (type $proc) + end + block ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + loop ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + else + i32.const 0 + call_indirect (type $proc) + end + block ;; label = @1 + i32.const 0 + i32.const 0 + call_indirect (type 1) + end + loop ;; label = @1 + i32.const 0 + i32.const 0 + call_indirect (type 1) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + i32.const 0 + call_indirect (type 1) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + i32.const 0 + call_indirect (type 1) + else + i32.const 0 + i32.const 0 + call_indirect (type 1) + end + block (result i32) ;; label = @1 + i32.const 0 + call_indirect (type 2) + end + drop + loop (result i32) ;; label = @1 + i32.const 0 + call_indirect (type 2) + end + drop + i32.const 0 + if (result i32) ;; label = @1 + i32.const 0 + call_indirect (type 2) + else + i32.const 0 + call_indirect (type 2) + end + drop + block ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + loop ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + else + i32.const 0 + call_indirect (type $proc) + end + block ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + loop ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + else + i32.const 0 + call_indirect (type $proc) + end + block ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + loop ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + else + i32.const 0 + call_indirect (type $proc) + end + block ;; label = @1 + i32.const 0 + i32.const 0 + call_indirect (type 1) + end + loop ;; label = @1 + i32.const 0 + i32.const 0 + call_indirect (type 1) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + i32.const 0 + call_indirect (type 1) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + i32.const 0 + call_indirect (type 1) + else + i32.const 0 + i32.const 0 + call_indirect (type 1) + end + block (result i32) ;; label = @1 + i32.const 0 + call_indirect (type 2) + end + drop + loop (result i32) ;; label = @1 + i32.const 0 + call_indirect (type 2) + end + drop + i32.const 0 + if (result i32) ;; label = @1 + i32.const 0 + call_indirect (type 2) + else + i32.const 0 + call_indirect (type 2) + end + drop + block ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + loop ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + if ;; label = @1 + i32.const 0 + call_indirect (type $proc) + else + i32.const 0 + call_indirect (type $proc) + end + i32.const 0 + call_indirect (type $proc) + ) + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/start.wast/15.print b/tests/snapshots/testsuite/start.wast/15.print new file mode 100644 index 0000000000..dd61d4f1b0 --- /dev/null +++ b/tests/snapshots/testsuite/start.wast/15.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32))) + (type (;1;) (func)) + (import "spectest" "print_i32" (func $print_i32 (;0;) (type 0))) + (func $main (;1;) (type 1) + i32.const 1 + call $print_i32 + ) + (start $main) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/start.wast/16.print b/tests/snapshots/testsuite/start.wast/16.print new file mode 100644 index 0000000000..0995850133 --- /dev/null +++ b/tests/snapshots/testsuite/start.wast/16.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32))) + (type (;1;) (func)) + (import "spectest" "print_i32" (func $print_i32 (;0;) (type 0))) + (func $main (;1;) (type 1) + i32.const 2 + call $print_i32 + ) + (start $main) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/start.wast/17.print b/tests/snapshots/testsuite/start.wast/17.print new file mode 100644 index 0000000000..2a2bf29afa --- /dev/null +++ b/tests/snapshots/testsuite/start.wast/17.print @@ -0,0 +1,5 @@ +(module + (type (;0;) (func)) + (import "spectest" "print" (func $print (;0;) (type 0))) + (start $print) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/start.wast/3.print b/tests/snapshots/testsuite/start.wast/3.print new file mode 100644 index 0000000000..794e99a9aa --- /dev/null +++ b/tests/snapshots/testsuite/start.wast/3.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (func $inc (;0;) (type 0) + i32.const 0 + i32.const 0 + i32.load8_u + i32.const 1 + i32.add + i32.store8 + ) + (func $get (;1;) (type 1) (result i32) + i32.const 0 + i32.load8_u + return + ) + (func $main (;2;) (type 0) + call $inc + call $inc + call $inc + ) + (memory (;0;) 1 1) + (export "inc" (func $inc)) + (export "get" (func $get)) + (start $main) + (data (;0;) (i32.const 0) "A") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/start.wast/9.print b/tests/snapshots/testsuite/start.wast/9.print new file mode 100644 index 0000000000..794e99a9aa --- /dev/null +++ b/tests/snapshots/testsuite/start.wast/9.print @@ -0,0 +1,27 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (func $inc (;0;) (type 0) + i32.const 0 + i32.const 0 + i32.load8_u + i32.const 1 + i32.add + i32.store8 + ) + (func $get (;1;) (type 1) (result i32) + i32.const 0 + i32.load8_u + return + ) + (func $main (;2;) (type 0) + call $inc + call $inc + call $inc + ) + (memory (;0;) 1 1) + (export "inc" (func $inc)) + (export "get" (func $get)) + (start $main) + (data (;0;) (i32.const 0) "A") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/store.wast/0.print b/tests/snapshots/testsuite/store.wast/0.print new file mode 100644 index 0000000000..188d319f07 --- /dev/null +++ b/tests/snapshots/testsuite/store.wast/0.print @@ -0,0 +1,85 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + end + ) + (func (;1;) (type 0) + loop ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + end + ) + (func (;2;) (type 0) + block ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + br 0 (;@1;) + end + ) + (func (;3;) (type 0) + block ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + i32.const 1 + br_if 0 (;@1;) + end + ) + (func (;4;) (type 0) + block ;; label = @1 + i32.const 6 + i32.const 0 + i32.const 1 + i32.store + br_if 0 (;@1;) + end + ) + (func (;5;) (type 0) + block ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + i32.const 1 + br_table 0 (;@1;) + end + ) + (func (;6;) (type 0) + i32.const 0 + i32.const 1 + i32.store + return + ) + (func (;7;) (type 0) + i32.const 1 + if ;; label = @1 + i32.const 0 + i32.const 1 + i32.store + end + ) + (func (;8;) (type 0) + i32.const 0 + if ;; label = @1 + else + i32.const 0 + i32.const 1 + i32.store + end + ) + (memory (;0;) 1) + (export "as-block-value" (func 0)) + (export "as-loop-value" (func 1)) + (export "as-br-value" (func 2)) + (export "as-br_if-value" (func 3)) + (export "as-br_if-value-cond" (func 4)) + (export "as-br_table-value" (func 5)) + (export "as-return-value" (func 6)) + (export "as-if-then" (func 7)) + (export "as-if-else" (func 8)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/switch.wast/0.print b/tests/snapshots/testsuite/switch.wast/0.print new file mode 100644 index 0000000000..86d190f9be --- /dev/null +++ b/tests/snapshots/testsuite/switch.wast/0.print @@ -0,0 +1,126 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i64) (result i64))) + (type (;2;) (func (result i32))) + (func (;0;) (type 0) (param $i i32) (result i32) + (local $j i32) + i32.const 100 + local.set $j + block $switch ;; label = @1 + block $7 ;; label = @2 + block $default ;; label = @3 + block $6 ;; label = @4 + block $5 ;; label = @5 + block $4 ;; label = @6 + block $3 ;; label = @7 + block $2 ;; label = @8 + block $1 ;; label = @9 + block $0 ;; label = @10 + local.get $i + br_table 0 (;@10;) 1 (;@9;) 2 (;@8;) 3 (;@7;) 4 (;@6;) 5 (;@5;) 6 (;@4;) 8 (;@2;) 7 (;@3;) + end + local.get $i + return + end + nop + end + end + i32.const 0 + local.get $i + i32.sub + local.set $j + br 5 (;@1;) + end + br 4 (;@1;) + end + i32.const 101 + local.set $j + br 3 (;@1;) + end + i32.const 101 + local.set $j + end + i32.const 102 + local.set $j + end + end + local.get $j + return + ) + (func (;1;) (type 1) (param $i i64) (result i64) + (local $j i64) + i64.const 100 + local.set $j + block $switch (result i64) ;; label = @1 + block $7 ;; label = @2 + block $default ;; label = @3 + block $4 ;; label = @4 + block $5 ;; label = @5 + block $6 ;; label = @6 + block $3 ;; label = @7 + block $2 ;; label = @8 + block $1 ;; label = @9 + block $0 ;; label = @10 + local.get $i + i32.wrap_i64 + br_table 0 (;@10;) 1 (;@9;) 2 (;@8;) 3 (;@7;) 6 (;@4;) 5 (;@5;) 4 (;@6;) 8 (;@2;) 7 (;@3;) + end + local.get $i + return + end + nop + end + end + i64.const 0 + local.get $i + i64.sub + br 5 (;@1;) + end + i64.const 101 + local.set $j + end + end + end + local.get $j + br 1 (;@1;) + end + i64.const -5 + end + return + ) + (func (;2;) (type 0) (param $i i32) (result i32) + block $2 (result i32) ;; label = @1 + i32.const 10 + block $1 (result i32) ;; label = @2 + i32.const 100 + block $0 (result i32) ;; label = @3 + i32.const 1000 + block $default (result i32) ;; label = @4 + i32.const 2 + local.get $i + i32.mul + i32.const 3 + local.get $i + i32.and + br_table 1 (;@3;) 2 (;@2;) 3 (;@1;) 0 (;@4;) + end + i32.add + end + i32.add + end + i32.add + end + return + ) + (func (;3;) (type 2) (result i32) + block ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + end + i32.const 1 + ) + (export "stmt" (func 0)) + (export "expr" (func 1)) + (export "arg" (func 2)) + (export "corner" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/0.print b/tests/snapshots/testsuite/table.wast/0.print new file mode 100644 index 0000000000..328f5cbd46 --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/0.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/1.print b/tests/snapshots/testsuite/table.wast/1.print new file mode 100644 index 0000000000..56069a92bc --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/1.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/2.print b/tests/snapshots/testsuite/table.wast/2.print new file mode 100644 index 0000000000..920f0e4379 --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/2.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/3.print b/tests/snapshots/testsuite/table.wast/3.print new file mode 100644 index 0000000000..7f97709846 --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/3.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 1 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/4.print b/tests/snapshots/testsuite/table.wast/4.print new file mode 100644 index 0000000000..88fb1c3ca9 --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/4.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 1 256 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/5.print b/tests/snapshots/testsuite/table.wast/5.print new file mode 100644 index 0000000000..83ff161c50 --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/5.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 65536 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/6.print b/tests/snapshots/testsuite/table.wast/6.print new file mode 100644 index 0000000000..bade100584 --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/6.print @@ -0,0 +1,3 @@ +(module + (table (;0;) 0 4294967295 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/7.print b/tests/snapshots/testsuite/table.wast/7.print new file mode 100644 index 0000000000..ef6430337b --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/7.print @@ -0,0 +1,4 @@ +(module + (table (;0;) 0 funcref) + (table (;1;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table.wast/8.print b/tests/snapshots/testsuite/table.wast/8.print new file mode 100644 index 0000000000..e059d68750 --- /dev/null +++ b/tests/snapshots/testsuite/table.wast/8.print @@ -0,0 +1,4 @@ +(module + (import "spectest" "table" (table (;0;) 0 funcref)) + (table (;1;) 0 funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/0.print b/tests/snapshots/testsuite/table_copy.wast/0.print new file mode 100644 index 0000000000..8c51f10af3 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/0.print @@ -0,0 +1,23 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (export "ef0" (func 0)) + (export "ef1" (func 1)) + (export "ef2" (func 2)) + (export "ef3" (func 3)) + (export "ef4" (func 4)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1056.print b/tests/snapshots/testsuite/table_copy.wast/1056.print new file mode 100644 index 0000000000..b580217441 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1056.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 10 + i32.const 0 + i32.const 20 + table.copy $t0 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1118.print b/tests/snapshots/testsuite/table_copy.wast/1118.print new file mode 100644 index 0000000000..d0fe702334 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1118.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 28 + i32.const 1 + i32.const 3 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1120.print b/tests/snapshots/testsuite/table_copy.wast/1120.print new file mode 100644 index 0000000000..c0e36e921e --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1120.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const -2 + i32.const 1 + i32.const 2 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1122.print b/tests/snapshots/testsuite/table_copy.wast/1122.print new file mode 100644 index 0000000000..b88947927d --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1122.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 25 + i32.const 6 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1124.print b/tests/snapshots/testsuite/table_copy.wast/1124.print new file mode 100644 index 0000000000..672afe82b0 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1124.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const -2 + i32.const 2 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1126.print b/tests/snapshots/testsuite/table_copy.wast/1126.print new file mode 100644 index 0000000000..4857142780 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1126.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 25 + i32.const 0 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1128.print b/tests/snapshots/testsuite/table_copy.wast/1128.print new file mode 100644 index 0000000000..691553b55f --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1128.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 30 + i32.const 15 + i32.const 0 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1130.print b/tests/snapshots/testsuite/table_copy.wast/1130.print new file mode 100644 index 0000000000..c481f722d7 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1130.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 31 + i32.const 15 + i32.const 0 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1132.print b/tests/snapshots/testsuite/table_copy.wast/1132.print new file mode 100644 index 0000000000..d7f68bbf63 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1132.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 30 + i32.const 0 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1134.print b/tests/snapshots/testsuite/table_copy.wast/1134.print new file mode 100644 index 0000000000..0afd384d56 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1134.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 31 + i32.const 0 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1136.print b/tests/snapshots/testsuite/table_copy.wast/1136.print new file mode 100644 index 0000000000..49184e88af --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1136.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 30 + i32.const 30 + i32.const 0 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1138.print b/tests/snapshots/testsuite/table_copy.wast/1138.print new file mode 100644 index 0000000000..397ce9cf0a --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1138.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 31 + i32.const 31 + i32.const 0 + table.copy + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1140.print b/tests/snapshots/testsuite/table_copy.wast/1140.print new file mode 100644 index 0000000000..9b62302719 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1140.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 28 + i32.const 1 + i32.const 3 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1142.print b/tests/snapshots/testsuite/table_copy.wast/1142.print new file mode 100644 index 0000000000..618568fb4f --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1142.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const -2 + i32.const 1 + i32.const 2 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1144.print b/tests/snapshots/testsuite/table_copy.wast/1144.print new file mode 100644 index 0000000000..ae4a4c75ef --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1144.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 25 + i32.const 6 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1146.print b/tests/snapshots/testsuite/table_copy.wast/1146.print new file mode 100644 index 0000000000..eac1586c3a --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1146.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const -2 + i32.const 2 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1148.print b/tests/snapshots/testsuite/table_copy.wast/1148.print new file mode 100644 index 0000000000..15b431917f --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1148.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 25 + i32.const 0 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1150.print b/tests/snapshots/testsuite/table_copy.wast/1150.print new file mode 100644 index 0000000000..589702e07d --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1150.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 30 + i32.const 15 + i32.const 0 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1152.print b/tests/snapshots/testsuite/table_copy.wast/1152.print new file mode 100644 index 0000000000..b300a3cc82 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1152.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 31 + i32.const 15 + i32.const 0 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1154.print b/tests/snapshots/testsuite/table_copy.wast/1154.print new file mode 100644 index 0000000000..f40bfac814 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1154.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 30 + i32.const 0 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1156.print b/tests/snapshots/testsuite/table_copy.wast/1156.print new file mode 100644 index 0000000000..8830e62ff8 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1156.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 31 + i32.const 0 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1158.print b/tests/snapshots/testsuite/table_copy.wast/1158.print new file mode 100644 index 0000000000..d4d09beb36 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1158.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 30 + i32.const 30 + i32.const 0 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1160.print b/tests/snapshots/testsuite/table_copy.wast/1160.print new file mode 100644 index 0000000000..ec0a339d57 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1160.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 31 + i32.const 31 + i32.const 0 + table.copy $t1 $t0 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1162.print b/tests/snapshots/testsuite/table_copy.wast/1162.print new file mode 100644 index 0000000000..7513d59839 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1162.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 0) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1196.print b/tests/snapshots/testsuite/table_copy.wast/1196.print new file mode 100644 index 0000000000..c2a52324f4 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1196.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 0) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1230.print b/tests/snapshots/testsuite/table_copy.wast/1230.print new file mode 100644 index 0000000000..d89ec6848a --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1230.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 24) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/126.print b/tests/snapshots/testsuite/table_copy.wast/126.print new file mode 100644 index 0000000000..bddbd20eb9 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/126.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 25 + i32.const 15 + i32.const 2 + table.copy + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1264.print b/tests/snapshots/testsuite/table_copy.wast/1264.print new file mode 100644 index 0000000000..a1b61d8457 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1264.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 23) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1298.print b/tests/snapshots/testsuite/table_copy.wast/1298.print new file mode 100644 index 0000000000..61dd507887 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1298.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 11) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1332.print b/tests/snapshots/testsuite/table_copy.wast/1332.print new file mode 100644 index 0000000000..d89ec6848a --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1332.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 24) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1366.print b/tests/snapshots/testsuite/table_copy.wast/1366.print new file mode 100644 index 0000000000..db72b857fb --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1366.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 21) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1400.print b/tests/snapshots/testsuite/table_copy.wast/1400.print new file mode 100644 index 0000000000..d89ec6848a --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1400.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 24) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1434.print b/tests/snapshots/testsuite/table_copy.wast/1434.print new file mode 100644 index 0000000000..3b6a25bbb7 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1434.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 21) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1468.print b/tests/snapshots/testsuite/table_copy.wast/1468.print new file mode 100644 index 0000000000..e74af4ad8b --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1468.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 128 128 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 112) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/1598.print b/tests/snapshots/testsuite/table_copy.wast/1598.print new file mode 100644 index 0000000000..40755f4319 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/1598.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + local.get $targetOffs + local.get $srcOffs + local.get $len + table.copy + ) + (table (;0;) 128 128 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) (i32.const 0) func $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/188.print b/tests/snapshots/testsuite/table_copy.wast/188.print new file mode 100644 index 0000000000..c9c69df2b3 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/188.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 13 + i32.const 25 + i32.const 3 + table.copy + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/2.print b/tests/snapshots/testsuite/table_copy.wast/2.print new file mode 100644 index 0000000000..dd4c2958dc --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/2.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + nop + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/250.print b/tests/snapshots/testsuite/table_copy.wast/250.print new file mode 100644 index 0000000000..c9328fce67 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/250.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 20 + i32.const 22 + i32.const 4 + table.copy + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/312.print b/tests/snapshots/testsuite/table_copy.wast/312.print new file mode 100644 index 0000000000..84ac45b22c --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/312.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 25 + i32.const 1 + i32.const 3 + table.copy + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/374.print b/tests/snapshots/testsuite/table_copy.wast/374.print new file mode 100644 index 0000000000..32a0821f2f --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/374.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 10 + i32.const 12 + i32.const 7 + table.copy + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/436.print b/tests/snapshots/testsuite/table_copy.wast/436.print new file mode 100644 index 0000000000..fe35276333 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/436.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 10 + i32.const 7 + table.copy + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/498.print b/tests/snapshots/testsuite/table_copy.wast/498.print new file mode 100644 index 0000000000..6f7717be6f --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/498.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 10 + i32.const 0 + i32.const 20 + table.copy $t1 $t0 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/560.print b/tests/snapshots/testsuite/table_copy.wast/560.print new file mode 100644 index 0000000000..e8498aaa02 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/560.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + nop + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/622.print b/tests/snapshots/testsuite/table_copy.wast/622.print new file mode 100644 index 0000000000..51199da945 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/622.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 13 + i32.const 2 + i32.const 3 + table.copy $t1 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/64.print b/tests/snapshots/testsuite/table_copy.wast/64.print new file mode 100644 index 0000000000..1f7461afd8 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/64.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 13 + i32.const 2 + i32.const 3 + table.copy + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (table $t1) (i32.const 3) func 1 3 1 4) + (elem (;5;) (table $t1) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/684.print b/tests/snapshots/testsuite/table_copy.wast/684.print new file mode 100644 index 0000000000..5e43dc6723 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/684.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 25 + i32.const 15 + i32.const 2 + table.copy $t1 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/746.print b/tests/snapshots/testsuite/table_copy.wast/746.print new file mode 100644 index 0000000000..5d1c8d40d9 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/746.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 13 + i32.const 25 + i32.const 3 + table.copy $t1 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/808.print b/tests/snapshots/testsuite/table_copy.wast/808.print new file mode 100644 index 0000000000..91ea38ea16 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/808.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 20 + i32.const 22 + i32.const 4 + table.copy $t1 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/870.print b/tests/snapshots/testsuite/table_copy.wast/870.print new file mode 100644 index 0000000000..2468e0fb5a --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/870.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 25 + i32.const 1 + i32.const 3 + table.copy $t1 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/932.print b/tests/snapshots/testsuite/table_copy.wast/932.print new file mode 100644 index 0000000000..9d66b8d4c2 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/932.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 10 + i32.const 12 + i32.const 7 + table.copy $t1 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_copy.wast/994.print b/tests/snapshots/testsuite/table_copy.wast/994.print new file mode 100644 index 0000000000..ef33073431 --- /dev/null +++ b/tests/snapshots/testsuite/table_copy.wast/994.print @@ -0,0 +1,50 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 10 + i32.const 7 + table.copy $t1 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (func (;12;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check_t0" (func 11)) + (export "check_t1" (func 12)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (;4;) (i32.const 3) func 1 3 1 4) + (elem (;5;) (i32.const 11) func 6 3 2 5 7) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_fill.wast/0.print b/tests/snapshots/testsuite/table_fill.wast/0.print new file mode 100644 index 0000000000..7e5c0c1c3c --- /dev/null +++ b/tests/snapshots/testsuite/table_fill.wast/0.print @@ -0,0 +1,24 @@ +(module + (type (;0;) (func (param i32 externref i32))) + (type (;1;) (func (param i32) (result externref))) + (func (;0;) (type 0) (param $i i32) (param $r externref) (param $n i32) + local.get $i + local.get $r + local.get $n + table.fill $t + ) + (func (;1;) (type 0) (param $i i32) (param $r externref) (param $n i32) + local.get $i + local.get $r + local.get $n + table.fill $t + ) + (func (;2;) (type 1) (param $i i32) (result externref) + local.get $i + table.get $t + ) + (table $t (;0;) 10 externref) + (export "fill" (func 0)) + (export "fill-abbrev" (func 1)) + (export "get" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_get.wast/0.print b/tests/snapshots/testsuite/table_get.wast/0.print new file mode 100644 index 0000000000..917a8877ec --- /dev/null +++ b/tests/snapshots/testsuite/table_get.wast/0.print @@ -0,0 +1,37 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param externref))) + (type (;2;) (func (param i32) (result externref))) + (type (;3;) (func (param i32) (result funcref))) + (type (;4;) (func (param i32) (result i32))) + (func $dummy (;0;) (type 0)) + (func (;1;) (type 1) (param $r externref) + i32.const 1 + local.get $r + table.set $t2 + i32.const 2 + i32.const 1 + table.get $t3 + table.set $t3 + ) + (func (;2;) (type 2) (param $i i32) (result externref) + local.get $i + table.get $t2 + ) + (func $f3 (;3;) (type 3) (param $i i32) (result funcref) + local.get $i + table.get $t3 + ) + (func (;4;) (type 4) (param $i i32) (result i32) + local.get $i + call $f3 + ref.is_null + ) + (table $t2 (;0;) 2 externref) + (table $t3 (;1;) 3 funcref) + (export "init" (func 1)) + (export "get-externref" (func 2)) + (export "get-funcref" (func $f3)) + (export "is_null-funcref" (func 4)) + (elem (;0;) (table $t3) (i32.const 1) func $dummy) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_grow.wast/0.print b/tests/snapshots/testsuite/table_grow.wast/0.print new file mode 100644 index 0000000000..b91560b07f --- /dev/null +++ b/tests/snapshots/testsuite/table_grow.wast/0.print @@ -0,0 +1,34 @@ +(module + (type (;0;) (func (param i32) (result externref))) + (type (;1;) (func (param i32 externref))) + (type (;2;) (func (param i32 externref) (result i32))) + (type (;3;) (func (result i32))) + (func (;0;) (type 0) (param $i i32) (result externref) + local.get $i + table.get $t + ) + (func (;1;) (type 1) (param $i i32) (param $r externref) + local.get $i + local.get $r + table.set $t + ) + (func (;2;) (type 2) (param $sz i32) (param $init externref) (result i32) + local.get $init + local.get $sz + table.grow $t + ) + (func (;3;) (type 2) (param $sz i32) (param $init externref) (result i32) + local.get $init + local.get $sz + table.grow $t + ) + (func (;4;) (type 3) (result i32) + table.size $t + ) + (table $t (;0;) 0 externref) + (export "get" (func 0)) + (export "set" (func 1)) + (export "grow" (func 2)) + (export "grow-abbrev" (func 3)) + (export "size" (func 4)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_grow.wast/22.print b/tests/snapshots/testsuite/table_grow.wast/22.print new file mode 100644 index 0000000000..52322538ba --- /dev/null +++ b/tests/snapshots/testsuite/table_grow.wast/22.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (func (result i32))) + (func $f (;0;) (type 0) (result i32) + ref.func $f + i32.const -16 + table.grow $t + ) + (table $t (;0;) 16 funcref) + (export "grow" (func $f)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_grow.wast/24.print b/tests/snapshots/testsuite/table_grow.wast/24.print new file mode 100644 index 0000000000..97bc1ab037 --- /dev/null +++ b/tests/snapshots/testsuite/table_grow.wast/24.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + ref.null extern + local.get 0 + table.grow $t + ) + (table $t (;0;) 0 externref) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_grow.wast/30.print b/tests/snapshots/testsuite/table_grow.wast/30.print new file mode 100644 index 0000000000..0b1acc0d4b --- /dev/null +++ b/tests/snapshots/testsuite/table_grow.wast/30.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + ref.null extern + local.get 0 + table.grow $t + ) + (table $t (;0;) 0 10 externref) + (export "grow" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_grow.wast/39.print b/tests/snapshots/testsuite/table_grow.wast/39.print new file mode 100644 index 0000000000..e34206f66d --- /dev/null +++ b/tests/snapshots/testsuite/table_grow.wast/39.print @@ -0,0 +1,42 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 i32) (result funcref))) + (func (;0;) (type 0) (param i32) (result i32) + ref.null func + local.get 0 + table.grow $t + ) + (func (;1;) (type 1) (param i32 i32) (result funcref) + (local funcref) + ref.func 1 + local.set 2 + block ;; label = @1 + loop ;; label = @2 + local.get 0 + table.get $t + local.set 2 + local.get 2 + ref.is_null + i32.eqz + br_if 1 (;@1;) + local.get 0 + local.get 1 + i32.ge_u + br_if 1 (;@1;) + local.get 0 + i32.const 1 + i32.add + local.set 0 + local.get 0 + local.get 1 + i32.le_u + br_if 0 (;@2;) + end + end + local.get 2 + ) + (table $t (;0;) 10 funcref) + (export "grow" (func 0)) + (export "check-table-null" (func 1)) + (elem (;0;) declare func 1) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/0.print b/tests/snapshots/testsuite/table_init.wast/0.print new file mode 100644 index 0000000000..8c51f10af3 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/0.print @@ -0,0 +1,23 @@ +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (export "ef0" (func 0)) + (export "ef1" (func 1)) + (export "ef2" (func 2)) + (export "ef3" (func 3)) + (export "ef4" (func 4)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/130.print b/tests/snapshots/testsuite/table_init.wast/130.print new file mode 100644 index 0000000000..b0ed46e5bd --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/130.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 1 + i32.const 3 + table.init $t1 3 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check" (func 11)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/162.print b/tests/snapshots/testsuite/table_init.wast/162.print new file mode 100644 index 0000000000..05961295f7 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/162.print @@ -0,0 +1,69 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 7 + i32.const 0 + i32.const 4 + table.init $t1 1 + elem.drop 1 + i32.const 15 + i32.const 1 + i32.const 3 + table.init $t1 3 + elem.drop 3 + i32.const 20 + i32.const 15 + i32.const 5 + table.copy $t1 $t1 + i32.const 21 + i32.const 29 + i32.const 1 + table.copy $t1 $t1 + i32.const 24 + i32.const 10 + i32.const 1 + table.copy $t1 $t1 + i32.const 13 + i32.const 11 + i32.const 4 + table.copy $t1 $t1 + i32.const 19 + i32.const 20 + i32.const 5 + table.copy $t1 $t1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check" (func 11)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/198.print b/tests/snapshots/testsuite/table_init.wast/198.print new file mode 100644 index 0000000000..4f7c0b99c8 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/198.print @@ -0,0 +1,44 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + elem.drop 2 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/2.print b/tests/snapshots/testsuite/table_init.wast/2.print new file mode 100644 index 0000000000..ddb473d6d3 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/2.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 7 + i32.const 0 + i32.const 4 + table.init 1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check" (func 11)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/200.print b/tests/snapshots/testsuite/table_init.wast/200.print new file mode 100644 index 0000000000..2fe8531ba9 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/200.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 1 + i32.const 1 + table.init 2 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/202.print b/tests/snapshots/testsuite/table_init.wast/202.print new file mode 100644 index 0000000000..4d7a58ae67 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/202.print @@ -0,0 +1,51 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 1 + i32.const 1 + table.init 1 + i32.const 21 + i32.const 1 + i32.const 1 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/204.print b/tests/snapshots/testsuite/table_init.wast/204.print new file mode 100644 index 0000000000..4b417e4f33 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/204.print @@ -0,0 +1,45 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + elem.drop 1 + elem.drop 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/206.print b/tests/snapshots/testsuite/table_init.wast/206.print new file mode 100644 index 0000000000..e5e97c1ca9 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/206.print @@ -0,0 +1,48 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + elem.drop 1 + i32.const 12 + i32.const 1 + i32.const 1 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/208.print b/tests/snapshots/testsuite/table_init.wast/208.print new file mode 100644 index 0000000000..ab8ee0b190 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/208.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 0 + i32.const 5 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/210.print b/tests/snapshots/testsuite/table_init.wast/210.print new file mode 100644 index 0000000000..b8db19b2bb --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/210.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 2 + i32.const 3 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/212.print b/tests/snapshots/testsuite/table_init.wast/212.print new file mode 100644 index 0000000000..785777a400 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/212.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 28 + i32.const 1 + i32.const 3 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/214.print b/tests/snapshots/testsuite/table_init.wast/214.print new file mode 100644 index 0000000000..38ea44e9d6 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/214.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 4 + i32.const 0 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/216.print b/tests/snapshots/testsuite/table_init.wast/216.print new file mode 100644 index 0000000000..52b6b253fe --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/216.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 5 + i32.const 0 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/218.print b/tests/snapshots/testsuite/table_init.wast/218.print new file mode 100644 index 0000000000..7c388e9b01 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/218.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 30 + i32.const 2 + i32.const 0 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/220.print b/tests/snapshots/testsuite/table_init.wast/220.print new file mode 100644 index 0000000000..75eae66e33 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/220.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 31 + i32.const 2 + i32.const 0 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/222.print b/tests/snapshots/testsuite/table_init.wast/222.print new file mode 100644 index 0000000000..fb1a1c06b4 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/222.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 30 + i32.const 4 + i32.const 0 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/224.print b/tests/snapshots/testsuite/table_init.wast/224.print new file mode 100644 index 0000000000..54ad495376 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/224.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 31 + i32.const 5 + i32.const 0 + table.init 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/226.print b/tests/snapshots/testsuite/table_init.wast/226.print new file mode 100644 index 0000000000..6256bb61fb --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/226.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 26 + i32.const 1 + i32.const 3 + table.init $t1 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/228.print b/tests/snapshots/testsuite/table_init.wast/228.print new file mode 100644 index 0000000000..4c66771dcf --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/228.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 4 + i32.const 0 + table.init $t1 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/230.print b/tests/snapshots/testsuite/table_init.wast/230.print new file mode 100644 index 0000000000..7d79aac4e8 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/230.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 12 + i32.const 5 + i32.const 0 + table.init $t1 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/232.print b/tests/snapshots/testsuite/table_init.wast/232.print new file mode 100644 index 0000000000..f79e81736f --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/232.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 28 + i32.const 2 + i32.const 0 + table.init $t1 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/234.print b/tests/snapshots/testsuite/table_init.wast/234.print new file mode 100644 index 0000000000..b0d126c9c4 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/234.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 29 + i32.const 2 + i32.const 0 + table.init $t1 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/236.print b/tests/snapshots/testsuite/table_init.wast/236.print new file mode 100644 index 0000000000..8eeebfd830 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/236.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 28 + i32.const 4 + i32.const 0 + table.init $t1 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/238.print b/tests/snapshots/testsuite/table_init.wast/238.print new file mode 100644 index 0000000000..1c28c2e1e1 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/238.print @@ -0,0 +1,47 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + i32.const 0 + ) + (func (;1;) (type 0) (result i32) + i32.const 1 + ) + (func (;2;) (type 0) (result i32) + i32.const 2 + ) + (func (;3;) (type 0) (result i32) + i32.const 3 + ) + (func (;4;) (type 0) (result i32) + i32.const 4 + ) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 29 + i32.const 5 + i32.const 0 + table.init $t1 1 + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 28 28 funcref) + (export "test" (func 10)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/303.print b/tests/snapshots/testsuite/table_init.wast/303.print new file mode 100644 index 0000000000..46336354aa --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/303.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + table.init 0 + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) 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)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/337.print b/tests/snapshots/testsuite/table_init.wast/337.print new file mode 100644 index 0000000000..46336354aa --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/337.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + table.init 0 + ) + (table (;0;) 32 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) 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)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/34.print b/tests/snapshots/testsuite/table_init.wast/34.print new file mode 100644 index 0000000000..701c056af0 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/34.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 15 + i32.const 1 + i32.const 3 + table.init 3 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check" (func 11)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/371.print b/tests/snapshots/testsuite/table_init.wast/371.print new file mode 100644 index 0000000000..ae7cd3b047 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/371.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + table.init 0 + ) + (table (;0;) 160 320 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) 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)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/533.print b/tests/snapshots/testsuite/table_init.wast/533.print new file mode 100644 index 0000000000..ae7cd3b047 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/533.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + table.init 0 + ) + (table (;0;) 160 320 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) 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)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/66.print b/tests/snapshots/testsuite/table_init.wast/66.print new file mode 100644 index 0000000000..39f4becaa4 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/66.print @@ -0,0 +1,69 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 7 + i32.const 0 + i32.const 4 + table.init 1 + elem.drop 1 + i32.const 15 + i32.const 1 + i32.const 3 + table.init 3 + elem.drop 3 + i32.const 20 + i32.const 15 + i32.const 5 + table.copy + i32.const 21 + i32.const 29 + i32.const 1 + table.copy + i32.const 24 + i32.const 10 + i32.const 1 + table.copy + i32.const 13 + i32.const 11 + i32.const 4 + table.copy + i32.const 19 + i32.const 20 + i32.const 5 + table.copy + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check" (func 11)) + (elem (;0;) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/695.print b/tests/snapshots/testsuite/table_init.wast/695.print new file mode 100644 index 0000000000..2c788ca902 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/695.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $offs i32) (param $len i32) + local.get $offs + i32.const 0 + local.get $len + table.init 0 + ) + (table (;0;) 64 64 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) 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)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/761.print b/tests/snapshots/testsuite/table_init.wast/761.print new file mode 100644 index 0000000000..b127df5921 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/761.print @@ -0,0 +1,83 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (type (;2;) (func (param i32 i32))) + (func $f0 (;0;) (type 0) (result i32) + i32.const 0 + ) + (func $f1 (;1;) (type 0) (result i32) + i32.const 1 + ) + (func $f2 (;2;) (type 0) (result i32) + i32.const 2 + ) + (func $f3 (;3;) (type 0) (result i32) + i32.const 3 + ) + (func $f4 (;4;) (type 0) (result i32) + i32.const 4 + ) + (func $f5 (;5;) (type 0) (result i32) + i32.const 5 + ) + (func $f6 (;6;) (type 0) (result i32) + i32.const 6 + ) + (func $f7 (;7;) (type 0) (result i32) + i32.const 7 + ) + (func $f8 (;8;) (type 0) (result i32) + i32.const 8 + ) + (func $f9 (;9;) (type 0) (result i32) + i32.const 9 + ) + (func $f10 (;10;) (type 0) (result i32) + i32.const 10 + ) + (func $f11 (;11;) (type 0) (result i32) + i32.const 11 + ) + (func $f12 (;12;) (type 0) (result i32) + i32.const 12 + ) + (func $f13 (;13;) (type 0) (result i32) + i32.const 13 + ) + (func $f14 (;14;) (type 0) (result i32) + i32.const 14 + ) + (func $f15 (;15;) (type 0) (result i32) + i32.const 15 + ) + (func (;16;) (type 1) (param $n i32) (result i32) + local.get $n + call_indirect (type 0) + ) + (func (;17;) (type 2) (param $offs i32) (param $len i32) + local.get $offs + i32.const 8 + local.get $len + table.init 0 + ) + (table (;0;) 16 16 funcref) + (export "f0" (func $f0)) + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + (export "f4" (func $f4)) + (export "f5" (func $f5)) + (export "f6" (func $f6)) + (export "f7" (func $f7)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f10" (func $f10)) + (export "f11" (func $f11)) + (export "f12" (func $f12)) + (export "f13" (func $f13)) + (export "f14" (func $f14)) + (export "f15" (func $f15)) + (export "test" (func 16)) + (export "run" (func 17)) + (elem (;0;) 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)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/779.print b/tests/snapshots/testsuite/table_init.wast/779.print new file mode 100644 index 0000000000..023b666cba --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/779.print @@ -0,0 +1,75 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + i32.const 0 + i32.const 0 + i32.const 0 + table.init 64 + ) + (table (;0;) 1 funcref) + (elem (;0;) funcref) + (elem (;1;) funcref) + (elem (;2;) funcref) + (elem (;3;) funcref) + (elem (;4;) funcref) + (elem (;5;) funcref) + (elem (;6;) funcref) + (elem (;7;) funcref) + (elem (;8;) funcref) + (elem (;9;) funcref) + (elem (;10;) funcref) + (elem (;11;) funcref) + (elem (;12;) funcref) + (elem (;13;) funcref) + (elem (;14;) funcref) + (elem (;15;) funcref) + (elem (;16;) funcref) + (elem (;17;) funcref) + (elem (;18;) funcref) + (elem (;19;) funcref) + (elem (;20;) funcref) + (elem (;21;) funcref) + (elem (;22;) funcref) + (elem (;23;) funcref) + (elem (;24;) funcref) + (elem (;25;) funcref) + (elem (;26;) funcref) + (elem (;27;) funcref) + (elem (;28;) funcref) + (elem (;29;) funcref) + (elem (;30;) funcref) + (elem (;31;) funcref) + (elem (;32;) funcref) + (elem (;33;) funcref) + (elem (;34;) funcref) + (elem (;35;) funcref) + (elem (;36;) funcref) + (elem (;37;) funcref) + (elem (;38;) funcref) + (elem (;39;) funcref) + (elem (;40;) funcref) + (elem (;41;) funcref) + (elem (;42;) funcref) + (elem (;43;) funcref) + (elem (;44;) funcref) + (elem (;45;) funcref) + (elem (;46;) funcref) + (elem (;47;) funcref) + (elem (;48;) funcref) + (elem (;49;) funcref) + (elem (;50;) funcref) + (elem (;51;) funcref) + (elem (;52;) funcref) + (elem (;53;) funcref) + (elem (;54;) funcref) + (elem (;55;) funcref) + (elem (;56;) funcref) + (elem (;57;) funcref) + (elem (;58;) funcref) + (elem (;59;) funcref) + (elem (;60;) funcref) + (elem (;61;) funcref) + (elem (;62;) funcref) + (elem (;63;) funcref) + (elem (;64;) funcref) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_init.wast/98.print b/tests/snapshots/testsuite/table_init.wast/98.print new file mode 100644 index 0000000000..4465b6c0f4 --- /dev/null +++ b/tests/snapshots/testsuite/table_init.wast/98.print @@ -0,0 +1,43 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32) (result i32))) + (import "a" "ef0" (func (;0;) (type 0))) + (import "a" "ef1" (func (;1;) (type 0))) + (import "a" "ef2" (func (;2;) (type 0))) + (import "a" "ef3" (func (;3;) (type 0))) + (import "a" "ef4" (func (;4;) (type 0))) + (func (;5;) (type 0) (result i32) + i32.const 5 + ) + (func (;6;) (type 0) (result i32) + i32.const 6 + ) + (func (;7;) (type 0) (result i32) + i32.const 7 + ) + (func (;8;) (type 0) (result i32) + i32.const 8 + ) + (func (;9;) (type 0) (result i32) + i32.const 9 + ) + (func (;10;) (type 1) + i32.const 7 + i32.const 0 + i32.const 4 + table.init $t1 1 + ) + (func (;11;) (type 2) (param i32) (result i32) + local.get 0 + call_indirect $t1 (type 0) + ) + (table $t0 (;0;) 30 30 funcref) + (table $t1 (;1;) 30 30 funcref) + (export "test" (func 10)) + (export "check" (func 11)) + (elem (;0;) (table $t1) (i32.const 2) func 3 1 4 1) + (elem (;1;) funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (;2;) (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem (;3;) funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_set.wast/0.print b/tests/snapshots/testsuite/table_set.wast/0.print new file mode 100644 index 0000000000..db62bacf4c --- /dev/null +++ b/tests/snapshots/testsuite/table_set.wast/0.print @@ -0,0 +1,48 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result externref))) + (type (;2;) (func (param i32) (result funcref))) + (type (;3;) (func (param i32 externref))) + (type (;4;) (func (param i32 funcref))) + (type (;5;) (func (param i32 i32))) + (type (;6;) (func (param i32) (result i32))) + (func $dummy (;0;) (type 0)) + (func (;1;) (type 1) (param $i i32) (result externref) + local.get $i + table.get $t2 + ) + (func $f3 (;2;) (type 2) (param $i i32) (result funcref) + local.get $i + table.get $t3 + ) + (func (;3;) (type 3) (param $i i32) (param $r externref) + local.get $i + local.get $r + table.set $t2 + ) + (func (;4;) (type 4) (param $i i32) (param $r funcref) + local.get $i + local.get $r + table.set $t3 + ) + (func (;5;) (type 5) (param $i i32) (param $j i32) + local.get $i + local.get $j + table.get $t3 + table.set $t3 + ) + (func (;6;) (type 6) (param $i i32) (result i32) + local.get $i + call $f3 + ref.is_null + ) + (table $t2 (;0;) 1 externref) + (table $t3 (;1;) 2 funcref) + (export "get-externref" (func 1)) + (export "get-funcref" (func $f3)) + (export "set-externref" (func 3)) + (export "set-funcref" (func 4)) + (export "set-funcref-from" (func 5)) + (export "is_null-funcref" (func 6)) + (elem (;0;) (table $t3) (i32.const 1) func $dummy) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/table_size.wast/0.print b/tests/snapshots/testsuite/table_size.wast/0.print new file mode 100644 index 0000000000..9f872e8c9e --- /dev/null +++ b/tests/snapshots/testsuite/table_size.wast/0.print @@ -0,0 +1,52 @@ +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (func (;0;) (type 0) (result i32) + table.size $t0 + ) + (func (;1;) (type 0) (result i32) + table.size $t1 + ) + (func (;2;) (type 0) (result i32) + table.size $t2 + ) + (func (;3;) (type 0) (result i32) + table.size $t3 + ) + (func (;4;) (type 1) (param $sz i32) + ref.null extern + local.get $sz + table.grow $t0 + drop + ) + (func (;5;) (type 1) (param $sz i32) + ref.null extern + local.get $sz + table.grow $t1 + drop + ) + (func (;6;) (type 1) (param $sz i32) + ref.null extern + local.get $sz + table.grow $t2 + drop + ) + (func (;7;) (type 1) (param $sz i32) + ref.null extern + local.get $sz + table.grow $t3 + drop + ) + (table $t0 (;0;) 0 externref) + (table $t1 (;1;) 1 externref) + (table $t2 (;2;) 0 2 externref) + (table $t3 (;3;) 3 8 externref) + (export "size-t0" (func 0)) + (export "size-t1" (func 1)) + (export "size-t2" (func 2)) + (export "size-t3" (func 3)) + (export "grow-t0" (func 4)) + (export "grow-t1" (func 5)) + (export "grow-t2" (func 6)) + (export "grow-t3" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/0.print b/tests/snapshots/testsuite/tokens.wast/0.print new file mode 100644 index 0000000000..a05f7992fa --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/0.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/1.print b/tests/snapshots/testsuite/tokens.wast/1.print new file mode 100644 index 0000000000..9f99641bc2 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/1.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/10.print b/tests/snapshots/testsuite/tokens.wast/10.print new file mode 100644 index 0000000000..f81d636a1b --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/10.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/11.print b/tests/snapshots/testsuite/tokens.wast/11.print new file mode 100644 index 0000000000..a05f7992fa --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/11.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/12.print b/tests/snapshots/testsuite/tokens.wast/12.print new file mode 100644 index 0000000000..a05f7992fa --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/12.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/13.print b/tests/snapshots/testsuite/tokens.wast/13.print new file mode 100644 index 0000000000..0b1aa45c99 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/13.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/14.print b/tests/snapshots/testsuite/tokens.wast/14.print new file mode 100644 index 0000000000..3897180c1c --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/14.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + br 0 (;@0;) + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/15.print b/tests/snapshots/testsuite/tokens.wast/15.print new file mode 100644 index 0000000000..56805dd9c4 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/15.print @@ -0,0 +1,3 @@ +(module + (data (;0;) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/16.print b/tests/snapshots/testsuite/tokens.wast/16.print new file mode 100644 index 0000000000..443d654542 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/16.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block $l ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/18.print b/tests/snapshots/testsuite/tokens.wast/18.print new file mode 100644 index 0000000000..443d654542 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/18.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block $l ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/2.print b/tests/snapshots/testsuite/tokens.wast/2.print new file mode 100644 index 0000000000..9f99641bc2 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/2.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/20.print b/tests/snapshots/testsuite/tokens.wast/20.print new file mode 100644 index 0000000000..443d654542 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/20.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block $l ;; label = @1 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/22.print b/tests/snapshots/testsuite/tokens.wast/22.print new file mode 100644 index 0000000000..5597fb11d2 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/22.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block $l0 ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/23.print b/tests/snapshots/testsuite/tokens.wast/23.print new file mode 100644 index 0000000000..3c3fdaf6e7 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/23.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block $l$l ;; label = @1 + i32.const 0 + br_table 0 (;@1;) + end + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/24.print b/tests/snapshots/testsuite/tokens.wast/24.print new file mode 100644 index 0000000000..56805dd9c4 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/24.print @@ -0,0 +1,3 @@ +(module + (data (;0;) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/26.print b/tests/snapshots/testsuite/tokens.wast/26.print new file mode 100644 index 0000000000..cdebea1372 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/26.print @@ -0,0 +1,3 @@ +(module + (data $l (;0;) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/28.print b/tests/snapshots/testsuite/tokens.wast/28.print new file mode 100644 index 0000000000..aa050e9642 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/28.print @@ -0,0 +1,3 @@ +(module + (data $l (;0;) " a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/3.print b/tests/snapshots/testsuite/tokens.wast/3.print new file mode 100644 index 0000000000..9f99641bc2 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/3.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + nop + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/30.print b/tests/snapshots/testsuite/tokens.wast/30.print new file mode 100644 index 0000000000..1ad728f567 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/30.print @@ -0,0 +1,3 @@ +(module + (data $l (;0;) "a ") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/32.print b/tests/snapshots/testsuite/tokens.wast/32.print new file mode 100644 index 0000000000..8ef31ab344 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/32.print @@ -0,0 +1,3 @@ +(module + (data $l (;0;) "a b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/34.print b/tests/snapshots/testsuite/tokens.wast/34.print new file mode 100644 index 0000000000..8c31c73817 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/34.print @@ -0,0 +1,3 @@ +(module + (data $l (;0;) "\ef\98\9a\ef\92\a9") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/36.print b/tests/snapshots/testsuite/tokens.wast/36.print new file mode 100644 index 0000000000..144116c799 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/36.print @@ -0,0 +1,3 @@ +(module + (data $l (;0;) " \ef\98\9a\ef\92\a9") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/38.print b/tests/snapshots/testsuite/tokens.wast/38.print new file mode 100644 index 0000000000..e47ca09790 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/38.print @@ -0,0 +1,3 @@ +(module + (data $l (;0;) "\ef\98\9a\ef\92\a9 ") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/4.print b/tests/snapshots/testsuite/tokens.wast/4.print new file mode 100644 index 0000000000..dba9d1353f --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/4.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0) + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/40.print b/tests/snapshots/testsuite/tokens.wast/40.print new file mode 100644 index 0000000000..486daa357a --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/40.print @@ -0,0 +1,3 @@ +(module + (data (;0;) "ab") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/42.print b/tests/snapshots/testsuite/tokens.wast/42.print new file mode 100644 index 0000000000..5df264e49c --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/42.print @@ -0,0 +1,3 @@ +(module + (data (;0;) "a b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/44.print b/tests/snapshots/testsuite/tokens.wast/44.print new file mode 100644 index 0000000000..5df264e49c --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/44.print @@ -0,0 +1,3 @@ +(module + (data (;0;) "a b") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/46.print b/tests/snapshots/testsuite/tokens.wast/46.print new file mode 100644 index 0000000000..c037c015ec --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/46.print @@ -0,0 +1,3 @@ +(module + (data (;0;) "\ef\98\9a\ef\92\a9\ef\98\9a\ef\92\a9") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/48.print b/tests/snapshots/testsuite/tokens.wast/48.print new file mode 100644 index 0000000000..5a267d2c91 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/48.print @@ -0,0 +1,3 @@ +(module + (data (;0;) "\ef\98\9a\ef\92\a9 \ef\98\9a\ef\92\a9") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/5.print b/tests/snapshots/testsuite/tokens.wast/5.print new file mode 100644 index 0000000000..ae17b704a6 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/5.print @@ -0,0 +1,7 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + br 0 (;@0;) + nop + ) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/50.print b/tests/snapshots/testsuite/tokens.wast/50.print new file mode 100644 index 0000000000..5a267d2c91 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/50.print @@ -0,0 +1,3 @@ +(module + (data (;0;) "\ef\98\9a\ef\92\a9 \ef\98\9a\ef\92\a9") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/6.print b/tests/snapshots/testsuite/tokens.wast/6.print new file mode 100644 index 0000000000..117b57d059 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/6.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0)) + (table (;0;) 1 funcref) + (elem (;0;) (i32.const 0) func 0) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/7.print b/tests/snapshots/testsuite/tokens.wast/7.print new file mode 100644 index 0000000000..923bbe17ba --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/7.print @@ -0,0 +1,6 @@ +(module + (type (;0;) (func)) + (func $f (;0;) (type 0)) + (table (;0;) 1 funcref) + (elem (;0;) (i32.const 0) func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/8.print b/tests/snapshots/testsuite/tokens.wast/8.print new file mode 100644 index 0000000000..cc1e75fe22 --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/8.print @@ -0,0 +1,4 @@ +(module + (memory (;0;) 1) + (data (;0;) (i32.const 0) "a") +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/tokens.wast/9.print b/tests/snapshots/testsuite/tokens.wast/9.print new file mode 100644 index 0000000000..8ed521365c --- /dev/null +++ b/tests/snapshots/testsuite/tokens.wast/9.print @@ -0,0 +1,4 @@ +(module + (type (;0;) (func)) + (import "spectest" "print" (func (;0;) (type 0))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/traps.wast/0.print b/tests/snapshots/testsuite/traps.wast/0.print new file mode 100644 index 0000000000..d5de71780d --- /dev/null +++ b/tests/snapshots/testsuite/traps.wast/0.print @@ -0,0 +1,32 @@ +(module + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i64 i64))) + (func (;0;) (type 0) (param $x i32) (param $y i32) + local.get $x + local.get $y + i32.div_s + drop + ) + (func (;1;) (type 0) (param $x i32) (param $y i32) + local.get $x + local.get $y + i32.div_u + drop + ) + (func (;2;) (type 1) (param $x i64) (param $y i64) + local.get $x + local.get $y + i64.div_s + drop + ) + (func (;3;) (type 1) (param $x i64) (param $y i64) + local.get $x + local.get $y + i64.div_u + drop + ) + (export "no_dce.i32.div_s" (func 0)) + (export "no_dce.i32.div_u" (func 1)) + (export "no_dce.i64.div_s" (func 2)) + (export "no_dce.i64.div_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/traps.wast/12.print b/tests/snapshots/testsuite/traps.wast/12.print new file mode 100644 index 0000000000..993f0d491b --- /dev/null +++ b/tests/snapshots/testsuite/traps.wast/12.print @@ -0,0 +1,52 @@ +(module + (type (;0;) (func (param f32))) + (type (;1;) (func (param f64))) + (func (;0;) (type 0) (param $x f32) + local.get $x + i32.trunc_f32_s + drop + ) + (func (;1;) (type 0) (param $x f32) + local.get $x + i32.trunc_f32_u + drop + ) + (func (;2;) (type 1) (param $x f64) + local.get $x + i32.trunc_f64_s + drop + ) + (func (;3;) (type 1) (param $x f64) + local.get $x + i32.trunc_f64_u + drop + ) + (func (;4;) (type 0) (param $x f32) + local.get $x + i64.trunc_f32_s + drop + ) + (func (;5;) (type 0) (param $x f32) + local.get $x + i64.trunc_f32_u + drop + ) + (func (;6;) (type 1) (param $x f64) + local.get $x + i64.trunc_f64_s + drop + ) + (func (;7;) (type 1) (param $x f64) + local.get $x + i64.trunc_f64_u + drop + ) + (export "no_dce.i32.trunc_f32_s" (func 0)) + (export "no_dce.i32.trunc_f32_u" (func 1)) + (export "no_dce.i32.trunc_f64_s" (func 2)) + (export "no_dce.i32.trunc_f64_u" (func 3)) + (export "no_dce.i64.trunc_f32_s" (func 4)) + (export "no_dce.i64.trunc_f32_u" (func 5)) + (export "no_dce.i64.trunc_f64_s" (func 6)) + (export "no_dce.i64.trunc_f64_u" (func 7)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/traps.wast/21.print b/tests/snapshots/testsuite/traps.wast/21.print new file mode 100644 index 0000000000..db0664f856 --- /dev/null +++ b/tests/snapshots/testsuite/traps.wast/21.print @@ -0,0 +1,88 @@ +(module + (type (;0;) (func (param i32))) + (func (;0;) (type 0) (param $i i32) + local.get $i + i32.load + drop + ) + (func (;1;) (type 0) (param $i i32) + local.get $i + i32.load16_s + drop + ) + (func (;2;) (type 0) (param $i i32) + local.get $i + i32.load16_u + drop + ) + (func (;3;) (type 0) (param $i i32) + local.get $i + i32.load8_s + drop + ) + (func (;4;) (type 0) (param $i i32) + local.get $i + i32.load8_u + drop + ) + (func (;5;) (type 0) (param $i i32) + local.get $i + i64.load + drop + ) + (func (;6;) (type 0) (param $i i32) + local.get $i + i64.load32_s + drop + ) + (func (;7;) (type 0) (param $i i32) + local.get $i + i64.load32_u + drop + ) + (func (;8;) (type 0) (param $i i32) + local.get $i + i64.load16_s + drop + ) + (func (;9;) (type 0) (param $i i32) + local.get $i + i64.load16_u + drop + ) + (func (;10;) (type 0) (param $i i32) + local.get $i + i64.load8_s + drop + ) + (func (;11;) (type 0) (param $i i32) + local.get $i + i64.load8_u + drop + ) + (func (;12;) (type 0) (param $i i32) + local.get $i + f32.load + drop + ) + (func (;13;) (type 0) (param $i i32) + local.get $i + f64.load + drop + ) + (memory (;0;) 1) + (export "no_dce.i32.load" (func 0)) + (export "no_dce.i32.load16_s" (func 1)) + (export "no_dce.i32.load16_u" (func 2)) + (export "no_dce.i32.load8_s" (func 3)) + (export "no_dce.i32.load8_u" (func 4)) + (export "no_dce.i64.load" (func 5)) + (export "no_dce.i64.load32_s" (func 6)) + (export "no_dce.i64.load32_u" (func 7)) + (export "no_dce.i64.load16_s" (func 8)) + (export "no_dce.i64.load16_u" (func 9)) + (export "no_dce.i64.load8_s" (func 10)) + (export "no_dce.i64.load8_u" (func 11)) + (export "no_dce.f32.load" (func 12)) + (export "no_dce.f64.load" (func 13)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/traps.wast/7.print b/tests/snapshots/testsuite/traps.wast/7.print new file mode 100644 index 0000000000..1b5e5bbbe8 --- /dev/null +++ b/tests/snapshots/testsuite/traps.wast/7.print @@ -0,0 +1,32 @@ +(module + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i64 i64))) + (func (;0;) (type 0) (param $x i32) (param $y i32) + local.get $x + local.get $y + i32.rem_s + drop + ) + (func (;1;) (type 0) (param $x i32) (param $y i32) + local.get $x + local.get $y + i32.rem_u + drop + ) + (func (;2;) (type 1) (param $x i64) (param $y i64) + local.get $x + local.get $y + i64.rem_s + drop + ) + (func (;3;) (type 1) (param $x i64) (param $y i64) + local.get $x + local.get $y + i64.rem_u + drop + ) + (export "no_dce.i32.rem_s" (func 0)) + (export "no_dce.i32.rem_u" (func 1)) + (export "no_dce.i64.rem_s" (func 2)) + (export "no_dce.i64.rem_u" (func 3)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/type.wast/0.print b/tests/snapshots/testsuite/type.wast/0.print new file mode 100644 index 0000000000..dd22b20a09 --- /dev/null +++ b/tests/snapshots/testsuite/type.wast/0.print @@ -0,0 +1,25 @@ +(module + (type (;0;) (func)) + (type $t (;1;) (func)) + (type (;2;) (func (param i32))) + (type (;3;) (func (param i32))) + (type (;4;) (func (result i32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i32) (result i32))) + (type (;7;) (func (param f32 f64))) + (type (;8;) (func (result i64 f32))) + (type (;9;) (func (param i32 i64) (result f32 f64))) + (type (;10;) (func (param f32 f64))) + (type (;11;) (func (param f32 f64))) + (type (;12;) (func (param f32 f64))) + (type (;13;) (func (param f32 f64))) + (type (;14;) (func (result i64 f32))) + (type (;15;) (func (param i32 i64) (result f32 f64))) + (type (;16;) (func (param i32 i64) (result f32 f64))) + (type (;17;) (func (param f32 f64 i32 f64 i32 i32))) + (type (;18;) (func (result i64 i64 f32 f32 i32))) + (type (;19;) (func (param i32 i32 i64 i32) (result f32 f64 f64 i32))) + (type (;20;) (func (param f32 f64 i32))) + (type (;21;) (func (result i64 i64 f32))) + (type (;22;) (func (param i32 i32 i64 i32 i32) (result f32 f64 f64 i32))) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/unreachable.wast/0.print b/tests/snapshots/testsuite/unreachable.wast/0.print new file mode 100644 index 0000000000..cc76c72b95 --- /dev/null +++ b/tests/snapshots/testsuite/unreachable.wast/0.print @@ -0,0 +1,412 @@ +(module + (type $sig (;0;) (func (param i32 i32 i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (type (;4;) (func (result f32))) + (type (;5;) (func (result f64))) + (type (;6;) (func (param i32 i32) (result i32))) + (func $dummy (;0;) (type 1)) + (func $dummy3 (;1;) (type $sig) (param i32 i32 i32)) + (func (;2;) (type 2) (result i32) + unreachable + ) + (func (;3;) (type 3) (result i64) + unreachable + ) + (func (;4;) (type 4) (result f32) + unreachable + ) + (func (;5;) (type 5) (result f64) + unreachable + ) + (func (;6;) (type 2) (result i32) + unreachable + i32.const -1 + ) + (func (;7;) (type 2) (result i32) + call $dummy + unreachable + i32.const -1 + ) + (func (;8;) (type 1) + call $dummy + unreachable + ) + (func (;9;) (type 2) (result i32) + call $dummy + unreachable + ) + (func (;10;) (type 2) (result i32) + block (result i32) ;; label = @1 + unreachable + i32.const 2 + end + ) + (func (;11;) (type 2) (result i32) + block (result i32) ;; label = @1 + call $dummy + unreachable + i32.const 2 + end + ) + (func (;12;) (type 1) + block ;; label = @1 + nop + call $dummy + unreachable + end + ) + (func (;13;) (type 2) (result i32) + block (result i32) ;; label = @1 + nop + call $dummy + unreachable + end + ) + (func (;14;) (type 2) (result i32) + block (result i32) ;; label = @1 + call $dummy + i32.const 1 + br 0 (;@1;) + unreachable + end + ) + (func (;15;) (type 2) (result i32) + loop (result i32) ;; label = @1 + unreachable + i32.const 2 + end + ) + (func (;16;) (type 2) (result i32) + loop (result i32) ;; label = @1 + call $dummy + unreachable + i32.const 2 + end + ) + (func (;17;) (type 1) + loop ;; label = @1 + nop + call $dummy + unreachable + end + ) + (func (;18;) (type 2) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + call $dummy + i32.const 1 + br 1 (;@1;) + unreachable + end + end + ) + (func (;19;) (type 2) (result i32) + block (result i32) ;; label = @1 + unreachable + br 0 (;@1;) + end + ) + (func (;20;) (type 1) + block ;; label = @1 + unreachable + br_if 0 (;@1;) + end + ) + (func (;21;) (type 2) (result i32) + block (result i32) ;; label = @1 + unreachable + i32.const 1 + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;22;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + unreachable + br_if 0 (;@1;) + drop + i32.const 7 + end + ) + (func (;23;) (type 1) + block ;; label = @1 + unreachable + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + end + ) + (func (;24;) (type 2) (result i32) + block (result i32) ;; label = @1 + unreachable + i32.const 1 + br_table 0 (;@1;) 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;25;) (type 2) (result i32) + block (result i32) ;; label = @1 + block (result i32) ;; label = @2 + unreachable + i32.const 1 + br_table 0 (;@2;) 1 (;@1;) + end + end + ) + (func (;26;) (type 2) (result i32) + block (result i32) ;; label = @1 + i32.const 6 + unreachable + br_table 0 (;@1;) 0 (;@1;) + i32.const 7 + end + ) + (func (;27;) (type 2) (result i32) + block (result i32) ;; label = @1 + unreachable + br_table 0 (;@1;) 0 (;@1;) + i32.const 8 + end + ) + (func (;28;) (type 3) (result i64) + unreachable + return + ) + (func (;29;) (type 2) (result i32) + unreachable + if (result i32) ;; label = @1 + i32.const 0 + else + i32.const 1 + end + ) + (func (;30;) (type 6) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + unreachable + else + local.get 1 + end + ) + (func (;31;) (type 6) (param i32 i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 1 + else + unreachable + end + ) + (func (;32;) (type 6) (param i32 i32) (result i32) + local.get 0 + if ;; label = @1 + unreachable + end + local.get 1 + ) + (func (;33;) (type 6) (param i32 i32) (result i32) + unreachable + local.get 0 + local.get 1 + select + ) + (func (;34;) (type 6) (param i32 i32) (result i32) + local.get 0 + unreachable + local.get 1 + select + ) + (func (;35;) (type 2) (result i32) + i32.const 0 + i32.const 1 + unreachable + select + ) + (func (;36;) (type 1) + unreachable + i32.const 2 + i32.const 3 + call $dummy3 + ) + (func (;37;) (type 1) + i32.const 1 + unreachable + i32.const 3 + call $dummy3 + ) + (func (;38;) (type 1) + i32.const 1 + i32.const 2 + unreachable + call $dummy3 + ) + (func (;39;) (type 1) + unreachable + i32.const 1 + i32.const 2 + i32.const 3 + call_indirect (type $sig) + ) + (func (;40;) (type 1) + i32.const 0 + unreachable + i32.const 2 + i32.const 3 + call_indirect (type $sig) + ) + (func (;41;) (type 1) + i32.const 0 + i32.const 1 + unreachable + i32.const 3 + call_indirect (type $sig) + ) + (func (;42;) (type 1) + i32.const 0 + i32.const 1 + i32.const 2 + unreachable + call_indirect (type $sig) + ) + (func (;43;) (type 1) + (local f32) + unreachable + local.set 0 + ) + (func (;44;) (type 4) (result f32) + (local f32) + unreachable + local.tee 0 + ) + (func (;45;) (type 4) (result f32) + unreachable + global.set $a + ) + (func (;46;) (type 4) (result f32) + unreachable + f32.load + ) + (func (;47;) (type 3) (result i64) + unreachable + i64.load8_s + ) + (func (;48;) (type 1) + unreachable + f64.const 0x1.cp+2 (;=7;) + f64.store + ) + (func (;49;) (type 1) + i32.const 2 + unreachable + i64.store + ) + (func (;50;) (type 1) + unreachable + i32.const 7 + i32.store8 + ) + (func (;51;) (type 1) + i32.const 2 + unreachable + i64.store16 + ) + (func (;52;) (type 4) (result f32) + unreachable + f32.neg + ) + (func (;53;) (type 2) (result i32) + unreachable + i32.const 10 + i32.add + ) + (func (;54;) (type 3) (result i64) + i64.const 10 + unreachable + i64.sub + ) + (func (;55;) (type 2) (result i32) + unreachable + i32.eqz + ) + (func (;56;) (type 2) (result i32) + unreachable + f64.const 0x1.4p+3 (;=10;) + f64.le + ) + (func (;57;) (type 2) (result i32) + f32.const 0x1.4p+3 (;=10;) + unreachable + f32.ne + ) + (func (;58;) (type 2) (result i32) + unreachable + i32.wrap_i64 + ) + (func (;59;) (type 2) (result i32) + unreachable + memory.grow + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 1) + (global $a (;0;) (mut f32) f32.const 0x0p+0 (;=0;)) + (export "type-i32" (func 2)) + (export "type-i64" (func 3)) + (export "type-f32" (func 4)) + (export "type-f64" (func 5)) + (export "as-func-first" (func 6)) + (export "as-func-mid" (func 7)) + (export "as-func-last" (func 8)) + (export "as-func-value" (func 9)) + (export "as-block-first" (func 10)) + (export "as-block-mid" (func 11)) + (export "as-block-last" (func 12)) + (export "as-block-value" (func 13)) + (export "as-block-broke" (func 14)) + (export "as-loop-first" (func 15)) + (export "as-loop-mid" (func 16)) + (export "as-loop-last" (func 17)) + (export "as-loop-broke" (func 18)) + (export "as-br-value" (func 19)) + (export "as-br_if-cond" (func 20)) + (export "as-br_if-value" (func 21)) + (export "as-br_if-value-cond" (func 22)) + (export "as-br_table-index" (func 23)) + (export "as-br_table-value" (func 24)) + (export "as-br_table-value-2" (func 25)) + (export "as-br_table-value-index" (func 26)) + (export "as-br_table-value-and-index" (func 27)) + (export "as-return-value" (func 28)) + (export "as-if-cond" (func 29)) + (export "as-if-then" (func 30)) + (export "as-if-else" (func 31)) + (export "as-if-then-no-else" (func 32)) + (export "as-select-first" (func 33)) + (export "as-select-second" (func 34)) + (export "as-select-cond" (func 35)) + (export "as-call-first" (func 36)) + (export "as-call-mid" (func 37)) + (export "as-call-last" (func 38)) + (export "as-call_indirect-func" (func 39)) + (export "as-call_indirect-first" (func 40)) + (export "as-call_indirect-mid" (func 41)) + (export "as-call_indirect-last" (func 42)) + (export "as-local.set-value" (func 43)) + (export "as-local.tee-value" (func 44)) + (export "as-global.set-value" (func 45)) + (export "as-load-address" (func 46)) + (export "as-loadN-address" (func 47)) + (export "as-store-address" (func 48)) + (export "as-store-value" (func 49)) + (export "as-storeN-address" (func 50)) + (export "as-storeN-value" (func 51)) + (export "as-unary-operand" (func 52)) + (export "as-binary-left" (func 53)) + (export "as-binary-right" (func 54)) + (export "as-test-operand" (func 55)) + (export "as-compare-left" (func 56)) + (export "as-compare-right" (func 57)) + (export "as-convert-operand" (func 58)) + (export "as-memory.grow-size" (func 59)) + (elem (;0;) (i32.const 0) func $dummy3) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/unreached-valid.wast/0.print b/tests/snapshots/testsuite/unreached-valid.wast/0.print new file mode 100644 index 0000000000..792817850c --- /dev/null +++ b/tests/snapshots/testsuite/unreached-valid.wast/0.print @@ -0,0 +1,70 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (result i64))) + (func (;0;) (type 0) (param $cond i32) (result i32) + unreachable + i32.const 0 + local.get $cond + select + ) + (func (;1;) (type 0) (param $cond i32) (result i32) + i32.const 0 + unreachable + local.get $cond + select + ) + (func (;2;) (type 1) + 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 0x0p+0 (;=0;) + i32.const 0 + select + unreachable + ) + (func (;3;) (type 2) (result i32) + unreachable + select + i32.add + ) + (func (;4;) (type 3) (result i64) + unreachable + i64.const 0 + i32.const 0 + select + i64.add + ) + (func (;5;) (type 1) + unreachable + select + i32.eqz + drop + ) + (func (;6;) (type 1) + unreachable + select + ref.is_null + drop + ) + (export "select-trap-left" (func 0)) + (export "select-trap-right" (func 1)) + (export "select-unreached" (func 2)) + (export "select_unreached_result_1" (func 3)) + (export "select_unreached_result_2" (func 4)) + (export "unreachable-num" (func 5)) + (export "unreachable-ref" (func 6)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/unreached-valid.wast/5.print b/tests/snapshots/testsuite/unreached-valid.wast/5.print new file mode 100644 index 0000000000..da1010d5be --- /dev/null +++ b/tests/snapshots/testsuite/unreached-valid.wast/5.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + block (result f64) ;; label = @1 + block (result f32) ;; label = @2 + unreachable + i32.const 1 + br_table 0 (;@2;) 1 (;@1;) 1 (;@1;) + end + drop + f64.const 0x0p+0 (;=0;) + end + drop + ) + (export "meet-bottom" (func 0)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/unwind.wast/0.print b/tests/snapshots/testsuite/unwind.wast/0.print new file mode 100644 index 0000000000..f2f0ab6850 --- /dev/null +++ b/tests/snapshots/testsuite/unwind.wast/0.print @@ -0,0 +1,474 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) + i32.const 3 + i64.const 1 + unreachable + ) + (func (;1;) (type 0) + i32.const 3 + i64.const 1 + br 0 (;@0;) + ) + (func (;2;) (type 1) (result i32) + i32.const 3 + i64.const 1 + i32.const 9 + br 0 (;@0;) + ) + (func (;3;) (type 0) + i32.const 3 + i64.const 1 + i32.const 1 + br_if 0 (;@0;) + drop + drop + ) + (func (;4;) (type 1) (result i32) + i32.const 3 + i64.const 1 + i32.const 9 + i32.const 1 + br_if 0 (;@0;) + drop + drop + ) + (func (;5;) (type 0) + i32.const 3 + i64.const 1 + i32.const 0 + br_table 0 (;@0;) + ) + (func (;6;) (type 1) (result i32) + i32.const 3 + i64.const 1 + i32.const 9 + i32.const 0 + br_table 0 (;@0;) + ) + (func (;7;) (type 1) (result i32) + i32.const 3 + i64.const 1 + i32.const 9 + return + ) + (func (;8;) (type 0) + block ;; label = @1 + i32.const 3 + i64.const 1 + unreachable + end + ) + (func (;9;) (type 1) (result i32) + block ;; label = @1 + i32.const 3 + i64.const 1 + br 0 (;@1;) + end + i32.const 9 + ) + (func (;10;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + i64.const 1 + i32.const 9 + br 0 (;@1;) + end + ) + (func (;11;) (type 1) (result i32) + block ;; label = @1 + i32.const 3 + i64.const 1 + i32.const 1 + br_if 0 (;@1;) + drop + drop + end + i32.const 9 + ) + (func (;12;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + i64.const 1 + i32.const 9 + i32.const 1 + br_if 0 (;@1;) + drop + drop + end + ) + (func (;13;) (type 1) (result i32) + block ;; label = @1 + i32.const 3 + i64.const 1 + i32.const 0 + br_table 0 (;@1;) + end + i32.const 9 + ) + (func (;14;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + i64.const 1 + i32.const 9 + i32.const 0 + br_table 0 (;@1;) + end + ) + (func (;15;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + i64.const 1 + i32.const 9 + return + end + ) + (func (;16;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + block ;; label = @2 + i64.const 1 + unreachable + end + end + ) + (func (;17;) (type 1) (result i32) + block ;; label = @1 + i32.const 3 + block ;; label = @2 + i64.const 1 + br 1 (;@1;) + end + drop + end + i32.const 9 + ) + (func (;18;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + block ;; label = @2 + i64.const 1 + i32.const 9 + br 1 (;@1;) + end + end + ) + (func (;19;) (type 1) (result i32) + block ;; label = @1 + i32.const 3 + block ;; label = @2 + i64.const 1 + i32.const 1 + br_if 1 (;@1;) + drop + end + drop + end + i32.const 9 + ) + (func (;20;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + block ;; label = @2 + i64.const 1 + i32.const 9 + i32.const 1 + br_if 1 (;@1;) + drop + drop + end + end + ) + (func (;21;) (type 1) (result i32) + block ;; label = @1 + i32.const 3 + block ;; label = @2 + i64.const 1 + i32.const 1 + br_table 1 (;@1;) + end + drop + end + i32.const 9 + ) + (func (;22;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + block ;; label = @2 + i64.const 1 + i32.const 9 + i32.const 1 + br_table 1 (;@1;) + end + end + ) + (func (;23;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 3 + block ;; label = @2 + i64.const 1 + i32.const 9 + return + end + end + ) + (func (;24;) (type 1) (result i32) + f32.const 0x0p+0 (;=0;) + unreachable + i64.eqz + ) + (func (;25;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + i32.const 9 + br 0 (;@1;) + i64.eqz + end + ) + (func (;26;) (type 1) (result i32) + block (result i32) ;; label = @1 + i64.const 0 + i32.const 9 + i32.const 1 + br_if 0 (;@1;) + drop + i64.eqz + end + ) + (func (;27;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + i32.const 9 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + i64.eqz + end + ) + (func (;28;) (type 1) (result i32) + f32.const 0x0p+0 (;=0;) + i32.const 9 + return + i64.eqz + ) + (func (;29;) (type 1) (result i32) + f32.const 0x0p+0 (;=0;) + f64.const 0x1p+0 (;=1;) + unreachable + i64.eq + ) + (func (;30;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + f64.const 0x1p+0 (;=1;) + i32.const 9 + br 0 (;@1;) + i64.eq + end + ) + (func (;31;) (type 1) (result i32) + block (result i32) ;; label = @1 + i64.const 0 + i64.const 1 + i32.const 9 + i32.const 1 + br_if 0 (;@1;) + drop + i64.eq + end + ) + (func (;32;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + f64.const 0x1p+0 (;=1;) + i32.const 9 + i32.const 0 + br_table 0 (;@1;) + i64.eq + end + ) + (func (;33;) (type 1) (result i32) + f32.const 0x0p+0 (;=0;) + f64.const 0x1p+0 (;=1;) + i32.const 9 + return + i64.eq + ) + (func (;34;) (type 1) (result i32) + f32.const 0x0p+0 (;=0;) + f64.const 0x1p+0 (;=1;) + i64.const 0 + unreachable + select + ) + (func (;35;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + f64.const 0x1p+0 (;=1;) + i64.const 0 + i32.const 9 + br 0 (;@1;) + select + end + ) + (func (;36;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 1 + i32.const 0 + i32.const 9 + i32.const 1 + br_if 0 (;@1;) + drop + select + end + ) + (func (;37;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + f64.const 0x1p+0 (;=1;) + i64.const 0 + i32.const 9 + i32.const 0 + br_table 0 (;@1;) + select + end + ) + (func (;38;) (type 1) (result i32) + f32.const 0x0p+0 (;=0;) + f64.const 0x1p+0 (;=1;) + i64.const 1 + i32.const 9 + return + select + ) + (func (;39;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + unreachable + end + ) + (func (;40;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + i32.const 9 + br 0 (;@1;) + end + ) + (func (;41;) (type 1) (result i32) + block (result i32) ;; label = @1 + i32.const 0 + i32.const 9 + i32.const 1 + br_if 0 (;@1;) + drop + end + ) + (func (;42;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + i32.const 9 + i32.const 0 + br_table 0 (;@1;) 0 (;@1;) + end + ) + (func (;43;) (type 1) (result i32) + block (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + i32.const 9 + return + end + ) + (func (;44;) (type 1) (result i32) + loop (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + unreachable + end + ) + (func (;45;) (type 1) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + f32.const 0x0p+0 (;=0;) + i32.const 9 + br 1 (;@1;) + end + end + ) + (func (;46;) (type 1) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + i32.const 0 + i32.const 9 + i32.const 1 + br_if 1 (;@1;) + drop + end + end + ) + (func (;47;) (type 1) (result i32) + block (result i32) ;; label = @1 + loop (result i32) ;; label = @2 + f32.const 0x0p+0 (;=0;) + i32.const 9 + i32.const 0 + br_table 1 (;@1;) 1 (;@1;) + end + end + ) + (func (;48;) (type 1) (result i32) + loop (result i32) ;; label = @1 + f32.const 0x0p+0 (;=0;) + i32.const 9 + return + end + ) + (export "func-unwind-by-unreachable" (func 0)) + (export "func-unwind-by-br" (func 1)) + (export "func-unwind-by-br-value" (func 2)) + (export "func-unwind-by-br_if" (func 3)) + (export "func-unwind-by-br_if-value" (func 4)) + (export "func-unwind-by-br_table" (func 5)) + (export "func-unwind-by-br_table-value" (func 6)) + (export "func-unwind-by-return" (func 7)) + (export "block-unwind-by-unreachable" (func 8)) + (export "block-unwind-by-br" (func 9)) + (export "block-unwind-by-br-value" (func 10)) + (export "block-unwind-by-br_if" (func 11)) + (export "block-unwind-by-br_if-value" (func 12)) + (export "block-unwind-by-br_table" (func 13)) + (export "block-unwind-by-br_table-value" (func 14)) + (export "block-unwind-by-return" (func 15)) + (export "block-nested-unwind-by-unreachable" (func 16)) + (export "block-nested-unwind-by-br" (func 17)) + (export "block-nested-unwind-by-br-value" (func 18)) + (export "block-nested-unwind-by-br_if" (func 19)) + (export "block-nested-unwind-by-br_if-value" (func 20)) + (export "block-nested-unwind-by-br_table" (func 21)) + (export "block-nested-unwind-by-br_table-value" (func 22)) + (export "block-nested-unwind-by-return" (func 23)) + (export "unary-after-unreachable" (func 24)) + (export "unary-after-br" (func 25)) + (export "unary-after-br_if" (func 26)) + (export "unary-after-br_table" (func 27)) + (export "unary-after-return" (func 28)) + (export "binary-after-unreachable" (func 29)) + (export "binary-after-br" (func 30)) + (export "binary-after-br_if" (func 31)) + (export "binary-after-br_table" (func 32)) + (export "binary-after-return" (func 33)) + (export "select-after-unreachable" (func 34)) + (export "select-after-br" (func 35)) + (export "select-after-br_if" (func 36)) + (export "select-after-br_table" (func 37)) + (export "select-after-return" (func 38)) + (export "block-value-after-unreachable" (func 39)) + (export "block-value-after-br" (func 40)) + (export "block-value-after-br_if" (func 41)) + (export "block-value-after-br_table" (func 42)) + (export "block-value-after-return" (func 43)) + (export "loop-value-after-unreachable" (func 44)) + (export "loop-value-after-br" (func 45)) + (export "loop-value-after-br_if" (func 46)) + (export "loop-value-after-br_table" (func 47)) + (export "loop-value-after-return" (func 48)) +) \ No newline at end of file