diff --git a/.github/actions/binary-compatible-builds/main.js b/.github/actions/binary-compatible-builds/main.js index 378c5c202c9c..6230126fcb81 100755 --- a/.github/actions/binary-compatible-builds/main.js +++ b/.github/actions/binary-compatible-builds/main.js @@ -34,7 +34,7 @@ if (process.env.CENTOS !== undefined) { return; } -const name = process.env.INPUT_NAME; +const name = process.env.INPUT_NAME.replace(/-min$/, ''); child_process.execFileSync('docker', [ 'build', diff --git a/.github/actions/install-rust/action.yml b/.github/actions/install-rust/action.yml index 003c994f6dfc..b15c33c0a4cd 100644 --- a/.github/actions/install-rust/action.yml +++ b/.github/actions/install-rust/action.yml @@ -61,6 +61,14 @@ runs: CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse EOF + - name: Require semicolons in WIT + shell: bash + run: echo WIT_REQUIRE_SEMICOLONS=1 >> "$GITHUB_ENV" + + - name: Install the WASI target + shell: bash + run: rustup target add wasm32-wasi wasm32-unknown-unknown + - name: Choose registry cache key shell: bash # Update the registry index cache at most once per day. actions/cache diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d5b777e48338..fa44e2d9bb38 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -125,6 +125,7 @@ jobs: outputs: run-full: ${{ steps.calculate.outputs.run-full }} test-matrix: ${{ steps.calculate.outputs.test-matrix }} + build-matrix: ${{ steps.calculate.outputs.build-matrix }} test-capi: ${{ steps.calculate.outputs.test-capi }} build-fuzz: ${{ steps.calculate.outputs.build-fuzz }} audit: ${{ steps.calculate.outputs.audit }} @@ -170,6 +171,9 @@ jobs: echo "test-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT echo "$matrix" + matrix="$(node ./ci/build-build-matrix.js)" + echo "build-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT + if [ "$run_full" = "true" ]; then echo run-full=true >> $GITHUB_OUTPUT echo test-capi=true >> $GITHUB_OUTPUT @@ -196,7 +200,7 @@ jobs: submodules: true - uses: ./.github/actions/install-rust with: - toolchain: nightly-2023-07-02 + toolchain: nightly-2023-10-10 # Build C API documentation - run: curl -L https://sourceforge.net/projects/doxygen/files/rel-1.9.3/doxygen-1.9.3.linux.bin.tar.gz/download | tar xzf - @@ -266,8 +270,7 @@ jobs: # Check some feature combinations of the `wasmtime` crate - run: cargo check -p wasmtime --no-default-features - run: cargo check -p wasmtime --no-default-features --features wat - - run: cargo check -p wasmtime --no-default-features --features jitdump - - run: cargo check -p wasmtime --no-default-features --features vtune + - run: cargo check -p wasmtime --no-default-features --features profiling - run: cargo check -p wasmtime --no-default-features --features cache - run: cargo check -p wasmtime --no-default-features --features async - run: cargo check -p wasmtime --no-default-features --features pooling-allocator @@ -276,12 +279,20 @@ jobs: - run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache - run: cargo check -p wasmtime --no-default-features --features winch - run: cargo check -p wasmtime --no-default-features --features wmemcheck + - run: cargo check -p wasmtime --no-default-features --features demangle + - run: cargo check -p wasmtime --no-default-features --features addr2line - run: cargo check --features component-model - run: cargo check -p wasmtime --features incremental-cache + # Feature combinations of the `wasmtime-cli` + - run: cargo check -p wasmtime-cli --no-default-features + # Check that benchmarks of the cranelift project build - run: cargo check --benches -p cranelift-codegen + # Check that the bench-api compiles + - run: cargo check -p wasmtime-bench-api + # Check some feature combinations of the `wasmtime-c-api` crate - run: cargo check -p wasmtime-c-api --no-default-features - run: cargo check -p wasmtime-c-api --no-default-features --features wat @@ -356,7 +367,7 @@ jobs: # flags to rustc. - uses: ./.github/actions/install-rust with: - toolchain: nightly-2023-07-02 + toolchain: nightly-2023-10-10 - run: cargo install cargo-fuzz --vers "^0.11" # Install the OCaml packages necessary for fuzz targets that use the # `wasm-spec-interpreter`. @@ -383,9 +394,9 @@ jobs: name: ${{ matrix.name }} runs-on: ${{ matrix.os }} env: - QEMU_BUILD_VERSION: 8.0.4 + QEMU_BUILD_VERSION: 8.1.1 strategy: - fail-fast: true + fail-fast: false matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }} steps: - uses: actions/checkout@v3 @@ -405,8 +416,6 @@ jobs: if: matrix.target == 'x86_64-pc-windows-gnu' - run: cargo fetch --locked - - run: cargo fetch --locked --manifest-path crates/test-programs/wasi-tests/Cargo.toml - - run: cargo fetch --locked --manifest-path crates/test-programs/wasi-http-tests/Cargo.toml - uses: actions/cache@v3 with: @@ -444,7 +453,6 @@ jobs: # quickly. curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf - cd qemu-$QEMU_BUILD_VERSION - patch -p1 < $GITHUB_WORKSPACE/ci/qemu-cpuinfo.patch ./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache}}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs ninja -C build install touch ${{ runner.tool_cache }}/qemu/built @@ -502,7 +510,7 @@ jobs: submodules: true - uses: ./.github/actions/install-rust - run: rustup target add wasm32-wasi - - uses: abrown/install-openvino-action@v6 + - uses: abrown/install-openvino-action@v7 with: version: 2022.3.0 apt: true @@ -640,7 +648,7 @@ jobs: submodules: true - uses: ./.github/actions/install-rust with: - toolchain: nightly-2023-07-02 + toolchain: nightly-2023-10-10 - run: rustup component add rust-src miri - uses: actions/cache@v3 with: @@ -666,40 +674,28 @@ jobs: # Perform release builds of `wasmtime` and `libwasmtime.so`. Builds a variety # of platforms and architectures and then uploads the release artifacts to # this workflow run's list of artifacts. + # + # Note that the full matrix is computed by `ci/build-build-matrix.js`. build: needs: determine if: needs.determine.outputs.run-full name: Release build for ${{ matrix.build }} runs-on: ${{ matrix.os }} 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: x86_64-mingw - os: windows-latest - target: x86_64-pc-windows-gnu - - build: aarch64-linux - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - - build: s390x-linux - os: ubuntu-latest - target: s390x-unknown-linux-gnu - - build: riscv64gc-linux - os: ubuntu-latest - target: riscv64gc-unknown-linux-gnu + fail-fast: false + matrix: ${{ fromJson(needs.determine.outputs.build-matrix) }} steps: - uses: actions/checkout@v3 with: submodules: true + - uses: ./.github/actions/install-rust + with: + toolchain: ${{ matrix.rust }} + - run: | + rustup component add rust-src + rustup target add ${{ matrix.target }} + # On one builder produce the source tarball since there's no need to produce # it everywhere - run: ./ci/build-src-tarball.sh @@ -707,21 +703,13 @@ jobs: - uses: ./.github/actions/binary-compatible-builds with: name: ${{ matrix.build }} - - run: | - echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV - rustup target add ${{ matrix.target }} - if: matrix.target != '' - - # Build `wasmtime` and executables. Note that we include some non-default - # features so the # release artifacts can be maximally feature-ful. - - run: $CENTOS cargo build --release --bin wasmtime --features all-arch,component-model - # Build `libwasmtime.so` - - run: $CENTOS cargo build --release --manifest-path crates/c-api/Cargo.toml + - run: $CENTOS ./ci/build-release-artifacts.sh "${{ matrix.build }}" "${{ matrix.target }}" - # Assemble release artifats appropriate for this platform, then upload them + # Assemble release artifacts appropriate for this platform, then upload them # unconditionally to this workflow's files so we have a copy of them. - run: ./ci/build-tarballs.sh "${{ matrix.build }}" "${{ matrix.target }}" + - uses: actions/upload-artifact@v3 with: name: bins-${{ matrix.build }} diff --git a/.github/workflows/publish-artifacts.yml b/.github/workflows/publish-artifacts.yml index e036474d24eb..8c149003dc91 100644 --- a/.github/workflows/publish-artifacts.yml +++ b/.github/workflows/publish-artifacts.yml @@ -28,6 +28,8 @@ jobs: env: GH_TOKEN: ${{ github.token }} + - run: ./ci/merge-artifacts.sh + # Deploy the `gh-pages.tar.gz` artifact to the `gh-pages` branch. - run: tar xf gh-pages.tar.gz working-directory: gh-pages @@ -41,10 +43,6 @@ jobs: - run: npm install --production working-directory: .github/actions/github-release - - run: | - mkdir dist - mv -t dist bins-*/*.tar.* - mv -t dist bins-*/*.{zip,msi,wasm} - name: Publish Release uses: ./.github/actions/github-release with: diff --git a/.gitignore b/.gitignore index afb3ff15003f..7790b83f8725 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ foo publish vendor examples/build +examples/.cache +*.coredump diff --git a/Cargo.lock b/Cargo.lock index 66d4d35629ea..e6f02a19fb74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,9 +106,9 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +checksum = "a2e1373abdaa212b704512ec2bd8b26bd0b7d5c3f70117411a5d9a451383c859" dependencies = [ "derive_arbitrary", ] @@ -194,9 +194,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" @@ -226,7 +226,7 @@ checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-array-literals" -version = "14.0.0" +version = "15.0.0" [[package]] name = "byteorder" @@ -257,7 +257,7 @@ checksum = "b779b2d0a001c125b4584ad586268fb4b92d957bff8d26d7fe0dd78283faa814" dependencies = [ "cap-primitives", "cap-std", - "io-lifetimes 2.0.2", + "io-lifetimes", "windows-sys", ] @@ -269,7 +269,7 @@ checksum = "6ffc30dee200c20b4dcb80572226f42658e1d9c4b668656d7cc59c33d50e396e" dependencies = [ "cap-primitives", "cap-std", - "rustix 0.38.8", + "rustix", "smallvec", ] @@ -282,10 +282,10 @@ dependencies = [ "ambient-authority", "fs-set-times", "io-extras", - "io-lifetimes 2.0.2", + "io-lifetimes", "ipnet", "maybe-owned", - "rustix 0.38.8", + "rustix", "windows-sys", "winx", ] @@ -308,8 +308,8 @@ checksum = "84bade423fa6403efeebeafe568fdb230e8c590a275fba2ba978dd112efcf6e9" dependencies = [ "cap-primitives", "io-extras", - "io-lifetimes 2.0.2", - "rustix 0.38.8", + "io-lifetimes", + "rustix", ] [[package]] @@ -320,7 +320,7 @@ checksum = "7b9e3348a3510c4619b4c7a7bcdef09a71221da18f266bda3ed6b9aea2c509e2" dependencies = [ "cap-std", "rand", - "rustix 0.38.8", + "rustix", "uuid", ] @@ -332,7 +332,7 @@ checksum = "f8f52b3c8f4abfe3252fd0a071f3004aaa3b18936ec97bdbd8763ce03aff6247" dependencies = [ "cap-primitives", "once_cell", - "rustix 0.38.8", + "rustix", "winx", ] @@ -484,15 +484,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "command-tests" -version = "0.0.0" -dependencies = [ - "anyhow", - "getrandom", - "wit-bindgen", -] - [[package]] name = "component-fuzz-util" version = "0.0.0" @@ -566,7 +557,7 @@ dependencies = [ [[package]] name = "cranelift" -version = "0.101.0" +version = "0.102.0" dependencies = [ "cranelift-codegen", "cranelift-frontend", @@ -574,14 +565,14 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.101.0" +version = "0.102.0" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.101.0" +version = "0.102.0" dependencies = [ "anyhow", "bincode", @@ -609,25 +600,25 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.101.0" +version = "0.102.0" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.101.0" +version = "0.102.0" [[package]] name = "cranelift-control" -version = "0.101.0" +version = "0.102.0" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.101.0" +version = "0.102.0" dependencies = [ "serde", "serde_derive", @@ -658,6 +649,7 @@ dependencies = [ "serde", "serde_derive", "similar", + "smallvec", "target-lexicon", "thiserror", "toml", @@ -667,7 +659,7 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.101.0" +version = "0.102.0" dependencies = [ "cranelift-codegen", "hashbrown 0.14.0", @@ -691,7 +683,7 @@ dependencies = [ [[package]] name = "cranelift-interpreter" -version = "0.101.0" +version = "0.102.0" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -705,7 +697,7 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.101.0" +version = "0.102.0" dependencies = [ "codespan-reporting", "log", @@ -714,7 +706,7 @@ dependencies = [ [[package]] name = "cranelift-jit" -version = "0.101.0" +version = "0.102.0" dependencies = [ "anyhow", "cranelift", @@ -735,7 +727,7 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.101.0" +version = "0.102.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -747,7 +739,7 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.101.0" +version = "0.102.0" dependencies = [ "cranelift-codegen", "libc", @@ -756,7 +748,7 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.101.0" +version = "0.102.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -771,7 +763,7 @@ dependencies = [ [[package]] name = "cranelift-reader" -version = "0.101.0" +version = "0.102.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -781,7 +773,7 @@ dependencies = [ [[package]] name = "cranelift-serde" -version = "0.101.0" +version = "0.102.0" dependencies = [ "clap", "cranelift-codegen", @@ -828,7 +820,7 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.101.0" +version = "0.102.0" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1141,12 +1133,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fd-lock" @@ -1155,7 +1144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b0377f1edc77dbd1118507bc7a66e4ab64d2b90c66f90726dc801e73a8c68f9" dependencies = [ "cfg-if", - "rustix 0.38.8", + "rustix", "windows-sys", ] @@ -1218,8 +1207,8 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd738b84894214045e8414eaded76359b4a5773f0a0a56b16575110739cdcf39" dependencies = [ - "io-lifetimes 2.0.2", - "rustix 0.38.8", + "io-lifetimes", + "rustix", "windows-sys", ] @@ -1309,7 +1298,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "debugid", "fxhash", "serde", @@ -1589,18 +1578,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d3c230ee517ee76b1cc593b52939ff68deda3fae9e41eca426c6b4993df51c4" dependencies = [ - "io-lifetimes 2.0.2", - "windows-sys", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" -dependencies = [ - "hermit-abi 0.3.0", - "libc", + "io-lifetimes", "windows-sys", ] @@ -1618,13 +1596,12 @@ checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.0", - "io-lifetimes 1.0.10", - "rustix 0.37.13", + "rustix", "windows-sys", ] @@ -1664,9 +1641,9 @@ checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "ittapi" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e648c437172ce7d3ac35ca11a068755072054826fa455a916b43524fa4a62a7" +checksum = "6b996fe614c41395cdaedf3cf408a9534851090959d90d54a535f675550b64b1" dependencies = [ "anyhow", "ittapi-sys", @@ -1675,9 +1652,9 @@ dependencies = [ [[package]] name = "ittapi-sys" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b32a4d23f72548178dde54f3c12c6b6a08598e25575c0d0fa5bd861e0dc1a5" +checksum = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc" dependencies = [ "cc", ] @@ -1714,9 +1691,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libfuzzer-sys" @@ -1747,15 +1724,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "linux-raw-sys" -version = "0.3.3" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b085a4f2cde5781fc4b1717f2e86c62f5cda49de7ba99a7c2eae02b61c9064c" - -[[package]] -name = "linux-raw-sys" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "listenfd" @@ -1809,11 +1780,11 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memfd" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.37.13", + "rustix", ] [[package]] @@ -1854,6 +1825,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -1965,6 +1946,12 @@ dependencies = [ "pretty_env_logger 0.4.0", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "paste" version = "1.0.7" @@ -2081,17 +2068,6 @@ 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 = "quick-error" version = "1.2.3" @@ -2176,13 +2152,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "reactor-tests" -version = "0.1.0" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "redox_syscall" version = "0.2.13" @@ -2214,9 +2183,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4dcbd3a2ae7fb94b5813fa0e957c6ab51bf5d0a8ee1b69e0c2d0f1e6eb8485" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", @@ -2311,29 +2280,15 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.37.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79bef90eb6d984c72722595b5b1348ab39275a5e5123faca6863bf07d75a4e0" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes 1.0.10", - "libc", - "linux-raw-sys 0.3.3", - "windows-sys", -] - -[[package]] -name = "rustix" -version = "0.38.8" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "itoa", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys", "once_cell", "windows-sys", ] @@ -2484,6 +2439,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "similar" version = "2.2.0" @@ -2612,12 +2576,12 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27ce32341b2c0b70c144bbf35627fdc1ef18c76ced5e5e7b3ee8b5ba6b2ab6a0" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "cap-fs-ext", "cap-std", "fd-lock", - "io-lifetimes 2.0.2", - "rustix 0.38.8", + "io-lifetimes", + "rustix", "windows-sys", "winx", ] @@ -2630,15 +2594,14 @@ checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.13", + "rustix", "windows-sys", ] @@ -2677,27 +2640,22 @@ name = "test-programs" version = "0.0.0" dependencies = [ "anyhow", - "cap-rand", - "cap-std", + "base64", + "futures", + "getrandom", + "libc", + "sha2", + "url", + "wasi", + "wit-bindgen", +] + +[[package]] +name = "test-programs-artifacts" +version = "0.0.0" +dependencies = [ "cargo_metadata", - "cfg-if", "heck", - "http", - "http-body", - "http-body-util", - "hyper", - "is-terminal", - "lazy_static", - "tempfile", - "test-log", - "tokio", - "tracing", - "tracing-subscriber", - "wasi-cap-std-sync", - "wasi-common", - "wasmtime", - "wasmtime-wasi", - "wasmtime-wasi-http", "wit-component", ] @@ -2768,6 +2726,7 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys", @@ -2848,6 +2807,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", ] [[package]] @@ -2857,12 +2828,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", + "nu-ansi-term", "once_cell", "regex", "sharded-slab", "thread_local", "tracing", "tracing-core", + "tracing-log", ] [[package]] @@ -2877,15 +2850,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[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.8" @@ -2969,9 +2933,15 @@ dependencies = [ "which", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "verify-component-adapter" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "wasmparser", @@ -3021,7 +2991,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi-cap-std-sync" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "async-trait", @@ -3031,10 +3001,9 @@ dependencies = [ "cap-time-ext", "fs-set-times", "io-extras", - "io-lifetimes 2.0.2", - "is-terminal", + "io-lifetimes", "once_cell", - "rustix 0.38.8", + "rustix", "system-interface", "tempfile", "tracing", @@ -3044,34 +3013,31 @@ dependencies = [ [[package]] name = "wasi-common" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", - "bitflags 2.3.3", + "bitflags 2.4.1", "cap-rand", "cap-std", "io-extras", "log", - "rustix 0.38.8", + "rustix", + "tempfile", + "test-log", + "test-programs-artifacts", "thiserror", + "tokio", "tracing", + "tracing-subscriber", "wasmtime", + "wasmtime-wasi", "wiggle", "windows-sys", ] -[[package]] -name = "wasi-http-tests" -version = "0.0.0" -dependencies = [ - "anyhow", - "tokio", - "wit-bindgen", -] - [[package]] name = "wasi-preview1-component-adapter" -version = "14.0.0" +version = "15.0.0" dependencies = [ "byte-array-literals", "object", @@ -3080,34 +3046,16 @@ dependencies = [ "wit-bindgen", ] -[[package]] -name = "wasi-sockets-tests" -version = "0.0.0" -dependencies = [ - "anyhow", - "wit-bindgen", -] - -[[package]] -name = "wasi-tests" -version = "0.0.0" -dependencies = [ - "libc", - "once_cell", - "wasi", - "wit-bindgen", -] - [[package]] name = "wasi-tokio" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "cap-std", "cap-tempfile", "io-extras", - "io-lifetimes 2.0.2", - "rustix 0.38.8", + "io-lifetimes", + "rustix", "tempfile", "tokio", "wasi-cap-std-sync", @@ -3171,22 +3119,23 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-encoder" -version = "0.33.1" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39de0723a53d3c8f54bed106cfbc0d06b3e4d945c5c5022115a61e3b29183ae" +checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca" dependencies = [ "leb128", ] [[package]] name = "wasm-metadata" -version = "0.10.5" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fab01638cbecc57afec7b53ce0e28620b44d7ae1dea53120c96dd08486c07ce" +checksum = "14abc161bfda5b519aa229758b68f2a52b45a12b993808665c857d1a9a00223c" dependencies = [ "anyhow", "indexmap 2.0.0", "serde", + "serde_derive", "serde_json", "spdx", "wasm-encoder", @@ -3195,9 +3144,9 @@ dependencies = [ [[package]] name = "wasm-mutate" -version = "0.2.34" +version = "0.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730c1644f14f3dfa52d8c63bb26c6f3fe89ba80430f1ce29b0388e04825ec514" +checksum = "7b1e04b0c049b0a0c42dd108a56c5c92500076747363d3bf1e83e7f0f8b4dfe4" dependencies = [ "egg", "log", @@ -3209,9 +3158,9 @@ dependencies = [ [[package]] name = "wasm-smith" -version = "0.12.17" +version = "0.12.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "154bb82cb9f17e5c0773e192e800094583767f752077d5116be376de747539eb" +checksum = "fef779c243bbf04d9f03333c2cb50b98047c6dcc2a1db0cc7d0691e4135064b4" dependencies = [ "arbitrary", "flagset", @@ -3261,9 +3210,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.113.1" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a128cea7b8516703ab41b10a0b1aa9ba18d0454cd3792341489947ddeee268db" +checksum = "e06c0641a4add879ba71ccb3a1e4278fd546f76f1eafb21d8f7b07733b547cd5" dependencies = [ "indexmap 2.0.0", "semver", @@ -3280,9 +3229,9 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.2.66" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2e5e818f88cee5311e9a5df15cba0a8f772978baf3109af97004bce6e8e3c6" +checksum = "e74458a9bc5cc9c7108abfa0fe4dc88d5abf1f3baf194df3264985f17d559b5e" dependencies = [ "anyhow", "wasmparser", @@ -3290,7 +3239,7 @@ dependencies = [ [[package]] name = "wasmtime" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "async-trait", @@ -3331,14 +3280,14 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "14.0.0" +version = "15.0.0" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-bench-api" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "cap-std", @@ -3355,12 +3304,22 @@ dependencies = [ [[package]] name = "wasmtime-c-api" -version = "14.0.0" +version = "15.0.0" +dependencies = [ + "wasmtime-c-api-impl", +] + +[[package]] +name = "wasmtime-c-api-impl" +version = "15.0.0" dependencies = [ "anyhow", "cap-std", "env_logger 0.10.0", + "futures", + "log", "once_cell", + "tracing", "wasi-cap-std-sync", "wasi-common", "wasmtime", @@ -3379,7 +3338,7 @@ dependencies = [ [[package]] name = "wasmtime-cache" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "base64", @@ -3389,7 +3348,7 @@ dependencies = [ "log", "once_cell", "pretty_env_logger 0.5.0", - "rustix 0.38.8", + "rustix", "serde", "serde_derive", "sha2", @@ -3401,11 +3360,12 @@ dependencies = [ [[package]] name = "wasmtime-cli" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "async-trait", "bstr", + "bytes", "clap", "component-macro-test", "component-test-util", @@ -3413,6 +3373,8 @@ dependencies = [ "env_logger 0.10.0", "expect-test", "filecheck", + "http-body-util", + "hyper", "libc", "listenfd", "log", @@ -3420,16 +3382,16 @@ dependencies = [ "num_cpus", "once_cell", "rayon", - "rustix 0.38.8", + "rustix", "serde", "serde_derive", "serde_json", "target-lexicon", "tempfile", - "test-programs", + "test-programs-artifacts", "tokio", + "tracing", "walkdir", - "wasm-encoder", "wasmparser", "wasmtime", "wasmtime-cache", @@ -3444,27 +3406,27 @@ dependencies = [ "wasmtime-wasi-nn", "wasmtime-wasi-threads", "wasmtime-wast", - "wast 65.0.1", + "wast 66.0.2", "wat", "windows-sys", ] [[package]] name = "wasmtime-cli-flags" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "clap", "file-per-thread-logger", "humantime 2.1.0", - "pretty_env_logger 0.5.0", "rayon", + "tracing-subscriber", "wasmtime", ] [[package]] name = "wasmtime-component-macro" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "component-macro-test-helpers", @@ -3480,11 +3442,11 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "14.0.0" +version = "15.0.0" [[package]] name = "wasmtime-cranelift" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "cfg-if", @@ -3507,7 +3469,7 @@ dependencies = [ [[package]] name = "wasmtime-cranelift-shared" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -3521,10 +3483,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", - "atty", "clap", "cranelift-entity", "env_logger 0.10.0", @@ -3560,7 +3521,7 @@ dependencies = [ [[package]] name = "wasmtime-explorer" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "capstone", @@ -3574,12 +3535,13 @@ dependencies = [ [[package]] name = "wasmtime-fiber" -version = "14.0.0" +version = "15.0.0" dependencies = [ + "anyhow", "backtrace", "cc", "cfg-if", - "rustix 0.38.8", + "rustix", "wasmtime-asm-macros", "wasmtime-versioned-export-macros", "windows-sys", @@ -3642,7 +3604,7 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "14.0.0" +version = "15.0.0" dependencies = [ "addr2line", "anyhow", @@ -3654,7 +3616,7 @@ dependencies = [ "log", "object", "rustc-demangle", - "rustix 0.38.8", + "rustix", "serde", "serde_derive", "target-lexicon", @@ -3667,17 +3629,17 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "14.0.0" +version = "15.0.0" dependencies = [ "object", "once_cell", - "rustix 0.38.8", + "rustix", "wasmtime-versioned-export-macros", ] [[package]] name = "wasmtime-jit-icache-coherence" -version = "14.0.0" +version = "15.0.0" dependencies = [ "cfg-if", "libc", @@ -3686,7 +3648,7 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "cc", @@ -3700,8 +3662,9 @@ dependencies = [ "memoffset", "once_cell", "paste", + "proptest", "rand", - "rustix 0.38.8", + "rustix", "sptr", "wasm-encoder", "wasmtime-asm-macros", @@ -3715,7 +3678,7 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "14.0.0" +version = "15.0.0" dependencies = [ "cranelift-entity", "serde", @@ -3726,7 +3689,7 @@ dependencies = [ [[package]] name = "wasmtime-versioned-export-macros" -version = "14.0.0" +version = "15.0.0" dependencies = [ "proc-macro2", "quote", @@ -3735,11 +3698,11 @@ dependencies = [ [[package]] name = "wasmtime-wasi" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "async-trait", - "bitflags 2.3.3", + "bitflags 2.4.1", "bytes", "cap-fs-ext", "cap-net-ext", @@ -3749,17 +3712,20 @@ dependencies = [ "fs-set-times", "futures", "io-extras", - "io-lifetimes 2.0.2", - "is-terminal", + "io-lifetimes", "libc", + "log", "once_cell", - "rustix 0.38.8", + "rustix", "system-interface", + "tempfile", "test-log", + "test-programs-artifacts", "thiserror", "tokio", "tracing", "tracing-subscriber", + "url", "wasi-cap-std-sync", "wasi-common", "wasi-tokio", @@ -3770,10 +3736,11 @@ dependencies = [ [[package]] name = "wasmtime-wasi-http" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "async-trait", + "base64", "bytes", "futures", "http", @@ -3781,10 +3748,13 @@ dependencies = [ "http-body-util", "hyper", "rustls", - "thiserror", + "sha2", + "test-log", + "test-programs-artifacts", "tokio", "tokio-rustls", "tracing", + "tracing-subscriber", "wasmtime", "wasmtime-wasi", "webpki-roots", @@ -3792,7 +3762,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi-nn" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "openvino", @@ -3805,7 +3775,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi-threads" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "log", @@ -3817,17 +3787,17 @@ dependencies = [ [[package]] name = "wasmtime-wast" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "log", "wasmtime", - "wast 65.0.1", + "wast 66.0.2", ] [[package]] name = "wasmtime-winch" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -3842,7 +3812,7 @@ dependencies = [ [[package]] name = "wasmtime-wit-bindgen" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "heck", @@ -3852,7 +3822,7 @@ dependencies = [ [[package]] name = "wasmtime-wmemcheck" -version = "14.0.0" +version = "15.0.0" [[package]] name = "wast" @@ -3865,9 +3835,9 @@ dependencies = [ [[package]] name = "wast" -version = "65.0.1" +version = "66.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd8c1cbadf94a0b0d1071c581d3cfea1b7ed5192c79808dd15406e508dd0afb" +checksum = "93cb43b0ac6dd156f2c375735ccfd72b012a7c0a6e6d09503499b8d3cb6e6072" dependencies = [ "leb128", "memchr", @@ -3877,11 +3847,11 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.73" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3209e35eeaf483714f4c6be93f4a03e69aad5f304e3fa66afa7cb90fe1c8051f" +checksum = "e367582095d2903caeeea9acbb140e1db9c7677001efa4347c3687fd34fe7072" dependencies = [ - "wast 65.0.1", + "wast 66.0.2", ] [[package]] @@ -3913,11 +3883,11 @@ dependencies = [ [[package]] name = "wiggle" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "async-trait", - "bitflags 2.3.3", + "bitflags 2.4.1", "proptest", "thiserror", "tokio", @@ -3930,7 +3900,7 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "14.0.0" +version = "15.0.0" dependencies = [ "anyhow", "heck", @@ -3943,7 +3913,7 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "14.0.0" +version = "15.0.0" dependencies = [ "proc-macro2", "quote", @@ -3998,7 +3968,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "0.12.0" +version = "0.13.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -4131,25 +4101,25 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4857cedf8371f690bb6782a3e2b065c54d1b6661be068aaf3eac8b45e813fdf8" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "windows-sys", ] [[package]] name = "wit-bindgen" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a3e8e965dc50e6eb4410d9a11720719fadc6a1713803ea5f3be390b81c8279" +checksum = "c7d92ce0ca6b6074059413a9581a637550c3a740581c854f9847ec293c8aed71" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "wit-bindgen-rust-macro", ] [[package]] name = "wit-bindgen-core" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77255512565dfbd0b61de466e854918041d1da53c7bc049d6188c6e02643dc1e" +checksum = "565b945ae074886071eccf9cdaf8ccd7b959c2b0d624095bea5fe62003e8b3e0" dependencies = [ "anyhow", "wit-component", @@ -4158,54 +4128,44 @@ dependencies = [ [[package]] name = "wit-bindgen-rust" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c60e6ea8598d1380e792f13d557007834f0fb799fea6503408cbc5debb4ae" +checksum = "5695ff4e41873ed9ce56d2787e6b5772bdad9e70e2c1d2d160621d1762257f4f" dependencies = [ "anyhow", "heck", "wasm-metadata", "wit-bindgen-core", - "wit-bindgen-rust-lib", "wit-component", ] -[[package]] -name = "wit-bindgen-rust-lib" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fb7a43c7dc28b0b727d6ae01bf369981229b7539e768fba2b7a4df13feeeb" -dependencies = [ - "heck", - "wit-bindgen-core", -] - [[package]] name = "wit-bindgen-rust-macro" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cea5ed784da06da0e55836a6c160e7502dbe28771c2368a595e8606243bf22" +checksum = "a91835ea4231da1fe7971679d505ba14be7826e192b6357f08465866ef482e08" dependencies = [ "anyhow", "proc-macro2", + "quote", "syn 2.0.29", "wit-bindgen-core", "wit-bindgen-rust", - "wit-bindgen-rust-lib", "wit-component", ] [[package]] name = "wit-component" -version = "0.14.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af872ef43ecb73cc49c7bd2dd19ef9117168e183c78cf70000dca0e14b6a5473" +checksum = "e87488b57a08e2cbbd076b325acbe7f8666965af174d69d5929cd373bd54547f" dependencies = [ "anyhow", - "bitflags 2.3.3", + "bitflags 2.4.1", "indexmap 2.0.0", "log", "serde", + "serde_derive", "serde_json", "wasm-encoder", "wasm-metadata", @@ -4215,20 +4175,19 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dcd022610436a1873e60bfdd9b407763f2404adf7d1cb57912c7ae4059e57a5" +checksum = "f6ace9943d89bbf3dbbc71b966da0e7302057b311f36a4ac3d65ddfef17b52cf" dependencies = [ "anyhow", "id-arena", "indexmap 2.0.0", "log", - "pulldown-cmark", "semver", "serde", + "serde_derive", "serde_json", "unicode-xid", - "url", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9c1fca098d05..31a1ac788920 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,13 +22,13 @@ path = "src/bin/wasmtime.rs" doc = false [dependencies] -wasmtime = { workspace = true, features = ['cache', 'cranelift'] } -wasmtime-cache = { workspace = true } +wasmtime = { workspace = true } +wasmtime-cache = { workspace = true, optional = true } wasmtime-cli-flags = { workspace = true } -wasmtime-cranelift = { workspace = true } +wasmtime-cranelift = { workspace = true, optional = true } wasmtime-environ = { workspace = true } -wasmtime-explorer = { workspace = true } -wasmtime-wast = { workspace = true } +wasmtime-explorer = { workspace = true, optional = true } +wasmtime-wast = { workspace = true, optional = true } wasmtime-wasi = { workspace = true, default-features = true, features = [ "exit", ] } @@ -36,17 +36,24 @@ wasmtime-wasi-nn = { workspace = true, optional = true } wasmtime-wasi-threads = { workspace = true, optional = true } wasmtime-wasi-http = { workspace = true, optional = true } wasmtime-runtime = { workspace = true } -clap = { workspace = true, features = ["color", "suggestions", "derive"] } +clap = { workspace = true } anyhow = { workspace = true } target-lexicon = { workspace = true } once_cell = { workspace = true } listenfd = "1.0.0" -wat = { workspace = true } +wat = { workspace = true, optional = true } serde = { workspace = true } serde_derive = { workspace = true } serde_json = { workspace = true } wasmparser = { workspace = true } -wasm-encoder = { workspace = true } +tracing = { workspace = true } +log = { workspace = true } + +async-trait = { workspace = true } +bytes = { workspace = true } +tokio = { workspace = true, optional = true, features = [ "signal", "macros" ] } +hyper = { workspace = true, optional = true } +http-body-util = { workspace = true, optional = true } [target.'cfg(unix)'.dependencies] rustix = { workspace = true, features = ["mm", "param"] } @@ -59,9 +66,8 @@ log = { workspace = true } expect-test = { workspace = true } filecheck = { workspace = true } tempfile = { workspace = true } -test-programs = { path = "crates/test-programs" } wasmtime-runtime = { workspace = true } -tokio = { version = "1.8.0", features = ["rt", "time", "macros", "rt-multi-thread"] } +tokio = { workspace = true, features = ["rt", "time", "macros", "rt-multi-thread"] } wast = { workspace = true } criterion = "0.5.0" num_cpus = "1.13.0" @@ -78,6 +84,7 @@ libc = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } walkdir = { workspace = true } +test-programs-artifacts = { workspace = true } [target.'cfg(windows)'.dev-dependencies] windows-sys = { workspace = true, features = ["Win32_System_Memory"] } @@ -96,16 +103,9 @@ members = [ "cranelift/isle/islec", "cranelift/serde", "crates/bench-api", - "crates/c-api", - "crates/cli-flags", + "crates/c-api/artifact", "crates/environ/fuzz", - "crates/jit-icache-coherence", - "crates/test-programs/wasi-tests", - "crates/test-programs/wasi-http-tests", - "crates/test-programs/wasi-sockets-tests", - "crates/test-programs/command-tests", - "crates/test-programs/reactor-tests", - "crates/wmemcheck", + "crates/test-programs", "crates/wasi-preview1-component-adapter", "crates/wasi-preview1-component-adapter/verify", "crates/winch", @@ -122,66 +122,68 @@ exclude = [ ] [workspace.package] -version = "14.0.0" +version = "15.0.0" authors = ["The Wasmtime Project Developers"] edition = "2021" # Wasmtime's current policy is that this number can be no larger than the # current stable release of Rust minus 2. -rust-version = "1.70.0" +rust-version = "1.71.0" [workspace.dependencies] -wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "=14.0.0" } -wasmtime = { path = "crates/wasmtime", version = "14.0.0", default-features = false } -wasmtime-cache = { path = "crates/cache", version = "=14.0.0" } -wasmtime-cli-flags = { path = "crates/cli-flags", version = "=14.0.0" } -wasmtime-cranelift = { path = "crates/cranelift", version = "=14.0.0" } -wasmtime-cranelift-shared = { path = "crates/cranelift-shared", version = "=14.0.0" } -wasmtime-winch = { path = "crates/winch", version = "=14.0.0" } -wasmtime-environ = { path = "crates/environ", version = "=14.0.0" } -wasmtime-explorer = { path = "crates/explorer", version = "=14.0.0" } -wasmtime-fiber = { path = "crates/fiber", version = "=14.0.0" } -wasmtime-types = { path = "crates/types", version = "14.0.0" } -wasmtime-jit = { path = "crates/jit", version = "=14.0.0" } -wasmtime-jit-debug = { path = "crates/jit-debug", version = "=14.0.0" } -wasmtime-runtime = { path = "crates/runtime", version = "=14.0.0" } -wasmtime-wast = { path = "crates/wast", version = "=14.0.0" } -wasmtime-wasi = { path = "crates/wasi", version = "14.0.0", default-features = false } -wasmtime-wasi-http = { path = "crates/wasi-http", version = "=14.0.0", default-features = false } -wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "14.0.0" } -wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "14.0.0" } -wasmtime-component-util = { path = "crates/component-util", version = "=14.0.0" } -wasmtime-component-macro = { path = "crates/component-macro", version = "=14.0.0" } -wasmtime-asm-macros = { path = "crates/asm-macros", version = "=14.0.0" } -wasmtime-versioned-export-macros = { path = "crates/versioned-export-macros", version = "=14.0.0" } +arbitrary = { version = "1.3.1" } +wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "=15.0.0" } +wasmtime = { path = "crates/wasmtime", version = "15.0.0", default-features = false } +wasmtime-cache = { path = "crates/cache", version = "=15.0.0" } +wasmtime-cli-flags = { path = "crates/cli-flags", version = "=15.0.0" } +wasmtime-cranelift = { path = "crates/cranelift", version = "=15.0.0" } +wasmtime-cranelift-shared = { path = "crates/cranelift-shared", version = "=15.0.0" } +wasmtime-winch = { path = "crates/winch", version = "=15.0.0" } +wasmtime-environ = { path = "crates/environ", version = "=15.0.0" } +wasmtime-explorer = { path = "crates/explorer", version = "=15.0.0" } +wasmtime-fiber = { path = "crates/fiber", version = "=15.0.0" } +wasmtime-types = { path = "crates/types", version = "15.0.0" } +wasmtime-jit = { path = "crates/jit", version = "=15.0.0" } +wasmtime-jit-debug = { path = "crates/jit-debug", version = "=15.0.0" } +wasmtime-runtime = { path = "crates/runtime", version = "=15.0.0" } +wasmtime-wast = { path = "crates/wast", version = "=15.0.0" } +wasmtime-wasi = { path = "crates/wasi", version = "15.0.0", default-features = false } +wasmtime-wasi-http = { path = "crates/wasi-http", version = "=15.0.0", default-features = false } +wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "15.0.0" } +wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "15.0.0" } +wasmtime-component-util = { path = "crates/component-util", version = "=15.0.0" } +wasmtime-component-macro = { path = "crates/component-macro", version = "=15.0.0" } +wasmtime-asm-macros = { path = "crates/asm-macros", version = "=15.0.0" } +wasmtime-versioned-export-macros = { path = "crates/versioned-export-macros", version = "=15.0.0" } component-test-util = { path = "crates/misc/component-test-util" } component-fuzz-util = { path = "crates/misc/component-fuzz-util" } -wiggle = { path = "crates/wiggle", version = "=14.0.0", default-features = false } -wiggle-macro = { path = "crates/wiggle/macro", version = "=14.0.0" } -wiggle-generate = { path = "crates/wiggle/generate", version = "=14.0.0" } -wasi-common = { path = "crates/wasi-common", version = "=14.0.0" } -wasi-tokio = { path = "crates/wasi-common/tokio", version = "=14.0.0" } -wasi-cap-std-sync = { path = "crates/wasi-common/cap-std-sync", version = "=14.0.0" } +wiggle = { path = "crates/wiggle", version = "=15.0.0", default-features = false } +wiggle-macro = { path = "crates/wiggle/macro", version = "=15.0.0" } +wiggle-generate = { path = "crates/wiggle/generate", version = "=15.0.0" } +wasi-common = { path = "crates/wasi-common", version = "=15.0.0" } +wasi-tokio = { path = "crates/wasi-common/tokio", version = "=15.0.0" } +wasi-cap-std-sync = { path = "crates/wasi-common/cap-std-sync", version = "=15.0.0" } wasmtime-fuzzing = { path = "crates/fuzzing" } -wasmtime-jit-icache-coherence = { path = "crates/jit-icache-coherence", version = "=14.0.0" } -wasmtime-wit-bindgen = { path = "crates/wit-bindgen", version = "=14.0.0" } - -cranelift-wasm = { path = "cranelift/wasm", version = "0.101.0" } -cranelift-codegen = { path = "cranelift/codegen", version = "0.101.0" } -cranelift-frontend = { path = "cranelift/frontend", version = "0.101.0" } -cranelift-entity = { path = "cranelift/entity", version = "0.101.0" } -cranelift-native = { path = "cranelift/native", version = "0.101.0" } -cranelift-module = { path = "cranelift/module", version = "0.101.0" } -cranelift-interpreter = { path = "cranelift/interpreter", version = "0.101.0" } -cranelift-reader = { path = "cranelift/reader", version = "0.101.0" } +wasmtime-jit-icache-coherence = { path = "crates/jit-icache-coherence", version = "=15.0.0" } +wasmtime-wit-bindgen = { path = "crates/wit-bindgen", version = "=15.0.0" } +test-programs-artifacts = { path = 'crates/test-programs/artifacts' } + +cranelift-wasm = { path = "cranelift/wasm", version = "0.102.0" } +cranelift-codegen = { path = "cranelift/codegen", version = "0.102.0", default-features = false, features = ["std", "unwind"] } +cranelift-frontend = { path = "cranelift/frontend", version = "0.102.0" } +cranelift-entity = { path = "cranelift/entity", version = "0.102.0" } +cranelift-native = { path = "cranelift/native", version = "0.102.0" } +cranelift-module = { path = "cranelift/module", version = "0.102.0" } +cranelift-interpreter = { path = "cranelift/interpreter", version = "0.102.0" } +cranelift-reader = { path = "cranelift/reader", version = "0.102.0" } cranelift-filetests = { path = "cranelift/filetests" } -cranelift-object = { path = "cranelift/object", version = "0.101.0" } -cranelift-jit = { path = "cranelift/jit", version = "0.101.0" } +cranelift-object = { path = "cranelift/object", version = "0.102.0" } +cranelift-jit = { path = "cranelift/jit", version = "0.102.0" } cranelift-fuzzgen = { path = "cranelift/fuzzgen" } -cranelift-bforest = { path = "cranelift/bforest", version = "0.101.0" } -cranelift-control = { path = "cranelift/control", version = "0.101.0" } -cranelift = { path = "cranelift/umbrella", version = "0.101.0" } +cranelift-bforest = { path = "cranelift/bforest", version = "0.102.0" } +cranelift-control = { path = "cranelift/control", version = "0.102.0" } +cranelift = { path = "cranelift/umbrella", version = "0.102.0" } -winch-codegen = { path = "winch/codegen", version = "=0.12.0" } +winch-codegen = { path = "winch/codegen", version = "=0.13.0" } winch-filetests = { path = "winch/filetests" } winch-test-macros = { path = "winch/test-macros" } @@ -190,7 +192,7 @@ byte-array-literals = { path = "crates/wasi-preview1-component-adapter/byte-arra # Bytecode Alliance maintained dependencies: # --------------------------- -regalloc2 = "0.9.2" +regalloc2 = "0.9.3" # cap-std family: target-lexicon = { version = "0.12.3", default-features = false, features = ["std"] } @@ -207,18 +209,18 @@ io-extras = "0.18.0" rustix = "0.38.8" is-terminal = "0.4.0" # wit-bindgen: -wit-bindgen = { version = "0.11.0", default-features = false } +wit-bindgen = { version = "0.13.0", default-features = false } # wasm-tools family: -wasmparser = "0.113.1" -wat = "1.0.73" -wast = "65.0.1" -wasmprinter = "0.2.66" -wasm-encoder = "0.33.1" -wasm-smith = "0.12.17" -wasm-mutate = "0.2.34" -wit-parser = "0.11.1" -wit-component = "0.14.2" +wasmparser = "0.115.0" +wat = "1.0.77" +wast = "66.0.2" +wasmprinter = "0.2.70" +wasm-encoder = "0.35.0" +wasm-smith = "0.12.21" +wasm-mutate = "0.2.38" +wit-parser = "0.12.1" +wit-component = "0.16.0" # Non-Bytecode Alliance maintained dependencies: # -------------------------- @@ -229,7 +231,7 @@ windows-sys = "0.48.0" env_logger = "0.10" expect-test = "1.4.1" log = { version = "0.4.8", default-features = false } -clap = { version = "4.3.12", features = ["color", "suggestions", "derive"] } +clap = { version = "4.3.12", default-features = false, features = ["std", "derive"] } hashbrown = { version = "0.14", default-features = false } capstone = "0.9.0" once_cell = "1.12.0" @@ -253,40 +255,108 @@ tempfile = "3.1.0" filecheck = "0.5.0" libc = "0.2.60" file-per-thread-logger = "0.2.0" -tokio = { version = "1.26.0" } +tokio = { version = "1.26.0", features = [ "rt", "time" ] } +hyper = "=1.0.0-rc.3" +http = "0.2.9" +http-body = "=1.0.0-rc.2" +http-body-util = "=0.1.0-rc.2" bytes = "1.4" futures = { version = "0.3.27", default-features = false } indexmap = "2.0.0" pretty_env_logger = "0.5.0" syn = "2.0.25" test-log = { version = "0.2", default-features = false, features = ["trace"] } -tracing-subscriber = { version = "0.3.1", default-features = false, features = ['fmt', 'env-filter'] } +tracing-subscriber = { version = "0.3.1", default-features = false, features = ['fmt', 'env-filter', 'ansi', 'tracing-log'] } +url = "2.3.1" +# ============================================================================= +# +# Features for the Wasmtime CLI executable +# +# +# Note that many of these features are inherited from Wasmtime itself or +# otherwise configure the `wasmtime` crate's execution. Features are provided as +# compile-time switches to disable functionality primarily if one is interested +# in configuring binary size and or exploring the binary size implications of +# various features. Most features are enabled by default but most embeddings +# likely won't need all features. [features] default = [ - "jitdump", - "wasmtime/wat", - "wasmtime/parallel-compilation", - "vtune", + # All subcommands are included by default. + "compile", + "explore", + "serve", + "wast", + "config", + + # On-by-default WASI features "wasi-nn", "wasi-threads", "wasi-http", + + # Most features of Wasmtime are enabled by default. + "wat", + "parallel-compilation", "pooling-allocator", + "cache", + "logging", + "demangle", + "cranelift", + "profiling", + "coredump", + "addr2line", + "debug-builtins", + + # Enable some nice features of clap by default, but they come at a binary size + # cost, so allow disabling this through disabling of our own `default` + # feature. + "clap/default", ] -jitdump = ["wasmtime/jitdump"] -vtune = ["wasmtime/vtune"] + +# ======================================== +# Off-by-default features +# +# These features are off-by-default but may optionally be enabled. +all-arch = ["wasmtime/all-arch"] +winch = ["wasmtime/winch"] +wmemcheck = ["wasmtime/wmemcheck"] + +# This feature, when enabled, will statically compile out all logging statements +# throughout Wasmtime and its dependencies. +disable-logging = ["log/max_level_off", "tracing/max_level_off"] + +# ======================================== +# On-by-default features +# +# These features are all included in the `default` set above and this is +# the internal mapping for what they enable in Wasmtime itself. wasi-nn = ["dep:wasmtime-wasi-nn"] wasi-threads = ["dep:wasmtime-wasi-threads"] -wasi-http = ["dep:wasmtime-wasi-http", "wasmtime-wasi-http?/sync"] +wasi-http = ["component-model", "dep:wasmtime-wasi-http", "dep:tokio", "dep:hyper", "wasmtime-wasi-http?/sync"] pooling-allocator = ["wasmtime/pooling-allocator", "wasmtime-cli-flags/pooling-allocator"] -all-arch = ["wasmtime/all-arch"] component-model = [ "wasmtime/component-model", "wasmtime-wast/component-model", "wasmtime-cli-flags/component-model" ] -winch = ["wasmtime/winch"] -wmemcheck = ["wasmtime/wmemcheck"] +wat = ["dep:wat"] +cache = ["dep:wasmtime-cache", "wasmtime-cli-flags/cache"] +parallel-compilation = ["wasmtime-cli-flags/parallel-compilation"] +logging = ["wasmtime-cli-flags/logging"] +demangle = ["wasmtime/demangle"] +cranelift = ["wasmtime-cli-flags/cranelift", "dep:wasmtime-cranelift"] +profiling = ["wasmtime/profiling"] +coredump = ["wasmtime-cli-flags/coredump"] +addr2line = ["wasmtime/addr2line"] +debug-builtins = ["wasmtime/debug-builtins"] + +# CLI subcommands for the `wasmtime` executable. See `wasmtime $cmd --help` +# for more information on each subcommand. +serve = ["wasi-http", "component-model", "dep:http-body-util"] +explore = ["dep:wasmtime-explorer"] +wast = ["dep:wasmtime-wast"] +config = ["cache"] +compile = ["cranelift"] [[test]] name = "host_segfault" diff --git a/RELEASES.md b/RELEASES.md index 6d1ba437dda8..296ee1357d90 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,6 @@ -------------------------------------------------------------------------------- -## 14.0.0 +## 15.0.0 Unreleased. @@ -10,6 +10,204 @@ Unreleased. -------------------------------------------------------------------------------- +## 14.0.2 + +Released 2023-10-26 + +### Fixed + +* Make the `wasmtime::unix` module accessible on macOS again. + [#7360](https://github.com/bytecodealliance/wasmtime/pull/7360) + +* Inter-crate dependencies between `cranelift-*` crates now disable the + `default` feature meaning that it's possible for embedders to depend on + `cranelift-codegen` as well without the `default` feature. + [#7369](https://github.com/bytecodealliance/wasmtime/pull/7369) + +-------------------------------------------------------------------------------- + +## 14.0.1 + +Released 2023-10-23 + +### Fixed + +* Cranelift: preserve uext and sext flags for parameters on x86\_64 and apple + aarch64. Note that this does not affect Wasmtime and is only intended for + Cranelift embedders such as `rustc_codegen_cranelift`. + [#7333](https://github.com/bytecodealliance/wasmtime/pull/7333) + +-------------------------------------------------------------------------------- + +## 14.0.0 + +Released 2023-10-20 + +One of the larger changes in this release is a redesign of Wasmtime's CLI +arguments and where arguments are passed. This means that previous invocations +of the `wasmtime` CLI executable will need to be updated. No functionality was +removed but most of it is behind new flags. One major change is that Wasmtime +CLI flags are now grouped behind short options like `-O`. For example + + wasmtime run --opt-level 2 foo.wasm + +is now: + + wasmtime run -O opt-level=2 foo.wasm + +Additionally options prefixed with `--enable-*` or `--disable-*` now +consistently are considered boolean setters. For example: + + wasmtime run --disable-cache foo.wasm + +is now: + + wasmtime run -C cache=n foo.wasm + +Options can be explored with `wasmtime -C help` for example, and `wasmtime -h` +will show all option groups that can be expanded. + +Another major change in the CLI is that any CLI argument which positionally +comes after the wasm file specified will be passed as an argument to the guest +module. For example this invocations + + wasmtime run foo.wasm --epoch-interruption + +was previously accepted as enabling epoch interruption for the `foo.wasm` file. +This is now interpreted as if it were `./foo.wasm --epoch-interruption`, +however, passing the flag to the wasm file itself. Flags to Wasmtime must now +come after Wasmtime's subcommand (in this case `run`) and before the wasm file +that's being run, for example: + + wasmtime run -W epoch-interruption foo.wasm + +More information about this change can be found on +[#6925](https://github.com/bytecodealliance/wasmtime/pull/6925) and +[#6946](https://github.com/bytecodealliance/wasmtime/pull/6946). + +### Added + +* Added the `wasmtime::FrameInfo::module` method, which returns the + `wasmtime::Module` associated with the stack frame. + +* The `wasmtime::component::Linker` type now implements `Clone`. + [#7032](https://github.com/bytecodealliance/wasmtime/pull/7032) + +* Wasmtime's `TypedFunc` API now supports the `v128` WebAssembly type on x86\_64 + and aarch64. + [#7010](https://github.com/bytecodealliance/wasmtime/pull/7010) + +* Support for resources exported from a WebAssembly guest has been added to the + component `bindgen!` macro. + [#7050](https://github.com/bytecodealliance/wasmtime/pull/7050) + +* The C API now supports learning about a module's `image_range`. + [#7064](https://github.com/bytecodealliance/wasmtime/pull/7064) + +* Passing values between components is now possible with a more complete + implementation of type-checking of values. + [#7065](https://github.com/bytecodealliance/wasmtime/pull/7065) + +* Types representing resources can now be customized with `bindgen!`. + [#7069](https://github.com/bytecodealliance/wasmtime/pull/7069) + +* Wasm-defined globals and memories are now included in core dumps, and the + `wasmtime::WasmCoreDump` type is now serializable. + [#6935](https://github.com/bytecodealliance/wasmtime/pull/6935) + [#7078](https://github.com/bytecodealliance/wasmtime/pull/7078) + +* Initial experimental support for Intel MPK has been added to support running + more instances concurrently. + [#7072](https://github.com/bytecodealliance/wasmtime/pull/7072) + +* The implementation of `wasi:http` now supports inbound requests in addition to + outbound requests. A new `wasmtime serve` command is an example way of + handling http requests with wasm files. + [#7091](https://github.com/bytecodealliance/wasmtime/pull/7091) + +* The C API now supports Wasmtime's "host memory creation" API to customize the + allocation of linear memories. + [#7115](https://github.com/bytecodealliance/wasmtime/pull/7115) + +* The C API now supports asynchronous invocation of WebAssembly programs. + [#7106](https://github.com/bytecodealliance/wasmtime/pull/7106) + +* The C API now supports Wasmtime's `InstancePre` type. + [#7140](https://github.com/bytecodealliance/wasmtime/pull/7140) + +* The `wasi:sockets/ip-name-lookup` interface is now implemented by Wasmtime. + [#7109](https://github.com/bytecodealliance/wasmtime/pull/7109) + +### Changed + +* Wasmtime's CLI has been significantly overhauled. See the note above. + [#6925](https://github.com/bytecodealliance/wasmtime/pull/6925) + [#6946](https://github.com/bytecodealliance/wasmtime/pull/6946) + +* The `wasmtime::FrameInfo::module_name` has been removed, however you can now + get identical results by chaining `wasmtime::FrameInfo::module` and + `wasmtime::Module::name`: `my_frame.module().name()`. + +* WASI interfaces have seen significant work since the previous release. Streams + for example have a new backpressure and flushing design. Additionally WIT + `resource`s are now used ubiquitously throughout the specification and + implementation. + [#6877](https://github.com/bytecodealliance/wasmtime/pull/6877) + [#7029](https://github.com/bytecodealliance/wasmtime/pull/7029) + [#7090](https://github.com/bytecodealliance/wasmtime/pull/7090) + +* The implementation of `wasi:http` now uses `{input,output}-stream` from the + `wasi:io/streams` interface. + [#7056](https://github.com/bytecodealliance/wasmtime/pull/7056) + +* Lifting and lowering of the `list` component values has been significantly + optimized. + [#6971](https://github.com/bytecodealliance/wasmtime/pull/6971) + +* The `wasmtime-c-api` crate is now additionally built as an rlib as well as the + previous cdylib/staticlib combo. + [#6765](https://github.com/bytecodealliance/wasmtime/pull/6765) + +### Fixed + +* Support referencing stack slots in the DWARF debug info. + [#6960](https://github.com/bytecodealliance/wasmtime/pull/6960) + +* Printing unicode to stdio on Windows has been fixed. + [#6825](https://github.com/bytecodealliance/wasmtime/pull/6825) + +* Building for x86\_64-linux-android has been fixed. + [#7055](https://github.com/bytecodealliance/wasmtime/pull/7055) + +* Fixed stdout/stderr becoming nonblocking by accident with WASI preview2 on + macOS. + [#7058](https://github.com/bytecodealliance/wasmtime/pull/7058) + +* Fixed some character boundary-related panics in the preview2 implementation of + preview1. + [#7011](https://github.com/bytecodealliance/wasmtime/pull/7011) + +* Fixed an issue of guests sleeping for an incorrect amount of time with + preview2. + [#6993](https://github.com/bytecodealliance/wasmtime/pull/6993) + +* Cranelift will now return an error when running out of temporaries in a very + large function instead of panicking. + [#7114](https://github.com/bytecodealliance/wasmtime/pull/7114) + +-------------------------------------------------------------------------------- + +## 13.0.1 + +Released 2023-10-26 + +### Fixed + +* Make the `wasmtime::unix` module accessible on macOS again. + [#7360](https://github.com/bytecodealliance/wasmtime/pull/7360) + +-------------------------------------------------------------------------------- + ## 13.0.0 Released 2023-09-20 diff --git a/build.rs b/build.rs index b591af39d7cd..64584ca886c4 100644 --- a/build.rs +++ b/build.rs @@ -205,13 +205,34 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool { // We ignore tests that assert for traps on windows, given // that Winch doesn't encode unwind information for Windows, yet. if strategy == "Winch" { - if testsuite != "winch" { + let assert_trap = [ + "i32", + "i64", + "call_indirect", + "table_fill", + "table_init", + "table_copy", + "table_set", + "table_get", + ] + .contains(&testname); + + if assert_trap && env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() == "windows" { return true; } - let assert_trap = ["i32", "i64"].contains(&testname); + if testsuite == "misc_testsuite" { + // The misc/call_indirect is fully supported by Winch. + if testname != "call_indirect" { + return true; + } + } + if testsuite == "spec_testsuite" { + // The official table init and table copy tests are now supported. + return !["table_init", "table_copy"].contains(&testname); + } - if assert_trap && env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() == "windows" { + if testsuite != "winch" { return true; } } diff --git a/ci/build-build-matrix.js b/ci/build-build-matrix.js new file mode 100644 index 000000000000..23c2b6ebb060 --- /dev/null +++ b/ci/build-build-matrix.js @@ -0,0 +1,68 @@ +// Small script used to calculate the matrix of builds that are going to be +// done if CI decides to do a release build. +// +// This is a separate script primarily to write out all the release +// targets/platforms once and then duplicate them all with a "min" build. + +const array = [ + { + // The name of the build which shows up in the name of the artifact for + // Wasmtime's github releases. + "build": "x86_64-linux", + // The GitHub Actions platform that this build runs on + "os": "ubuntu-latest", + // The Rust target that will be used for the build. + "target": "x86_64-unknown-linux-gnu", + }, + { + "build": "aarch64-linux", + "os": "ubuntu-latest", + "target": "aarch64-unknown-linux-gnu", + }, + { + "build": "s390x-linux", + "os": "ubuntu-latest", + "target": "s390x-unknown-linux-gnu", + }, + { + "build": "riscv64gc-linux", + "os": "ubuntu-latest", + "target": "riscv64gc-unknown-linux-gnu", + }, + { + "build": "x86_64-macos", + "os": "macos-latest", + "target": "x86_64-apple-darwin", + }, + { + "build": "aarch64-macos", + "os": "macos-latest", + "target": "aarch64-apple-darwin", + }, + { + "build": "x86_64-windows", + "os": "windows-latest", + "target": "x86_64-pc-windows-msvc", + }, + { + "build": "x86_64-mingw", + "os": "windows-latest", + "target": "x86_64-pc-windows-gnu", + }, +]; + +const builds = []; +for (let build of array) { + // Perform a "deep clone" roundtripping through JSON for a copy of the build + // that's normal + build.rust = 'stable'; + builds.push(JSON.parse(JSON.stringify(build))); + + // Next generate a "min" build and add it to the builds list. Min builds + // require Nightly rust due to some nightly build options that are configured. + build.build += '-min'; + build.rust = 'nightly-2023-10-10'; + builds.push(build); +} + +console.log(JSON.stringify(builds)); diff --git a/ci/build-release-artifacts.sh b/ci/build-release-artifacts.sh new file mode 100755 index 000000000000..71c7888395cd --- /dev/null +++ b/ci/build-release-artifacts.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# A script to build the release artifacts of Wasmtime into the `target` +# directory. For now this is the CLI and the C API. Note that this script only +# produces the artifacts through Cargo and doesn't package things up. That's +# intended for the `build-tarballs.sh` script. +# +# This script takes a Rust target as its first input and optionally a parameter +# afterwards which can be "-min" to indicate that a minimal build should be +# produced with as many features as possible stripped out. + +set -ex + +build=$1 +target=$2 + +# Default build flags for release artifacts. Leave debugging for +# builds-from-source which have richer information anyway, and additionally the +# CLI won't benefit from catching unwinds and neither will the C API so use +# panic=abort in both situations. +export CARGO_PROFILE_RELEASE_STRIP=debuginfo +export CARGO_PROFILE_RELEASE_PANIC=abort + +if [[ "$build" = *-min ]]; then + # Configure a whole bunch of compile-time options which help reduce the size + # of the binary artifact produced. + export CARGO_PROFILE_RELEASE_OPT_LEVEL=s + export RUSTFLAGS=-Zlocation-detail=none + export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 + export CARGO_PROFILE_RELEASE_LTO=true + flags="-Zbuild-std=std,panic_abort --no-default-features -Zbuild-std-features=std_detect_dlsym_getauxval" + flags="$flags --features disable-logging" +else + # For release builds the CLI is built a bit more feature-ful than the Cargo + # defaults to provide artifacts that can do as much as possible. + bin_flags="--features all-arch,component-model" +fi + +cargo build --release $flags --target $target -p wasmtime-cli $bin_flags +cargo build --release $flags --target $target -p wasmtime-c-api diff --git a/ci/build-src-tarball.sh b/ci/build-src-tarball.sh index 571fcc47a3a7..c5d3c10fa9b7 100755 --- a/ci/build-src-tarball.sh +++ b/ci/build-src-tarball.sh @@ -18,3 +18,5 @@ cargo vendor > .cargo/config.toml tar -czf /tmp/$pkgname.tar.gz --transform "s/^\./$pkgname/S" --exclude=.git . mkdir -p dist mv /tmp/$pkgname.tar.gz dist/ + +rm .cargo/config.toml diff --git a/ci/build-tarballs.sh b/ci/build-tarballs.sh index eb6197c2a5ac..d8a249f113b1 100755 --- a/ci/build-tarballs.sh +++ b/ci/build-tarballs.sh @@ -1,19 +1,18 @@ #!/bin/bash # A small script used for assembling release tarballs for both the `wasmtime` -# binary and the C API. This is executed with two arguments, mostly coming from -# the CI matrix. +# binary and the C API. This is executed with two arguments, mostly coming +# from the CI matrix. # -# * The first argument is the name of the platform, used to name the release -# * The second argument is the "target", if present, currently only for -# cross-compiles +# * The first argument is the name of the "build", used to name the release. +# * The second argument is the Rust target that the build was performed for. # # This expects the build to already be done and will assemble release artifacts # in `dist/` set -ex -platform=$1 +build=$1 target=$2 rm -rf tmp @@ -25,8 +24,15 @@ if [[ $GITHUB_REF == refs/heads/release-* ]]; then tag=v$(./ci/print-current-version.sh) fi -bin_pkgname=wasmtime-$tag-$platform -api_pkgname=wasmtime-$tag-$platform-c-api +# For *-min builds produce the same named artifacts as the normal build and +# they'll get unioned together in a later step in the CI. +build_pkgname=$build +if [[ $build == *-min ]]; then + build_pkgname=${build%-min} +fi + +bin_pkgname=wasmtime-$tag-$build_pkgname +api_pkgname=wasmtime-$tag-$build_pkgname-c-api mkdir tmp/$api_pkgname mkdir tmp/$api_pkgname/lib @@ -37,47 +43,61 @@ cp LICENSE README.md tmp/$bin_pkgname cp -r crates/c-api/include tmp/$api_pkgname cp crates/c-api/wasm-c-api/include/wasm.h tmp/$api_pkgname/include -fmt=tar -if [ "$platform" = "x86_64-windows" ]; then - cp target/release/wasmtime.exe tmp/$bin_pkgname - cp target/release/{wasmtime.dll,wasmtime.lib,wasmtime.dll.lib} tmp/$api_pkgname/lib - fmt=zip - - # Generate a `*.msi` installer for Windows as well - export WT_VERSION=`cat Cargo.toml | sed -n 's/^version = "\([^"]*\)".*/\1/p'` - "$WIX/bin/candle" -arch x64 -out target/wasmtime.wixobj ci/wasmtime.wxs - "$WIX/bin/light" -out dist/$bin_pkgname.msi target/wasmtime.wixobj -ext WixUtilExtension - rm dist/$bin_pkgname.wixpdb -elif [ "$platform" = "x86_64-mingw" ]; then - cp target/x86_64-pc-windows-gnu/release/wasmtime.exe tmp/$bin_pkgname - cp target/x86_64-pc-windows-gnu/release/{wasmtime.dll,libwasmtime.a,libwasmtime.dll.a} tmp/$api_pkgname/lib - fmt=zip -elif [ "$platform" = "x86_64-macos" ]; then - # Postprocess the macOS dylib a bit to have a more reasonable `LC_ID_DYLIB` - # directive than the default one that comes out of the linker when typically - # doing `cargo build`. For more info see #984 - install_name_tool -id "@rpath/libwasmtime.dylib" target/release/libwasmtime.dylib - cp target/release/wasmtime tmp/$bin_pkgname - cp target/release/libwasmtime.{a,dylib} tmp/$api_pkgname/lib -elif [ "$platform" = "aarch64-macos" ]; then - install_name_tool -id "@rpath/libwasmtime.dylib" target/aarch64-apple-darwin/release/libwasmtime.dylib - cp target/aarch64-apple-darwin/release/wasmtime tmp/$bin_pkgname - cp target/aarch64-apple-darwin/release/libwasmtime.{a,dylib} tmp/$api_pkgname/lib -elif [ "$target" = "" ]; then - cp target/release/wasmtime tmp/$bin_pkgname - cp target/release/libwasmtime.{a,so} tmp/$api_pkgname/lib -else - cp target/$target/release/wasmtime tmp/$bin_pkgname - cp target/$target/release/libwasmtime.{a,so} tmp/$api_pkgname/lib +# For *-min builds rename artifacts with a `-min` suffix to avoid eventual +# clashes with the normal builds when the tarballs are unioned together. +if [[ $build == *-min ]]; then + min="-min" fi +fmt=tar + +case $build in + x86_64-windows*) + cp target/$target/release/wasmtime.exe tmp/$bin_pkgname/wasmtime$min.exe + cp target/$target/release/wasmtime.dll tmp/$api_pkgname/lib/wasmtime$min.dll + cp target/$target/release/wasmtime.lib tmp/$api_pkgname/lib/wasmtime$min.lib + cp target/$target/release/wasmtime.dll.lib tmp/$api_pkgname/lib/wasmtime$min.dll.lib + fmt=zip + + if [ "$min" = "" ]; then + # Generate a `*.msi` installer for Windows as well + export WT_VERSION=`cat Cargo.toml | sed -n 's/^version = "\([^"]*\)".*/\1/p'` + "$WIX/bin/candle" -arch x64 -out target/wasmtime.wixobj ci/wasmtime.wxs + "$WIX/bin/light" -out dist/$bin_pkgname.msi target/wasmtime.wixobj -ext WixUtilExtension + rm dist/$bin_pkgname.wixpdb + fi + ;; + + x86_64-mingw*) + cp target/$target/release/wasmtime.exe tmp/$bin_pkgname/wasmtime$min.exe + cp target/$target/release/wasmtime.dll tmp/$api_pkgname/lib/wasmtime$min.dll + cp target/$target/release/libwasmtime.a tmp/$api_pkgname/lib/libwasmtime$min.a + cp target/$target/release/libwasmtime.dll.a tmp/$api_pkgname/lib/libwasmtime$min.dll.a + fmt=zip + ;; + + *-macos*) + # Postprocess the macOS dylib a bit to have a more reasonable `LC_ID_DYLIB` + # directive than the default one that comes out of the linker when typically + # doing `cargo build`. For more info see #984 + install_name_tool -id "@rpath/libwasmtime$min.dylib" target/$target/release/libwasmtime.dylib + cp target/$target/release/wasmtime tmp/$bin_pkgname/wasmtime$min + cp target/$target/release/libwasmtime.a tmp/$api_pkgname/lib/libwasmtime$min.a + cp target/$target/release/libwasmtime.dylib tmp/$api_pkgname/lib/libwasmtime$min.dylib + ;; + + *) + cp target/$target/release/wasmtime tmp/$bin_pkgname/wasmtime$min + cp target/$target/release/libwasmtime.a tmp/$api_pkgname/lib/libwasmtime$min.a + cp target/$target/release/libwasmtime.so tmp/$api_pkgname/lib/libwasmtime$min.so + ;; +esac + mktarball() { dir=$1 if [ "$fmt" = "tar" ]; then - # this is a bit wonky, but the goal is to use `xz` with threaded compression - # to ideally get better performance with the `-T0` flag. - tar -cvf - -C tmp $dir | xz -9 -T0 > dist/$dir.tar.xz + 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 diff --git a/ci/build-test-matrix.js b/ci/build-test-matrix.js index 35c2c00efd57..5fee846d6787 100644 --- a/ci/build-test-matrix.js +++ b/ci/build-test-matrix.js @@ -91,17 +91,11 @@ const array = [ "target": "riscv64gc-unknown-linux-gnu", "gcc_package": "gcc-riscv64-linux-gnu", "gcc": "riscv64-linux-gnu-gcc", - "qemu": "qemu-riscv64 -cpu rv64,v=true,vlen=256,vext_spec=v1.0,zba=true,zbb=true,zbc=true,zbs=true,zbkb=true -L /usr/riscv64-linux-gnu", + "qemu": "qemu-riscv64 -cpu rv64,v=true,vlen=256,vext_spec=v1.0,zba=true,zbb=true,zbc=true,zbs=true,zbkb=true,zcb=true -L /usr/riscv64-linux-gnu", "qemu_target": "riscv64-linux-user", "name": "Test Linux riscv64", "filter": "linux-riscv64", "isa": "riscv64", - // There appears to be a miscompile in Rust 1.72 for riscv64 where - // wasmtime-wasi tests are segfaulting in CI with the stack pointing in - // Tokio. Updating rustc seems to do the trick, so without doing a full - // rigorous investigation this uses beta for now but Rust 1.73 should be - // good to go for this. - "rust": "beta-2023-09-10", } ]; diff --git a/ci/merge-artifacts.sh b/ci/merge-artifacts.sh new file mode 100755 index 000000000000..aece95e6c4ad --- /dev/null +++ b/ci/merge-artifacts.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Script to merge the outputs of a run on github actions to github releases. +# This is invoked from `.github/workflows/publish-artifacts.yml`. All previous +# artifacts from builds are located in `bins-*` folders. The main purpose of +# this script is to take the "min" build and merge it into the "normal" build to +# produce one final tarball. This means that the final artifacts will have both +# a normal and a min build in them for comparison and usage. + +set -ex + +# Prepare the upload folder and move all aritfacts that aren't being merged into +# this folder, e.g. the MSI installer and adapter wasm files. +rm -rf dist +mkdir dist +mv -t dist bins-*/*.{msi,wasm} + +# Merge tarballs and zips by searching for `*-min` builds, unpacking the +# min/normal builds, into the same destination, and then repacking into a +# tarball. +# +# Note that for now xz compression is used for the final artifact to try to get +# small artifacts, but it's left at the default level since a lot of artifacts +# are processed here and turning it up to the max 9 compression might take +# quite awhile on CI for this one builder to process. +for min in bins-*-min/*.tar.*; do + normal=${min/-min\//\/} + filename=$(basename $normal) + dir=${filename%.tar.gz} + + rm -rf tmp + mkdir tmp + tar xf $min -C tmp + tar xf $normal -C tmp + tar -cf - -C tmp $dir | xz -T0 > dist/$dir.tar.xz + rm $min $normal +done + +for min in bins-*-min/*.zip; do + normal=${min/-min\//\/} + filename=$(basename $normal) + dir=${filename%.zip} + + rm -rf tmp + mkdir tmp + (cd tmp && unzip -o ../$min) + (cd tmp && unzip -o ../$normal) + (cd tmp && 7z a ../dist/$dir.zip $dir/) + rm $min $normal +done + +# Copy over remaining source tarball into the dist folder +mv -t dist bins-*/*.tar.* diff --git a/ci/qemu-cpuinfo.patch b/ci/qemu-cpuinfo.patch deleted file mode 100644 index 261bcb593409..000000000000 --- a/ci/qemu-cpuinfo.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 5d05b046efb079360d0175164ee04947f20f9e66 Mon Sep 17 00:00:00 2001 -From: Afonso Bordado -Date: Tue, 21 Mar 2023 18:45:20 +0000 -Subject: [PATCH] linux-user: Emulate /proc/cpuinfo output for riscv - -RISC-V does not expose all extensions via hwcaps, thus some userspace -applications may want to query these via /proc/cpuinfo. - -Currently when querying this file the host's file is shown instead -which is slightly confusing. Emulate a basic /proc/cpuinfo file -with mmu info and an ISA string. ---- - linux-user/syscall.c | 34 ++++++++++++++++++++++++++++++++-- - tests/tcg/riscv64/cpuinfo.c | 30 ++++++++++++++++++++++++++++++ - 2 files changed, 62 insertions(+), 2 deletions(-) - create mode 100644 tests/tcg/riscv64/cpuinfo.c - -diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index 333e6b7026..e6d85e0e8a 100644 ---- a/linux-user/syscall.c -+++ b/linux-user/syscall.c -@@ -8231,7 +8231,8 @@ void target_exception_dump(CPUArchState *env, const char *fmt, int code) - } - - #if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN || \ -- defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA) -+ defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA) || \ -+ defined(TARGET_RISCV) - static int is_proc(const char *filename, const char *entry) - { - return strcmp(filename, entry) == 0; -@@ -8309,6 +8310,35 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd) - } - #endif - -+#if defined(TARGET_RISCV) -+static int open_cpuinfo(CPUArchState *cpu_env, int fd) -+{ -+ int i; -+ int num_cpus = sysconf(_SC_NPROCESSORS_ONLN); -+ RISCVCPU *cpu = env_archcpu(cpu_env); -+ const RISCVCPUConfig *cfg = riscv_cpu_cfg((CPURISCVState *) cpu_env); -+ char *isa_string = riscv_isa_string(cpu); -+ const char *mmu; -+ -+ if (cfg->mmu) { -+ mmu = (cpu_env->xl == MXL_RV32) ? "sv32" : "sv48"; -+ } else { -+ mmu = "none"; -+ } -+ -+ for (i = 0; i < num_cpus; i++) { -+ dprintf(fd, "processor\t: %d\n", i); -+ dprintf(fd, "hart\t\t: %d\n", i); -+ dprintf(fd, "isa\t\t: %s\n", isa_string); -+ dprintf(fd, "mmu\t\t: %s\n", mmu); -+ dprintf(fd, "uarch\t\t: qemu\n\n"); -+ } -+ -+ g_free(isa_string); -+ return 0; -+} -+#endif -+ - #if defined(TARGET_M68K) - static int open_hardware(CPUArchState *cpu_env, int fd) - { -@@ -8333,7 +8363,7 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int - #if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN - { "/proc/net/route", open_net_route, is_proc }, - #endif --#if defined(TARGET_SPARC) || defined(TARGET_HPPA) -+#if defined(TARGET_SPARC) || defined(TARGET_HPPA) || defined(TARGET_RISCV) - { "/proc/cpuinfo", open_cpuinfo, is_proc }, - #endif - #if defined(TARGET_M68K) -diff --git a/tests/tcg/riscv64/cpuinfo.c b/tests/tcg/riscv64/cpuinfo.c -new file mode 100644 -index 0000000000..296abd0a8c ---- /dev/null -+++ b/tests/tcg/riscv64/cpuinfo.c -@@ -0,0 +1,30 @@ -+#include -+#include -+#include -+#include -+ -+#define BUFFER_SIZE 1024 -+ -+int main(void) -+{ -+ char buffer[BUFFER_SIZE]; -+ FILE *fp = fopen("/proc/cpuinfo", "r"); -+ assert(fp != NULL); -+ -+ while (fgets(buffer, BUFFER_SIZE, fp) != NULL) { -+ if (strstr(buffer, "processor") != NULL) { -+ assert(strstr(buffer, "processor\t: ") == buffer); -+ } else if (strstr(buffer, "hart") != NULL) { -+ assert(strstr(buffer, "hart\t\t: ") == buffer); -+ } else if (strstr(buffer, "isa") != NULL) { -+ assert(strcmp(buffer, "isa\t\t: rv64imafdc_zicsr_zifencei\n") == 0); -+ } else if (strstr(buffer, "mmu") != NULL) { -+ assert(strcmp(buffer, "mmu\t\t: sv48\n") == 0); -+ } else if (strstr(buffer, "uarch") != NULL) { -+ assert(strcmp(buffer, "uarch\t\t: qemu\n") == 0); -+ } -+ } -+ -+ fclose(fp); -+ return 0; -+} --- -2.34.1 - diff --git a/ci/run-tests.sh b/ci/run-tests.sh index b29b6eb71d9b..db338dc2409e 100755 --- a/ci/run-tests.sh +++ b/ci/run-tests.sh @@ -1,14 +1,10 @@ #!/bin/bash cargo test \ - --features "test-programs/test_programs" \ --features wasi-threads \ --features wasi-http \ --features component-model \ + --features serve \ --workspace \ - --exclude 'wasmtime-wasi-*' \ - --exclude wasi-tests \ - --exclude wasi-http-tests \ - --exclude command-tests \ - --exclude reactor-tests \ + --exclude test-programs \ $@ diff --git a/ci/run-wasi-nn-example.sh b/ci/run-wasi-nn-example.sh index 74bab3bd30fc..6f433bc3eff2 100755 --- a/ci/run-wasi-nn-example.sh +++ b/ci/run-wasi-nn-example.sh @@ -39,7 +39,7 @@ pushd $WASMTIME_DIR/crates/wasi-nn/examples/classification-example cargo build --release --target=wasm32-wasi cp target/wasm32-wasi/release/wasi-nn-example.wasm $TMP_DIR popd -cargo run -- run --dir fixture::$TMP_DIR -S nn $TMP_DIR/wasi-nn-example.wasm +cargo run -- run --dir $TMP_DIR::fixture -S nn $TMP_DIR/wasi-nn-example.wasm # Build and run another example, this time using Wasmtime's graph flag to # preload the model. @@ -47,7 +47,7 @@ pushd $WASMTIME_DIR/crates/wasi-nn/examples/classification-example-named cargo build --release --target=wasm32-wasi cp target/wasm32-wasi/release/wasi-nn-example-named.wasm $TMP_DIR popd -cargo run -- run --dir fixture::$TMP_DIR -S nn,nn-graph=openvino::$TMP_DIR \ +cargo run -- run --dir $TMP_DIR::fixture -S nn,nn-graph=openvino::$TMP_DIR \ $TMP_DIR/wasi-nn-example-named.wasm # Clean up the temporary directory only if it was not specified (users may want diff --git a/ci/wasmtime.wxs b/ci/wasmtime.wxs index ec3a58f9aa13..0e947135d555 100644 --- a/ci/wasmtime.wxs +++ b/ci/wasmtime.wxs @@ -62,7 +62,7 @@ - + diff --git a/cranelift/Cargo.toml b/cranelift/Cargo.toml index f6b271112dbb..24577ddc1c2e 100644 --- a/cranelift/Cargo.toml +++ b/cranelift/Cargo.toml @@ -44,7 +44,7 @@ indicatif = "0.13.0" thiserror = { workspace = true } walkdir = { workspace = true } anyhow = { workspace = true } -clap = { workspace = true } +clap = { workspace = true, features = ['default'] } similar = { workspace = true } toml = { workspace = true } serde = { workspace = true } diff --git a/cranelift/bforest/Cargo.toml b/cranelift/bforest/Cargo.toml index d55fdad495ee..f620eb757029 100644 --- a/cranelift/bforest/Cargo.toml +++ b/cranelift/bforest/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-bforest" -version = "0.101.0" +version = "0.102.0" description = "A forest of B+-trees" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift-bforest" diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index 05bb88bed4a9..6697393e93af 100644 --- a/cranelift/codegen/Cargo.toml +++ b/cranelift/codegen/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-codegen" -version = "0.101.0" +version = "0.102.0" description = "Low-level code generator library" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift-codegen" @@ -16,7 +16,7 @@ edition.workspace = true anyhow = { workspace = true, optional = true } bumpalo = "3" capstone = { workspace = true, optional = true } -cranelift-codegen-shared = { path = "./shared", version = "0.101.0" } +cranelift-codegen-shared = { path = "./shared", version = "0.102.0" } cranelift-entity = { workspace = true } cranelift-bforest = { workspace = true } cranelift-control = { workspace = true } @@ -41,8 +41,8 @@ criterion = { version = "0.5.0", features = ["html_reports"] } similar = "2.1.0" [build-dependencies] -cranelift-codegen-meta = { path = "meta", version = "0.101.0" } -cranelift-isle = { path = "../isle/isle", version = "=0.101.0" } +cranelift-codegen-meta = { path = "meta", version = "0.102.0" } +cranelift-isle = { path = "../isle/isle", version = "=0.102.0" } [features] default = ["std", "unwind", "host-arch"] diff --git a/cranelift/codegen/meta/Cargo.toml b/cranelift/codegen/meta/Cargo.toml index 4b930571018d..f507cc873bbe 100644 --- a/cranelift/codegen/meta/Cargo.toml +++ b/cranelift/codegen/meta/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cranelift-codegen-meta" authors = ["The Cranelift Project Developers"] -version = "0.101.0" +version = "0.102.0" description = "Metaprogram for cranelift-codegen code generator library" license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/bytecodealliance/wasmtime" @@ -12,4 +12,4 @@ edition.workspace = true rustdoc-args = [ "--document-private-items" ] [dependencies] -cranelift-codegen-shared = { path = "../shared", version = "0.101.0" } +cranelift-codegen-shared = { path = "../shared", version = "0.102.0" } diff --git a/cranelift/codegen/meta/src/shared/immediates.rs b/cranelift/codegen/meta/src/shared/immediates.rs index 9f908c93da48..5584b5564bb9 100644 --- a/cranelift/codegen/meta/src/shared/immediates.rs +++ b/cranelift/codegen/meta/src/shared/immediates.rs @@ -181,6 +181,7 @@ impl Immediates { trapcode_values.insert("heap_oob", "HeapOutOfBounds"); trapcode_values.insert("int_ovf", "IntegerOverflow"); trapcode_values.insert("int_divz", "IntegerDivisionByZero"); + trapcode_values.insert("bad_toint", "BadConversionToInteger"); new_enum( "code", "ir::TrapCode", diff --git a/cranelift/codegen/meta/src/shared/settings.rs b/cranelift/codegen/meta/src/shared/settings.rs index e4e511b5e8cb..f632280145c8 100644 --- a/cranelift/codegen/meta/src/shared/settings.rs +++ b/cranelift/codegen/meta/src/shared/settings.rs @@ -63,6 +63,20 @@ pub(crate) fn define() -> SettingGroup { true, ); + settings.add_bool( + "enable_pcc", + "Enable proof-carrying code translation validation.", + r#" + This adds a proof-carrying-code mode. Proof-carrying code (PCC) is a strategy to verify + that the compiler preserves certain properties or invariants in the compiled code. + For example, a frontend that translates WebAssembly to CLIF can embed PCC facts in + the CLIF, and Cranelift will verify that the final machine code satisfies the stated + facts at each intermediate computed value. Loads and stores can be marked as "checked" + and their memory effects can be verified as safe. + "#, + false, + ); + // Note that Cranelift doesn't currently need an is_pie flag, because PIE is // just PIC where symbols can't be pre-empted, which can be expressed with the // `colocated` flag on external functions and global values. diff --git a/cranelift/codegen/shared/Cargo.toml b/cranelift/codegen/shared/Cargo.toml index 3575420fa117..d68f66091609 100644 --- a/cranelift/codegen/shared/Cargo.toml +++ b/cranelift/codegen/shared/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-codegen-shared" -version = "0.101.0" +version = "0.102.0" description = "For code shared between cranelift-codegen-meta and cranelift-codegen" license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/bytecodealliance/wasmtime" diff --git a/cranelift/codegen/src/binemit/mod.rs b/cranelift/codegen/src/binemit/mod.rs index d5582d87f3be..9eed2905c4cd 100644 --- a/cranelift/codegen/src/binemit/mod.rs +++ b/cranelift/codegen/src/binemit/mod.rs @@ -64,15 +64,21 @@ pub enum Reloc { /// Offset within page of TLVP slot. MachOAarch64TlsAdrPageOff12, - /// Aarch64 TLS GD - /// Set an ADRP immediate field to the top 21 bits of the final address. Checks for overflow. - /// This is equivalent to `R_AARCH64_TLSGD_ADR_PAGE21` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#relocations-for-thread-local-storage) - Aarch64TlsGdAdrPage21, + /// Aarch64 TLSDESC Adr Page21 + /// This is equivalent to `R_AARCH64_TLSDESC_ADR_PAGE21` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#57105thread-local-storage-descriptors) + Aarch64TlsDescAdrPage21, - /// Aarch64 TLS GD - /// Set the add immediate field to the low 12 bits of the final address. Does not check for overflow. - /// This is equivalent to `R_AARCH64_TLSGD_ADD_LO12_NC` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#relocations-for-thread-local-storage) - Aarch64TlsGdAddLo12Nc, + /// Aarch64 TLSDESC Ld64 Lo12 + /// This is equivalent to `R_AARCH64_TLSDESC_LD64_LO12` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#57105thread-local-storage-descriptors) + Aarch64TlsDescLd64Lo12, + + /// Aarch64 TLSDESC Add Lo12 + /// This is equivalent to `R_AARCH64_TLSGD_ADD_LO12` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#57105thread-local-storage-descriptors) + Aarch64TlsDescAddLo12, + + /// Aarch64 TLSDESC Call + /// This is equivalent to `R_AARCH64_TLSDESC_CALL` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#57105thread-local-storage-descriptors) + Aarch64TlsDescCall, /// AArch64 GOT Page /// Set the immediate value of an ADRP to bits 32:12 of X; check that –232 <= X < 232 @@ -85,12 +91,14 @@ pub enum Reloc { /// This is equivalent to `R_AARCH64_LD64_GOT_LO12_NC` (312) in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#static-aarch64-relocations) Aarch64Ld64GotLo12Nc, - /// procedure call. - /// call symbol - /// expands to the following assembly and relocation: - /// auipc ra, 0 - /// jalr ra, ra, 0 - RiscvCall, + /// RISC-V Call PLT: 32-bit PC-relative function call, macros call, tail (PIC) + /// + /// Despite having PLT in the name, this relocation is also used for normal calls. + /// The non-PLT version of this relocation has been deprecated. + /// + /// This is the `R_RISCV_CALL_PLT` relocation from the RISC-V ELF psABI document. + /// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#procedure-calls + RiscvCallPlt, /// RISC-V TLS GD: High 20 bits of 32-bit PC-relative TLS GD GOT reference, /// @@ -104,6 +112,12 @@ pub enum Reloc { /// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses RiscvPCRelLo12I, + /// High 20 bits of a 32-bit PC-relative GOT offset relocation + /// + /// This is the `R_RISCV_GOT_HI20` relocation from the RISC-V ELF psABI document. + /// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses + RiscvGotHi20, + /// s390x TLS GD64 - 64-bit offset of tls_index for GD symbol in GOT S390xTlsGd64, /// s390x TLS GDCall - marker to enable optimization of TLS calls @@ -125,15 +139,18 @@ impl fmt::Display for Reloc { Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"), Self::X86SecRel => write!(f, "SecRel"), Self::Arm32Call | Self::Arm64Call => write!(f, "Call"), - Self::RiscvCall => write!(f, "RiscvCall"), + Self::RiscvCallPlt => write!(f, "RiscvCallPlt"), Self::RiscvTlsGdHi20 => write!(f, "RiscvTlsGdHi20"), + Self::RiscvGotHi20 => write!(f, "RiscvGotHi20"), Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"), Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"), Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"), Self::MachOAarch64TlsAdrPage21 => write!(f, "MachOAarch64TlsAdrPage21"), Self::MachOAarch64TlsAdrPageOff12 => write!(f, "MachOAarch64TlsAdrPageOff12"), - Self::Aarch64TlsGdAdrPage21 => write!(f, "Aarch64TlsGdAdrPage21"), - Self::Aarch64TlsGdAddLo12Nc => write!(f, "Aarch64TlsGdAddLo12Nc"), + Self::Aarch64TlsDescAdrPage21 => write!(f, "Aarch64TlsDescAdrPage21"), + Self::Aarch64TlsDescLd64Lo12 => write!(f, "Aarch64TlsDescLd64Lo12"), + Self::Aarch64TlsDescAddLo12 => write!(f, "Aarch64TlsDescAddLo12"), + Self::Aarch64TlsDescCall => write!(f, "Aarch64TlsDescCall"), Self::Aarch64AdrGotPage21 => write!(f, "Aarch64AdrGotPage21"), Self::Aarch64Ld64GotLo12Nc => write!(f, "Aarch64AdrGotLo12Nc"), Self::S390xTlsGd64 => write!(f, "TlsGd64"), diff --git a/cranelift/codegen/src/context.rs b/cranelift/codegen/src/context.rs index 2dc62ee77fd5..ca3d5fb73628 100644 --- a/cranelift/codegen/src/context.rs +++ b/cranelift/codegen/src/context.rs @@ -237,6 +237,8 @@ impl Context { /// Run the verifier on the function. /// /// Also check that the dominator tree and control flow graph are consistent with the function. + /// + /// TODO: rename to "CLIF validate" or similar. pub fn verify<'a, FOI: Into>>(&self, fisa: FOI) -> VerifierResult<()> { let mut errors = VerifierErrors::default(); let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors); diff --git a/cranelift/codegen/src/egraph.rs b/cranelift/codegen/src/egraph.rs index e12b6fed39f2..b54c1e7b63d3 100644 --- a/cranelift/codegen/src/egraph.rs +++ b/cranelift/codegen/src/egraph.rs @@ -162,6 +162,7 @@ where let result = self.func.dfg.first_result(inst); self.value_to_opt_value[result] = orig_result; self.eclasses.union(result, orig_result); + self.func.dfg.merge_facts(result, orig_result); self.stats.union += 1; result } else { @@ -256,6 +257,11 @@ where // still works, but take *only* the subsuming // value, and break now. isle_ctx.ctx.eclasses.union(optimized_value, union_value); + isle_ctx + .ctx + .func + .dfg + .merge_facts(optimized_value, union_value); union_value = optimized_value; break; } @@ -273,6 +279,11 @@ where .ctx .eclasses .union(old_union_value, optimized_value); + isle_ctx + .ctx + .func + .dfg + .merge_facts(old_union_value, optimized_value); isle_ctx.ctx.eclasses.union(old_union_value, union_value); } @@ -342,6 +353,7 @@ where new_result ); self.value_to_opt_value[result] = new_result; + self.func.dfg.merge_facts(result, new_result); true } // Otherwise, generic side-effecting op -- always keep it, and @@ -658,7 +670,7 @@ pub(crate) struct Stats { pub(crate) elaborate_visit_node: u64, pub(crate) elaborate_memoize_hit: u64, pub(crate) elaborate_memoize_miss: u64, - pub(crate) elaborate_memoize_miss_remat: u64, + pub(crate) elaborate_remat: u64, pub(crate) elaborate_licm_hoist: u64, pub(crate) elaborate_func: u64, pub(crate) elaborate_func_pre_insts: u64, diff --git a/cranelift/codegen/src/egraph/cost.rs b/cranelift/codegen/src/egraph/cost.rs index 9cfb0894ca74..bc807df02dd1 100644 --- a/cranelift/codegen/src/egraph/cost.rs +++ b/cranelift/codegen/src/egraph/cost.rs @@ -33,12 +33,6 @@ use crate::ir::Opcode; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub(crate) struct Cost(u32); impl Cost { - pub(crate) fn at_level(&self, loop_level: usize) -> Cost { - let loop_level = std::cmp::min(2, loop_level); - let multiplier = 1u32 << ((10 * loop_level) as u32); - Cost(self.0.saturating_mul(multiplier)).finite() - } - pub(crate) fn infinity() -> Cost { // 2^32 - 1 is, uh, pretty close to infinite... (we use `Cost` // only for heuristics and always saturate so this suffices!) diff --git a/cranelift/codegen/src/egraph/elaborate.rs b/cranelift/codegen/src/egraph/elaborate.rs index 6acf83cba9ae..26c7378b2c7f 100644 --- a/cranelift/codegen/src/egraph/elaborate.rs +++ b/cranelift/codegen/src/egraph/elaborate.rs @@ -5,9 +5,10 @@ use super::cost::{pure_op_cost, Cost}; use super::domtree::DomTreeWithChildren; use super::Stats; use crate::dominator_tree::DominatorTree; -use crate::fx::FxHashSet; +use crate::fx::{FxHashMap, FxHashSet}; +use crate::hash_map::Entry as HashEntry; use crate::ir::{Block, Function, Inst, Value, ValueDef}; -use crate::loop_analysis::{Loop, LoopAnalysis, LoopLevel}; +use crate::loop_analysis::{Loop, LoopAnalysis}; use crate::scoped_hash_map::ScopedHashMap; use crate::trace; use crate::unionfind::UnionFind; @@ -56,6 +57,8 @@ pub(crate) struct Elaborator<'a> { elab_result_stack: Vec, /// Explicitly-unrolled block elaboration stack. block_stack: Vec, + /// Copies of values that have been rematerialized. + remat_copies: FxHashMap<(Block, Value), Value>, /// Stats for various events during egraph processing, to help /// with optimization of this infrastructure. stats: &'a mut Stats, @@ -95,7 +98,6 @@ enum ElabStackEntry { inst: Inst, result_idx: usize, num_args: usize, - remat: bool, before: Inst, }, } @@ -134,6 +136,7 @@ impl<'a> Elaborator<'a> { elab_stack: vec![], elab_result_stack: vec![], block_stack: vec![], + remat_copies: FxHashMap::default(), stats, } } @@ -211,26 +214,24 @@ impl<'a> Elaborator<'a> { // at this point, only the side-effecting skeleton), // then it must be computed and thus we give it zero // cost. - ValueDef::Result(inst, _) if self.func.layout.inst_block(inst).is_some() => { - best[value] = (Cost::zero(), value); - } ValueDef::Result(inst, _) => { - trace!(" -> value {}: result, computing cost", value); - let inst_data = &self.func.dfg.insts[inst]; - let loop_level = self - .func - .layout - .inst_block(inst) - .map(|block| self.loop_analysis.loop_level(block)) - .unwrap_or(LoopLevel::root()); - // N.B.: at this point we know that the opcode is - // pure, so `pure_op_cost`'s precondition is - // satisfied. - let cost = self.func.dfg.inst_values(inst).fold( - pure_op_cost(inst_data.opcode()).at_level(loop_level.level()), - |cost, value| cost + best[value].0, - ); - best[value] = (cost, value); + if let Some(_) = self.func.layout.inst_block(inst) { + best[value] = (Cost::zero(), value); + } else { + trace!(" -> value {}: result, computing cost", value); + let inst_data = &self.func.dfg.insts[inst]; + // N.B.: at this point we know that the opcode is + // pure, so `pure_op_cost`'s precondition is + // satisfied. + let cost = self + .func + .dfg + .inst_values(inst) + .fold(pure_op_cost(inst_data.opcode()), |cost, value| { + cost + best[value].0 + }); + best[value] = (cost, value); + } } }; debug_assert_ne!(best[value].0, Cost::infinity()); @@ -258,13 +259,49 @@ impl<'a> Elaborator<'a> { self.elab_result_stack.pop().unwrap() } + /// Possibly rematerialize the instruction producing the value in + /// `arg` and rewrite `arg` to refer to it, if needed. Returns + /// `true` if a rewrite occurred. + fn maybe_remat_arg( + remat_values: &FxHashSet, + func: &mut Function, + remat_copies: &mut FxHashMap<(Block, Value), Value>, + insert_block: Block, + before: Inst, + arg: &mut ElaboratedValue, + stats: &mut Stats, + ) -> bool { + // TODO (#7313): we may want to consider recursive + // rematerialization as well. We could process the arguments of + // the rematerialized instruction up to a certain depth. This + // would affect, e.g., adds-with-one-constant-arg, which are + // currently rematerialized. Right now we don't do this, to + // avoid the need for another fixpoint loop here. + if arg.in_block != insert_block && remat_values.contains(&arg.value) { + let new_value = match remat_copies.entry((insert_block, arg.value)) { + HashEntry::Occupied(o) => *o.get(), + HashEntry::Vacant(v) => { + let inst = func.dfg.value_def(arg.value).inst().unwrap(); + debug_assert_eq!(func.dfg.inst_results(inst).len(), 1); + let new_inst = func.dfg.clone_inst(inst); + func.layout.insert_inst(new_inst, before); + let new_result = func.dfg.inst_results(new_inst)[0]; + *v.insert(new_result) + } + }; + trace!("rematerialized {} as {}", arg.value, new_value); + arg.value = new_value; + stats.elaborate_remat += 1; + true + } else { + false + } + } + fn process_elab_stack(&mut self) { - while let Some(entry) = self.elab_stack.last() { + while let Some(entry) = self.elab_stack.pop() { match entry { - &ElabStackEntry::Start { value, before } => { - // We always replace the Start entry, so pop it now. - self.elab_stack.pop(); - + ElabStackEntry::Start { value, before } => { debug_assert_ne!(value, Value::reserved_value()); let value = self.func.dfg.resolve_aliases(value); @@ -283,39 +320,17 @@ impl<'a> Elaborator<'a> { // eclass. trace!("looking up best value for {}", value); let (_, best_value) = self.value_to_best_value[value]; - debug_assert_ne!(best_value, Value::reserved_value()); trace!("elaborate: value {} -> best {}", value, best_value); + debug_assert_ne!(best_value, Value::reserved_value()); + + if let Some(elab_val) = self.value_to_elaborated_value.get(&canonical_value) { + // Value is available; use it. + trace!("elaborate: value {} -> {:?}", value, elab_val); + self.stats.elaborate_memoize_hit += 1; + self.elab_result_stack.push(*elab_val); + continue; + } - let remat = if let Some(elab_val) = - self.value_to_elaborated_value.get(&canonical_value) - { - // Value is available. Look at the defined - // block, and determine whether this node kind - // allows rematerialization if the value comes - // from another block. If so, ignore the hit - // and recompute below. - let remat = elab_val.in_block != self.cur_block - && self.remat_values.contains(&best_value); - if !remat { - trace!("elaborate: value {} -> {:?}", value, elab_val); - self.stats.elaborate_memoize_hit += 1; - self.elab_result_stack.push(*elab_val); - continue; - } - trace!("elaborate: value {} -> remat", canonical_value); - self.stats.elaborate_memoize_miss_remat += 1; - // The op is pure at this point, so it is always valid to - // remove from this map. - self.value_to_elaborated_value.remove(&canonical_value); - true - } else { - // Value not available; but still look up - // whether it's been flagged for remat because - // this affects placement. - let remat = self.remat_values.contains(&best_value); - trace!(" -> not present in map; remat = {}", remat); - remat - }; self.stats.elaborate_memoize_miss += 1; // Now resolve the value to its definition to see @@ -363,7 +378,6 @@ impl<'a> Elaborator<'a> { inst, result_idx, num_args, - remat, before, }); @@ -376,21 +390,17 @@ impl<'a> Elaborator<'a> { } } - &ElabStackEntry::PendingInst { + ElabStackEntry::PendingInst { inst, result_idx, num_args, - remat, before, } => { - self.elab_stack.pop(); - trace!( - "PendingInst: {} result {} args {} remat {} before {}", + "PendingInst: {} result {} args {} before {}", inst, result_idx, num_args, - remat, before ); @@ -398,7 +408,7 @@ impl<'a> Elaborator<'a> { // point. Grab them and drain them out, removing // them. let arg_idx = self.elab_result_stack.len() - num_args; - let arg_values = &self.elab_result_stack[arg_idx..]; + let arg_values = &mut self.elab_result_stack[arg_idx..]; // Compute max loop depth. // @@ -444,16 +454,15 @@ impl<'a> Elaborator<'a> { // We know that this is a pure inst, because // non-pure roots have already been placed in the - // value-to-elab'd-value map and are never subject - // to remat, so they will not reach this stage of - // processing. + // value-to-elab'd-value map, so they will not + // reach this stage of processing. // // We now must determine the location at which we // place the instruction. This is the current // block *unless* we hoist above a loop when all // args are loop-invariant (and this op is pure). let (scope_depth, before, insert_block) = - if loop_hoist_level == self.loop_stack.len() || remat { + if loop_hoist_level == self.loop_stack.len() { // Depends on some value at the current // loop depth, or remat forces it here: // place it at the current location. @@ -486,16 +495,39 @@ impl<'a> Elaborator<'a> { insert_block ); - // Now we need to place `inst` at the computed - // location (just before `before`). Note that - // `inst` may already have been placed somewhere - // else, because a pure node may be elaborated at - // more than one place. In this case, we need to - // duplicate the instruction (and return the - // `Value`s for that duplicated instance - // instead). + // Now that we have the location for the + // instruction, check if any of its args are remat + // values. If so, and if we don't have a copy of + // the rematerializing instruction for this block + // yet, create one. + let mut remat_arg = false; + for arg_value in arg_values.iter_mut() { + if Self::maybe_remat_arg( + &self.remat_values, + &mut self.func, + &mut self.remat_copies, + insert_block, + before, + arg_value, + &mut self.stats, + ) { + remat_arg = true; + } + } + + // Now we need to place `inst` at the computed + // location (just before `before`). Note that + // `inst` may already have been placed somewhere + // else, because a pure node may be elaborated at + // more than one place. In this case, we need to + // duplicate the instruction (and return the + // `Value`s for that duplicated instance instead). + // + // Also clone if we rematerialized, because we + // don't want to rewrite the args in the original + // copy. trace!("need inst {} before {}", inst, before); - let inst = if self.func.layout.inst_block(inst).is_some() { + let inst = if self.func.layout.inst_block(inst).is_some() || remat_arg { // Clone the inst! let new_inst = self.func.dfg.clone_inst(inst); trace!( @@ -612,7 +644,16 @@ impl<'a> Elaborator<'a> { // Elaborate the arg, placing any newly-inserted insts // before `before`. Get the updated value, which may // be different than the original. - let new_arg = self.elaborate_eclass_use(*arg, before); + let mut new_arg = self.elaborate_eclass_use(*arg, before); + Self::maybe_remat_arg( + &self.remat_values, + &mut self.func, + &mut self.remat_copies, + block, + inst, + &mut new_arg, + &mut self.stats, + ); trace!(" -> rewrote arg to {:?}", new_arg); *arg = new_arg.value; } diff --git a/cranelift/codegen/src/ir/dfg.rs b/cranelift/codegen/src/ir/dfg.rs index 76b1b08cbeea..501a7f0a4ef4 100644 --- a/cranelift/codegen/src/ir/dfg.rs +++ b/cranelift/codegen/src/ir/dfg.rs @@ -5,6 +5,7 @@ use crate::ir; use crate::ir::builder::ReplaceBuilder; use crate::ir::dynamic_type::{DynamicTypeData, DynamicTypes}; use crate::ir::instructions::{CallInfo, InstructionData}; +use crate::ir::pcc::Fact; use crate::ir::{ types, Block, BlockCall, ConstantData, ConstantPool, DynamicType, ExtFuncData, FuncRef, Immediate, Inst, JumpTables, RelSourceLoc, SigRef, Signature, Type, Value, @@ -125,6 +126,9 @@ pub struct DataFlowGraph { /// Primary value table with entries for all values. values: PrimaryMap, + /// Facts: proof-carrying-code assertions about values. + pub facts: SecondaryMap>, + /// Function signature table. These signatures are referenced by indirect call instructions as /// well as the external function references. pub signatures: PrimaryMap, @@ -158,6 +162,7 @@ impl DataFlowGraph { dynamic_types: DynamicTypes::new(), value_lists: ValueListPool::new(), values: PrimaryMap::new(), + facts: SecondaryMap::new(), signatures: PrimaryMap::new(), old_signatures: SecondaryMap::new(), ext_funcs: PrimaryMap::new(), @@ -183,6 +188,7 @@ impl DataFlowGraph { self.constants.clear(); self.immediates.clear(); self.jump_tables.clear(); + self.facts.clear(); } /// Get the total number of instructions created in this function, whether they are currently @@ -953,7 +959,13 @@ impl DataFlowGraph { // Get the controlling type variable. let ctrl_typevar = self.ctrl_typevar(inst); // Create new result values. - self.make_inst_results(new_inst, ctrl_typevar); + let num_results = self.make_inst_results(new_inst, ctrl_typevar); + // Copy over PCC facts, if any. + for i in 0..num_results { + let old_result = self.inst_results(inst)[i]; + let new_result = self.inst_results(new_inst)[i]; + self.facts[new_result] = self.facts[old_result].clone(); + } new_inst } @@ -1279,6 +1291,38 @@ impl DataFlowGraph { pub fn detach_block_params(&mut self, block: Block) -> ValueList { self.blocks[block].params.take() } + + /// Merge the facts for two values. If both values have facts and + /// they differ, both values get a special "conflict" fact that is + /// never satisfied. + pub fn merge_facts(&mut self, a: Value, b: Value) { + let a = self.resolve_aliases(a); + let b = self.resolve_aliases(b); + match (&self.facts[a], &self.facts[b]) { + (Some(a), Some(b)) if a == b => { /* nothing */ } + (None, None) => { /* nothing */ } + (Some(a), None) => { + self.facts[b] = Some(a.clone()); + } + (None, Some(b)) => { + self.facts[a] = Some(b.clone()); + } + (Some(a_fact), Some(b_fact)) => { + assert_eq!(self.value_type(a), self.value_type(b)); + let merged = Fact::intersect(a_fact, b_fact); + crate::trace!( + "facts merge on {} and {}: {:?}, {:?} -> {:?}", + a, + b, + a_fact, + b_fact, + merged, + ); + self.facts[a] = Some(merged.clone()); + self.facts[b] = Some(merged); + } + } + } } /// Contents of a basic block. diff --git a/cranelift/codegen/src/ir/entities.rs b/cranelift/codegen/src/ir/entities.rs index f33e198c0936..af2b0efc9488 100644 --- a/cranelift/codegen/src/ir/entities.rs +++ b/cranelift/codegen/src/ir/entities.rs @@ -209,6 +209,29 @@ impl GlobalValue { } } +/// An opaque reference to a memory type. +/// +/// A `MemoryType` is a descriptor of a struct layout in memory, with +/// types and proof-carrying-code facts optionally attached to the +/// fields. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct MemoryType(u32); +entity_impl!(MemoryType, "mt"); + +impl MemoryType { + /// Create a new memory type reference from its number. + /// + /// This method is for use by the parser. + pub fn with_number(n: u32) -> Option { + if n < u32::MAX { + Some(Self(n)) + } else { + None + } + } +} + /// An opaque reference to a constant. /// /// You can store [`ConstantData`](super::ConstantData) in a @@ -412,6 +435,8 @@ pub enum AnyEntity { DynamicType(DynamicType), /// A Global value. GlobalValue(GlobalValue), + /// A memory type. + MemoryType(MemoryType), /// A jump table. JumpTable(JumpTable), /// A constant. @@ -437,6 +462,7 @@ impl fmt::Display for AnyEntity { Self::DynamicStackSlot(r) => r.fmt(f), Self::DynamicType(r) => r.fmt(f), Self::GlobalValue(r) => r.fmt(f), + Self::MemoryType(r) => r.fmt(f), Self::JumpTable(r) => r.fmt(f), Self::Constant(r) => r.fmt(f), Self::FuncRef(r) => r.fmt(f), @@ -495,6 +521,12 @@ impl From for AnyEntity { } } +impl From for AnyEntity { + fn from(r: MemoryType) -> Self { + Self::MemoryType(r) + } +} + impl From for AnyEntity { fn from(r: JumpTable) -> Self { Self::JumpTable(r) diff --git a/cranelift/codegen/src/ir/function.rs b/cranelift/codegen/src/ir/function.rs index f5b85c50af80..5d91e705e9eb 100644 --- a/cranelift/codegen/src/ir/function.rs +++ b/cranelift/codegen/src/ir/function.rs @@ -5,10 +5,10 @@ use crate::entity::{PrimaryMap, SecondaryMap}; use crate::ir::{ - self, Block, DataFlowGraph, DynamicStackSlot, DynamicStackSlotData, DynamicStackSlots, - DynamicType, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Inst, JumpTable, - JumpTableData, Layout, Opcode, SigRef, Signature, SourceLocs, StackSlot, StackSlotData, - StackSlots, Table, TableData, Type, + self, pcc::Fact, Block, DataFlowGraph, DynamicStackSlot, DynamicStackSlotData, + DynamicStackSlots, DynamicType, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Inst, + JumpTable, JumpTableData, Layout, MemoryType, MemoryTypeData, Opcode, SigRef, Signature, + SourceLocs, StackSlot, StackSlotData, StackSlots, Table, TableData, Type, }; use crate::isa::CallConv; use crate::write::write_function; @@ -172,6 +172,12 @@ pub struct FunctionStencil { /// Global values referenced. pub global_values: PrimaryMap, + /// Global value proof-carrying-code facts. + pub global_value_facts: SecondaryMap>, + + /// Memory types for proof-carrying code. + pub memory_types: PrimaryMap, + /// Tables referenced. pub tables: PrimaryMap, @@ -201,6 +207,8 @@ impl FunctionStencil { self.sized_stack_slots.clear(); self.dynamic_stack_slots.clear(); self.global_values.clear(); + self.global_value_facts.clear(); + self.memory_types.clear(); self.tables.clear(); self.dfg.clear(); self.layout.clear(); @@ -235,6 +243,11 @@ impl FunctionStencil { self.global_values.push(data) } + /// Declares a memory type for use by the function. + pub fn create_memory_type(&mut self, data: MemoryTypeData) -> MemoryType { + self.memory_types.push(data) + } + /// Find the global dyn_scale value associated with given DynamicType. pub fn get_dyn_scale(&self, ty: DynamicType) -> GlobalValue { self.dfg.dynamic_types.get(ty).unwrap().dynamic_scale @@ -314,7 +327,17 @@ impl FunctionStencil { pub fn is_leaf(&self) -> bool { // Conservative result: if there's at least one function signature referenced in this // function, assume it is not a leaf. - self.dfg.signatures.is_empty() + let has_signatures = !self.dfg.signatures.is_empty(); + + // Under some TLS models, retrieving the address of a TLS variable requires calling a + // function. Conservatively assume that any function that references a tls global value + // is not a leaf. + let has_tls = self.global_values.values().any(|gv| match gv { + GlobalValueData::Symbol { tls, .. } => *tls, + _ => false, + }); + + !has_signatures && !has_tls } /// Replace the `dst` instruction's data with the `src` instruction's data @@ -398,6 +421,8 @@ impl Function { sized_stack_slots: StackSlots::new(), dynamic_stack_slots: DynamicStackSlots::new(), global_values: PrimaryMap::new(), + global_value_facts: SecondaryMap::new(), + memory_types: PrimaryMap::new(), tables: PrimaryMap::new(), dfg: DataFlowGraph::new(), layout: Layout::new(), diff --git a/cranelift/codegen/src/ir/globalvalue.rs b/cranelift/codegen/src/ir/globalvalue.rs index 530875641e43..438a13e50119 100644 --- a/cranelift/codegen/src/ir/globalvalue.rs +++ b/cranelift/codegen/src/ir/globalvalue.rs @@ -1,7 +1,7 @@ //! Global values. use crate::ir::immediates::{Imm64, Offset32}; -use crate::ir::{ExternalName, GlobalValue, Type}; +use crate::ir::{ExternalName, GlobalValue, MemFlags, Type}; use crate::isa::TargetIsa; use core::fmt; @@ -31,9 +31,8 @@ pub enum GlobalValueData { /// Type of the loaded value. global_type: Type, - /// Specifies whether the memory that this refers to is readonly, allowing for the - /// elimination of redundant loads. - readonly: bool, + /// Specifies the memory flags to be used by the load. Guaranteed to be notrap and aligned. + flags: MemFlags, }, /// Value is an offset from another global value. @@ -111,15 +110,8 @@ impl fmt::Display for GlobalValueData { base, offset, global_type, - readonly, - } => write!( - f, - "load.{} notrap aligned {}{}{}", - global_type, - if readonly { "readonly " } else { "" }, - base, - offset - ), + flags, + } => write!(f, "load.{}{} {}{}", global_type, flags, base, offset), Self::IAddImm { global_type, base, diff --git a/cranelift/codegen/src/ir/memflags.rs b/cranelift/codegen/src/ir/memflags.rs index 87165ba69117..546e11fa3703 100644 --- a/cranelift/codegen/src/ir/memflags.rs +++ b/cranelift/codegen/src/ir/memflags.rs @@ -6,10 +6,19 @@ use core::fmt; use serde_derive::{Deserialize, Serialize}; enum FlagBit { + /// Guaranteed not to trap. This may enable additional + /// optimizations to be performed. Notrap, + /// Guaranteed to use "natural alignment" for the given type. This + /// may enable better instruction selection. Aligned, + /// A load that reads data in memory that does not change for the + /// duration of the function's execution. This may enable + /// additional optimizations to be performed. Readonly, + /// Load multi-byte values from memory in a little-endian format. LittleEndian, + /// Load multi-byte values from memory in a big-endian format. BigEndian, /// Accesses only the "heap" part of abstract state. Used for /// alias analysis. Mutually exclusive with "table" and "vmctx". @@ -20,10 +29,15 @@ enum FlagBit { /// Accesses only the "vmctx" part of abstract state. Used for /// alias analysis. Mutually exclusive with "heap" and "table". Vmctx, + /// Check this load or store for safety when using the + /// proof-carrying-code framework. The address must have a + /// `PointsTo` fact attached with a sufficiently large valid range + /// for the accessed size. + Checked, } -const NAMES: [&str; 8] = [ - "notrap", "aligned", "readonly", "little", "big", "heap", "table", "vmctx", +const NAMES: [&str; 9] = [ + "notrap", "aligned", "readonly", "little", "big", "heap", "table", "vmctx", "checked", ]; /// Endianness of a memory access. @@ -48,7 +62,7 @@ pub enum Endianness { #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct MemFlags { - bits: u8, + bits: u16, } impl MemFlags { @@ -265,6 +279,32 @@ impl MemFlags { self.set_vmctx(); self } + + /// Test if the `checked` bit is set. + /// + /// Loads and stores with this flag are verified to access + /// pointers only with a validated `PointsTo` fact attached, and + /// with that fact validated, when using the proof-carrying-code + /// framework. If initial facts on program inputs are correct + /// (i.e., correctly denote the shape and types of data structures + /// in memory), and if PCC validates the compiled output, then all + /// `checked`-marked memory accesses are guaranteed (up to the + /// checker's correctness) to access valid memory. This can be + /// used to ensure memory safety and sandboxing. + pub fn checked(self) -> bool { + self.read(FlagBit::Checked) + } + + /// Set the `checked` bit. + pub fn set_checked(&mut self) { + self.set(FlagBit::Checked); + } + + /// Set the `checked` bit, returning new flags. + pub fn with_checked(mut self) -> Self { + self.set_checked(); + self + } } impl fmt::Display for MemFlags { diff --git a/cranelift/codegen/src/ir/memtype.rs b/cranelift/codegen/src/ir/memtype.rs new file mode 100644 index 000000000000..403661d89c82 --- /dev/null +++ b/cranelift/codegen/src/ir/memtype.rs @@ -0,0 +1,181 @@ +//! Definitions for "memory types" in CLIF. +//! +//! A memory type is a struct-like definition -- fields with offsets, +//! each field having a type and possibly an attached fact -- that we +//! can use in proof-carrying code to validate accesses to structs and +//! propagate facts onto the loaded values as well. +//! +//! Memory types are meant to be rich enough to describe the *layout* +//! of values in memory, but do not necessarily need to embody +//! higher-level features such as subtyping directly. Rather, they +//! should encode an implementation of a type or object system. +//! +//! Note also that it is a non-goal for now for this type system to be +//! "complete" or fully orthogonal: we have some restrictions now +//! (e.g., struct fields are only primitives) because this is all we +//! need for existing PCC applications, and it keeps the +//! implementation simpler. +//! +//! There are a few basic kinds of types: +//! +//! - A struct is an aggregate of fields and an overall size. Each +//! field has a *primitive Cranelift type*. This is for simplicity's +//! sake: we do not allow nested memory types because to do so +//! invites cycles, requires recursive computation of sizes, creates +//! complicated questions when field types are dynamically-sized, +//! and in general is more complexity than we need. +//! +//! The expectation (validated by PCC) is that when a checked load +//! or store accesses memory typed by a memory type, accesses will +//! only be to fields at offsets named in the type, and will be via +//! the given Cranelift type -- i.e., no type-punning occurs in +//! memory. +//! +//! The overall size of the struct may be larger than that implied +//! by the fields because (i) we may not want or need to name all +//! the actually-existing fields in the memory type, and (ii) there +//! may be alignment padding that we also don't want or need to +//! represent explicitly. +//! +//! - A static memory is an untyped blob of storage with a static +//! size. This is memory that can be accessed with any type of load +//! or store at any valid offset. +//! +//! Note that this is *distinct* from an "array of u8" kind of +//! representation of memory, if/when we can represent such a thing, +//! because the expectation with memory types' fields (including +//! array elements) is that they are strongly typed, only accessed +//! via that type, and not type-punned. We don't want to imply any +//! restriction on load/store size, or any actual structure, with +//! untyped memory; it's just a blob. +//! +//! Eventually we plan to also have: +//! +//! - A dynamic memory is an untyped blob of storage with a size given +//! by a global value (GV). This is otherwise just like the "static +//! memory" variant described above. +//! +//! - A dynamic array is a sequence of struct memory types, with a +//! length given by a global value (GV). This is useful to model, +//! e.g., tables. +//! +//! - A discriminated union is a union of several memory types +//! together with a tag field. This will be useful to model and +//! verify subtyping/downcasting for Wasm GC, among other uses. +//! +//! - Nullability on pointer fields: the fact will hold only if the +//! field is not null (all zero bits). + +use crate::ir::pcc::Fact; +use crate::ir::Type; +use alloc::vec::Vec; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// Data defining a memory type. +/// +/// A memory type corresponds to a layout of data in memory. It may +/// have a statically-known or dynamically-known size. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum MemoryTypeData { + /// An aggregate consisting of certain fields at certain offsets. + /// + /// Fields must be sorted by offset, must be within the struct's + /// overall size, and must not overlap. These conditions are + /// checked by the CLIF verifier. + Struct { + /// Size of this type. + size: u64, + + /// Fields in this type. Sorted by offset. + fields: Vec, + }, + + /// A statically-sized untyped blob of memory. + Memory { + /// Accessible size. + size: u64, + }, + + /// A type with no size. + Empty, +} + +impl std::default::Default for MemoryTypeData { + fn default() -> Self { + Self::Empty + } +} + +impl std::fmt::Display for MemoryTypeData { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Struct { size, fields } => { + write!(f, "struct {size} {{")?; + let mut first = true; + for field in fields { + if first { + first = false; + } else { + write!(f, ",")?; + } + write!(f, " {}: {}", field.offset, field.ty)?; + if field.readonly { + write!(f, " readonly")?; + } + if let Some(fact) = &field.fact { + write!(f, " ! {}", fact)?; + } + } + write!(f, " }}")?; + Ok(()) + } + Self::Memory { size } => { + write!(f, "memory {size:#x}") + } + Self::Empty => { + write!(f, "empty") + } + } + } +} + +/// One field in a memory type. +#[derive(Clone, PartialEq, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct MemoryTypeField { + /// The offset of this field in the memory type. + pub offset: u64, + /// The primitive type of the value in this field. Accesses to the + /// field must use this type (i.e., cannot bitcast/type-pun in + /// memory). + pub ty: Type, + /// A proof-carrying-code fact about this value, if any. + pub fact: Option, + /// Whether this field is read-only, i.e., stores should be + /// disallowed. + pub readonly: bool, +} + +impl MemoryTypeField { + /// Get the fact, if any, on a field. + pub fn fact(&self) -> Option<&Fact> { + self.fact.as_ref() + } +} + +impl MemoryTypeData { + /// Provide the static size of this type, if known. + /// + /// (The size may not be known for dynamically-sized arrays or + /// memories, when those memtype kinds are added.) + pub fn static_size(&self) -> Option { + match self { + Self::Struct { size, .. } => Some(*size), + Self::Memory { size } => Some(*size), + Self::Empty => Some(0), + } + } +} diff --git a/cranelift/codegen/src/ir/mod.rs b/cranelift/codegen/src/ir/mod.rs index 986f8003722c..e2ec87d67205 100644 --- a/cranelift/codegen/src/ir/mod.rs +++ b/cranelift/codegen/src/ir/mod.rs @@ -18,6 +18,8 @@ pub(crate) mod known_symbol; pub mod layout; pub(crate) mod libcall; mod memflags; +mod memtype; +pub mod pcc; mod progpoint; mod sourceloc; pub mod stackslot; @@ -37,7 +39,7 @@ pub use crate::ir::dfg::{BlockData, DataFlowGraph, ValueDef}; pub use crate::ir::dynamic_type::{dynamic_to_fixed, DynamicTypeData, DynamicTypes}; pub use crate::ir::entities::{ Block, Constant, DynamicStackSlot, DynamicType, FuncRef, GlobalValue, Immediate, Inst, - JumpTable, SigRef, StackSlot, Table, UserExternalNameRef, Value, + JumpTable, MemoryType, SigRef, StackSlot, Table, UserExternalNameRef, Value, }; pub use crate::ir::extfunc::{ AbiParam, ArgumentExtension, ArgumentPurpose, ExtFuncData, Signature, @@ -53,6 +55,7 @@ pub use crate::ir::known_symbol::KnownSymbol; pub use crate::ir::layout::Layout; pub use crate::ir::libcall::{get_probestack_funcref, LibCall}; pub use crate::ir::memflags::{Endianness, MemFlags}; +pub use crate::ir::memtype::{MemoryTypeData, MemoryTypeField}; pub use crate::ir::progpoint::ProgramPoint; pub use crate::ir::sourceloc::RelSourceLoc; pub use crate::ir::sourceloc::SourceLoc; diff --git a/cranelift/codegen/src/ir/pcc.rs b/cranelift/codegen/src/ir/pcc.rs new file mode 100644 index 000000000000..fe7f08c96cdb --- /dev/null +++ b/cranelift/codegen/src/ir/pcc.rs @@ -0,0 +1,809 @@ +//! Proof-carrying code. We attach "facts" to values and then check +//! that they remain true after compilation. +//! +//! A few key design principle of this approach are: +//! +//! - The producer of the IR provides the axioms. All "ground truth", +//! such as what memory is accessible -- is meant to come by way of +//! facts on the function arguments and global values. In some +//! sense, all we are doing here is validating the "internal +//! consistency" of the facts that are provided on values, and the +//! actions performed on those values. +//! +//! - We do not derive and forward-propagate facts eagerly. Rather, +//! the producer needs to provide breadcrumbs -- a "proof witness" +//! of sorts -- to allow the checking to complete. That means that +//! as an address is computed, or pointer chains are dereferenced, +//! each intermediate value will likely have some fact attached. +//! +//! This does create more verbose IR, but a significant positive +//! benefit is that it avoids unnecessary work: we do not build up a +//! knowledge base that effectively encodes the integer ranges of +//! many or most values in the program. Rather, we only check +//! specifically the memory-access sequences. In practice, each such +//! sequence is likely to be a carefully-controlled sequence of IR +//! operations from, e.g., a sandboxing compiler (such as +//! `cranelift-wasm`) so adding annotations here to communicate +//! intent (ranges, bounds-checks, and the like) is no problem. +//! +//! Facts are attached to SSA values in CLIF, and are maintained +//! through optimizations and through lowering. They are thus also +//! present on VRegs in the VCode. In theory, facts could be checked +//! at either level, though in practice it is most useful to check +//! them at the VCode level if the goal is an end-to-end verification +//! of certain properties (e.g., memory sandboxing). +//! +//! Checking facts entails visiting each instruction that defines a +//! value with a fact, and checking the result's fact against the +//! facts on arguments and the operand. For VCode, this is +//! fundamentally a question of the target ISA's semantics, so we call +//! into the `LowerBackend` for this. Note that during checking there +//! is also limited forward propagation / inference, but only within +//! an instruction: for example, an addressing mode commonly can +//! include an addition, multiplication/shift, or extend operation, +//! and there is no way to attach facts to the intermediate values +//! "inside" the instruction, so instead the backend can use +//! `FactContext::add()` and friends to forward-propagate facts. +//! +//! TODO: +//! +//! Completeness: +//! - Propagate facts through optimization (egraph layer). +//! - Generate facts in cranelift-wasm frontend when lowering memory ops. +//! - Support bounds-checking-type operations for dynamic memories and +//! tables. +//! +//! More checks: +//! - Check that facts on `vmctx` GVs are subsumed by the actual facts +//! on the vmctx arg in block0 (function arg). +//! +//! Generality: +//! - facts on outputs (in func signature)? +//! - Implement checking at the CLIF level as well. +//! - Check instructions that can trap as well? +//! +//! Nicer errors: +//! - attach instruction index or some other identifier to errors +//! +//! Refactoring: +//! - avoid the "default fact" infra everywhere we fetch facts, +//! instead doing it in the subsume check (and take the type with +//! subsume)? +//! +//! Text format cleanup: +//! - make the bitwidth on `max` facts optional in the CLIF text +//! format? +//! - make offset in `mem` fact optional in the text format? +//! +//! Bikeshed colors (syntax): +//! - Put fact bang-annotations after types? +//! `v0: i64 ! fact(..)` vs. `v0 ! fact(..): i64` + +use crate::ir; +use crate::ir::types::*; +use crate::isa::TargetIsa; +use crate::machinst::{BlockIndex, LowerBackend, VCode}; +use crate::trace; +use regalloc2::Function as _; +use std::fmt; + +#[cfg(feature = "enable-serde")] +use serde_derive::{Deserialize, Serialize}; + +/// The result of checking proof-carrying-code facts. +pub type PccResult = std::result::Result; + +/// An error or inconsistency discovered when checking proof-carrying +/// code. +#[derive(Debug, Clone)] +pub enum PccError { + /// An operation wraps around, invalidating the stated value + /// range. + Overflow, + /// An input to an operator that produces a fact-annotated value + /// does not have a fact describing it, and one is needed. + MissingFact, + /// A derivation of an output fact is unsupported (incorrect or + /// not derivable). + UnsupportedFact, + /// A block parameter claims a fact that one of its predecessors + /// does not support. + UnsupportedBlockparam, + /// A memory access is out of bounds. + OutOfBounds, + /// Proof-carrying-code checking is not implemented for a + /// particular compiler backend. + UnimplementedBackend, + /// Proof-carrying-code checking is not implemented for a + /// particular instruction that instruction-selection chose. This + /// is an internal compiler error. + UnimplementedInst, + /// Access to an invalid or undefined field offset in a struct. + InvalidFieldOffset, + /// Access to a field via the wrong type. + BadFieldType, + /// Store to a read-only field. + WriteToReadOnlyField, + /// Store of data to a field with a fact that does not subsume the + /// field's fact. + InvalidStoredFact, +} + +/// A fact on a value. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum Fact { + /// A bitslice of a value (up to a bitwidth) is within the given + /// integer range. + /// + /// The slicing behavior is needed because this fact can describe + /// both an SSA `Value`, whose entire value is well-defined, and a + /// `VReg` in VCode, whose bits beyond the type stored in that + /// register are don't-care (undefined). + Range { + /// The bitwidth of bits we care about, from the LSB upward. + bit_width: u16, + /// The minimum value that the bitslice can take + /// (inclusive). The range is unsigned: the specified bits of + /// the actual value will be greater than or equal to this + /// value, as evaluated by an unsigned integer comparison. + min: u64, + /// The maximum value that the bitslice can take + /// (inclusive). The range is unsigned: the specified bits of + /// the actual value will be less than or equal to this value, + /// as evaluated by an unsigned integer comparison. + max: u64, + }, + + /// A pointer to a memory type. + Mem { + /// The memory type. + ty: ir::MemoryType, + /// The minimum offset into the memory type, inclusive. + min_offset: u64, + /// The maximum offset into the memory type, inclusive. + max_offset: u64, + }, + + /// A "conflict fact": this fact results from merging two other + /// facts, and it can never be satisfied -- checking any value + /// against this fact will fail. + Conflict, +} + +impl fmt::Display for Fact { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Fact::Range { + bit_width, + min, + max, + } => write!(f, "range({}, {:#x}, {:#x})", bit_width, min, max), + Fact::Mem { + ty, + min_offset, + max_offset, + } => write!(f, "mem({}, {:#x}, {:#x})", ty, min_offset, max_offset), + Fact::Conflict => write!(f, "conflict"), + } + } +} + +impl Fact { + /// Create a range fact that specifies a single known constant value. + pub fn constant(bit_width: u16, value: u64) -> Self { + debug_assert!(value <= max_value_for_width(bit_width)); + // `min` and `max` are inclusive, so this specifies a range of + // exactly one value. + Fact::Range { + bit_width, + min: value, + max: value, + } + } + + /// Create a range fact that specifies the maximum range for a + /// value of the given bit-width. + pub const fn max_range_for_width(bit_width: u16) -> Self { + match bit_width { + bit_width if bit_width < 64 => Fact::Range { + bit_width, + min: 0, + max: (1u64 << bit_width) - 1, + }, + 64 => Fact::Range { + bit_width: 64, + min: 0, + max: u64::MAX, + }, + _ => panic!("bit width too large!"), + } + } + + /// Create a range fact that specifies the maximum range for a + /// value of the given bit-width, zero-extended into a wider + /// width. + pub const fn max_range_for_width_extended(from_width: u16, to_width: u16) -> Self { + debug_assert!(from_width <= to_width); + match from_width { + from_width if from_width < 64 => Fact::Range { + bit_width: to_width, + min: 0, + max: (1u64 << from_width) - 1, + }, + 64 => Fact::Range { + bit_width: to_width, + min: 0, + max: u64::MAX, + }, + _ => panic!("bit width too large!"), + } + } + + /// Try to infer a minimal fact for a value of the given IR type. + pub fn infer_from_type(ty: ir::Type) -> Option<&'static Self> { + static FACTS: [Fact; 4] = [ + Fact::max_range_for_width(8), + Fact::max_range_for_width(16), + Fact::max_range_for_width(32), + Fact::max_range_for_width(64), + ]; + match ty { + I8 => Some(&FACTS[0]), + I16 => Some(&FACTS[1]), + I32 => Some(&FACTS[2]), + I64 => Some(&FACTS[3]), + _ => None, + } + } + + /// Does this fact "propagate" automatically, i.e., cause + /// instructions that process it to infer their own output facts? + /// Not all facts propagate automatically; otherwise, verification + /// would be much slower. + pub fn propagates(&self) -> bool { + match self { + Fact::Mem { .. } => true, + _ => false, + } + } + + /// Is this a constant value of the given bitwidth? Return it as a + /// `Some(value)` if so. + pub fn as_const(&self, bits: u16) -> Option { + match self { + Fact::Range { + bit_width, + min, + max, + } if *bit_width == bits && min == max => Some(*min), + _ => None, + } + } + + /// Merge two facts. We take the *intersection*: that is, we know + /// both facts to be true, so we can intersect ranges. (This + /// differs from the usual static analysis approach, where we are + /// merging multiple possibilities into a generalized / widened + /// fact. We want to narrow here.) + pub fn intersect(a: &Fact, b: &Fact) -> Fact { + match (a, b) { + ( + Fact::Range { + bit_width: bw_lhs, + min: min_lhs, + max: max_lhs, + }, + Fact::Range { + bit_width: bw_rhs, + min: min_rhs, + max: max_rhs, + }, + ) if bw_lhs == bw_rhs && max_lhs >= min_rhs && max_rhs >= min_lhs => Fact::Range { + bit_width: *bw_lhs, + min: std::cmp::max(*min_lhs, *min_rhs), + max: std::cmp::min(*max_lhs, *max_rhs), + }, + + ( + Fact::Mem { + ty: ty_lhs, + min_offset: min_offset_lhs, + max_offset: max_offset_lhs, + }, + Fact::Mem { + ty: ty_rhs, + min_offset: min_offset_rhs, + max_offset: max_offset_rhs, + }, + ) if ty_lhs == ty_rhs + && max_offset_lhs >= min_offset_rhs + && max_offset_rhs >= min_offset_lhs => + { + Fact::Mem { + ty: *ty_lhs, + min_offset: std::cmp::max(*min_offset_lhs, *min_offset_rhs), + max_offset: std::cmp::min(*max_offset_lhs, *max_offset_rhs), + } + } + + _ => Fact::Conflict, + } + } +} + +macro_rules! ensure { + ( $condition:expr, $err:tt $(,)? ) => { + if !$condition { + return Err(PccError::$err); + } + }; +} + +macro_rules! bail { + ( $err:tt ) => {{ + return Err(PccError::$err); + }}; +} + +/// A "context" in which we can evaluate and derive facts. This +/// context carries environment/global properties, such as the machine +/// pointer width. +pub struct FactContext<'a> { + function: &'a ir::Function, + pointer_width: u16, +} + +impl<'a> FactContext<'a> { + /// Create a new "fact context" in which to evaluate facts. + pub fn new(function: &'a ir::Function, pointer_width: u16) -> Self { + FactContext { + function, + pointer_width, + } + } + + /// Computes whether `lhs` "subsumes" (implies) `rhs`. + pub fn subsumes(&self, lhs: &Fact, rhs: &Fact) -> bool { + match (lhs, rhs) { + // Reflexivity. + (l, r) if l == r => true, + + ( + Fact::Range { + bit_width: bw_lhs, + min: min_lhs, + max: max_lhs, + }, + Fact::Range { + bit_width: bw_rhs, + min: min_rhs, + max: max_rhs, + }, + ) => { + // If the bitwidths we're claiming facts about are the + // same, or the left-hand-side makes a claim about a + // wider bitwidth, and if the right-hand-side range is + // larger than the left-hand-side range, than the LHS + // subsumes the RHS. + // + // In other words, we can always expand the claimed + // possible value range. + bw_lhs >= bw_rhs && max_lhs <= max_rhs && min_lhs >= min_rhs + } + + ( + Fact::Mem { + ty: ty_lhs, + min_offset: min_offset_lhs, + max_offset: max_offset_lhs, + }, + Fact::Mem { + ty: ty_rhs, + min_offset: min_offset_rhs, + max_offset: max_offset_rhs, + }, + ) => { + ty_lhs == ty_rhs + && max_offset_lhs <= max_offset_rhs + && min_offset_lhs >= min_offset_rhs + } + + _ => false, + } + } + + /// Computes whether the optional fact `lhs` subsumes (implies) + /// the optional fact `lhs`. A `None` never subsumes any fact, and + /// is always subsumed by any fact at all (or no fact). + pub fn subsumes_fact_optionals(&self, lhs: Option<&Fact>, rhs: Option<&Fact>) -> bool { + match (lhs, rhs) { + (None, None) => true, + (Some(_), None) => true, + (None, Some(_)) => false, + (Some(lhs), Some(rhs)) => self.subsumes(lhs, rhs), + } + } + + /// Computes whatever fact can be known about the sum of two + /// values with attached facts. The add is performed to the given + /// bit-width. Note that this is distinct from the machine or + /// pointer width: e.g., many 64-bit machines can still do 32-bit + /// adds that wrap at 2^32. + pub fn add(&self, lhs: &Fact, rhs: &Fact, add_width: u16) -> Option { + match (lhs, rhs) { + ( + Fact::Range { + bit_width: bw_lhs, + min: min_lhs, + max: max_lhs, + }, + Fact::Range { + bit_width: bw_rhs, + min: min_rhs, + max: max_rhs, + }, + ) if bw_lhs == bw_rhs && add_width >= *bw_lhs => { + let computed_min = min_lhs.checked_add(*min_rhs)?; + let computed_max = max_lhs.checked_add(*max_rhs)?; + let computed_max = std::cmp::min(max_value_for_width(add_width), computed_max); + Some(Fact::Range { + bit_width: *bw_lhs, + min: computed_min, + max: computed_max, + }) + } + + ( + Fact::Range { + bit_width: bw_max, + min, + max, + }, + Fact::Mem { + ty, + min_offset, + max_offset, + }, + ) + | ( + Fact::Mem { + ty, + min_offset, + max_offset, + }, + Fact::Range { + bit_width: bw_max, + min, + max, + }, + ) if *bw_max >= self.pointer_width && add_width >= *bw_max => { + let min_offset = min_offset.checked_add(*min)?; + let max_offset = max_offset.checked_add(*max)?; + Some(Fact::Mem { + ty: *ty, + min_offset, + max_offset, + }) + } + + _ => None, + } + } + + /// Computes the `uextend` of a value with the given facts. + pub fn uextend(&self, fact: &Fact, from_width: u16, to_width: u16) -> Option { + trace!( + "uextend: fact {:?} from {} to {}", + fact, + from_width, + to_width + ); + if from_width == to_width { + return Some(fact.clone()); + } + + match fact { + // If the claim is already for a same-or-wider value and the min + // and max are within range of the narrower value, we can + // claim the same range. + Fact::Range { + bit_width, + min, + max, + } if *bit_width >= from_width + && *min <= max_value_for_width(from_width) + && *max <= max_value_for_width(from_width) => + { + Some(Fact::Range { + bit_width: to_width, + min: *min, + max: *max, + }) + } + // Otherwise, we can at least claim that the value is + // within the range of `from_width`. + Fact::Range { .. } => Some(Fact::max_range_for_width_extended(from_width, to_width)), + + _ => None, + } + } + + /// Computes the `sextend` of a value with the given facts. + pub fn sextend(&self, fact: &Fact, from_width: u16, to_width: u16) -> Option { + match fact { + // If we have a defined value in bits 0..bit_width, and + // the MSB w.r.t. `from_width` is *not* set, then we can + // do the same as `uextend`. + Fact::Range { + bit_width, + // We can ignore `min`: it is always <= max in + // unsigned terms, and we check max's LSB below. + min: _, + max, + } if *bit_width == from_width && (*max & (1 << (*bit_width - 1)) == 0) => { + self.uextend(fact, from_width, to_width) + } + _ => None, + } + } + + /// Computes the bit-truncation of a value with the given fact. + pub fn truncate(&self, fact: &Fact, from_width: u16, to_width: u16) -> Option { + if from_width == to_width { + return Some(fact.clone()); + } + + trace!( + "truncate: fact {:?} from {} to {}", + fact, + from_width, + to_width + ); + + match fact { + Fact::Range { + bit_width, + min, + max, + } if *bit_width == from_width => { + let max_val = (1u64 << to_width) - 1; + if *min <= max_val && *max <= max_val { + Some(Fact::Range { + bit_width: to_width, + min: *min, + max: *max, + }) + } else { + Some(Fact::Range { + bit_width: to_width, + min: 0, + max: max_val, + }) + } + } + _ => None, + } + } + + /// Scales a value with a fact by a known constant. + pub fn scale(&self, fact: &Fact, width: u16, factor: u32) -> Option { + match fact { + Fact::Range { + bit_width, + min, + max, + } if *bit_width == width => { + let min = min.checked_mul(u64::from(factor))?; + let max = max.checked_mul(u64::from(factor))?; + if *bit_width < 64 && max > max_value_for_width(width) { + return None; + } + Some(Fact::Range { + bit_width: *bit_width, + min, + max, + }) + } + _ => None, + } + } + + /// Left-shifts a value with a fact by a known constant. + pub fn shl(&self, fact: &Fact, width: u16, amount: u16) -> Option { + if amount >= 32 { + return None; + } + let factor: u32 = 1 << amount; + self.scale(fact, width, factor) + } + + /// Offsets a value with a fact by a known amount. + pub fn offset(&self, fact: &Fact, width: u16, offset: i64) -> Option { + trace!( + "FactContext::offset: {:?} + {} in width {}", + fact, + offset, + width + ); + + let compute_offset = |base: u64| -> Option { + if offset >= 0 { + base.checked_add(u64::try_from(offset).unwrap()) + } else { + base.checked_sub(u64::try_from(-offset).unwrap()) + } + }; + + match fact { + Fact::Range { + bit_width, + min, + max, + } if *bit_width == width => { + let min = compute_offset(*min)?; + let max = compute_offset(*max)?; + + Some(Fact::Range { + bit_width: *bit_width, + min, + max, + }) + } + Fact::Mem { + ty, + min_offset: mem_min_offset, + max_offset: mem_max_offset, + } => { + let min_offset = compute_offset(*mem_min_offset)?; + let max_offset = compute_offset(*mem_max_offset)?; + Some(Fact::Mem { + ty: *ty, + min_offset, + max_offset, + }) + } + _ => None, + } + } + + /// Check that accessing memory via a pointer with this fact, with + /// a memory access of the given size, is valid. + /// + /// If valid, returns the memory type and offset into that type + /// that this address accesses, if known, or `None` if the range + /// doesn't constrain the access to exactly one location. + fn check_address(&self, fact: &Fact, size: u32) -> PccResult> { + trace!("check_address: fact {:?} size {}", fact, size); + match fact { + Fact::Mem { + ty, + min_offset, + max_offset, + } => { + let end_offset: u64 = max_offset + .checked_add(u64::from(size)) + .ok_or(PccError::Overflow)?; + match &self.function.memory_types[*ty] { + ir::MemoryTypeData::Struct { size, .. } + | ir::MemoryTypeData::Memory { size } => { + ensure!(end_offset <= *size, OutOfBounds) + } + ir::MemoryTypeData::Empty => bail!(OutOfBounds), + } + let specific_ty_and_offset = if min_offset == max_offset { + Some((*ty, *min_offset)) + } else { + None + }; + Ok(specific_ty_and_offset) + } + _ => bail!(OutOfBounds), + } + } + + /// Get the access struct field, if any, by a pointer with the + /// given fact and an access of the given type. + pub fn struct_field<'b>( + &'b self, + fact: &Fact, + access_ty: ir::Type, + ) -> PccResult> { + let (ty, offset) = match self.check_address(fact, access_ty.bytes())? { + Some((ty, offset)) => (ty, offset), + None => return Ok(None), + }; + + if let ir::MemoryTypeData::Struct { fields, .. } = &self.function.memory_types[ty] { + let field = fields + .iter() + .find(|field| field.offset == offset) + .ok_or(PccError::InvalidFieldOffset)?; + if field.ty != access_ty { + bail!(BadFieldType); + } + Ok(Some(field)) + } else { + // Access to valid memory, but not a struct: no facts can be attached to the result. + Ok(None) + } + } + + /// Check a load, and determine what fact, if any, the result of the load might have. + pub fn load<'b>(&'b self, fact: &Fact, access_ty: ir::Type) -> PccResult> { + Ok(self + .struct_field(fact, access_ty)? + .and_then(|field| field.fact())) + } + + /// Check a store. + pub fn store( + &self, + fact: &Fact, + access_ty: ir::Type, + data_fact: Option<&Fact>, + ) -> PccResult<()> { + if let Some(field) = self.struct_field(fact, access_ty)? { + // If it's a read-only field, disallow. + if field.readonly { + bail!(WriteToReadOnlyField); + } + // Check that the fact on the stored data subsumes the field's fact. + if !self.subsumes_fact_optionals(data_fact, field.fact()) { + bail!(InvalidStoredFact); + } + } + Ok(()) + } +} + +fn max_value_for_width(bits: u16) -> u64 { + assert!(bits <= 64); + if bits == 64 { + u64::MAX + } else { + (1u64 << bits) - 1 + } +} + +/// Top-level entry point after compilation: this checks the facts in +/// VCode. +pub fn check_vcode_facts( + f: &ir::Function, + vcode: &mut VCode, + backend: &B, +) -> PccResult<()> { + let ctx = FactContext::new(f, backend.triple().pointer_width().unwrap().bits().into()); + + // Check that individual instructions are valid according to input + // facts, and support the stated output facts. + for block in 0..vcode.num_blocks() { + let block = BlockIndex::new(block); + for inst in vcode.block_insns(block).iter() { + // Check any output facts on this inst. + if let Err(e) = backend.check_fact(&ctx, vcode, inst) { + log::error!("Error checking instruction: {:?}", vcode[inst]); + return Err(e); + } + + // If this is a branch, check that all block arguments subsume + // the assumed facts on the blockparams of successors. + if vcode.is_branch(inst) { + for (succ_idx, succ) in vcode.block_succs(block).iter().enumerate() { + for (arg, param) in vcode + .branch_blockparams(block, inst, succ_idx) + .iter() + .zip(vcode.block_params(*succ).iter()) + { + let arg_fact = vcode.vreg_fact(*arg); + let param_fact = vcode.vreg_fact(*param); + if !ctx.subsumes_fact_optionals(arg_fact, param_fact) { + return Err(PccError::UnsupportedBlockparam); + } + } + } + } + } + } + Ok(()) +} diff --git a/cranelift/codegen/src/isa/aarch64/abi.rs b/cranelift/codegen/src/isa/aarch64/abi.rs index bcf865d2603f..b5d6e56fcd9f 100644 --- a/cranelift/codegen/src/isa/aarch64/abi.rs +++ b/cranelift/codegen/src/isa/aarch64/abi.rs @@ -1148,10 +1148,14 @@ impl ABIMachineSpec for AArch64MachineDeps { } fn get_ext_mode( - _call_conv: isa::CallConv, - _specified: ir::ArgumentExtension, + call_conv: isa::CallConv, + specified: ir::ArgumentExtension, ) -> ir::ArgumentExtension { - ir::ArgumentExtension::None + if call_conv == isa::CallConv::AppleAarch64 { + specified + } else { + ir::ArgumentExtension::None + } } fn compute_frame_layout( diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index 624a5c9d987b..90c0911185c5 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -883,7 +883,8 @@ ;; Jump-table sequence, as one compound instruction (see note in lower_inst.rs for rationale). (JTSequence - (info BoxJTSequenceInfo) + (default MachLabel) + (targets BoxVecMachLabel) (ridx Reg) (rtmp1 WritableReg) (rtmp2 WritableReg)) @@ -946,8 +947,9 @@ ;; A call to the `ElfTlsGetAddr` libcall. Returns address of TLS symbol in x0. (ElfTlsGetAddr - (symbol ExternalName) - (rd WritableReg)) + (symbol BoxExternalName) + (rd WritableReg) + (tmp WritableReg)) (MachOTlsGetAddr (symbol ExternalName) @@ -1717,18 +1719,13 @@ (decl u64_into_imm_logic (Type u64) ImmLogic) (extern constructor u64_into_imm_logic u64_into_imm_logic) -(decl branch_target (VecMachLabel u8) BranchTarget) +(decl branch_target (MachLabel) BranchTarget) (extern constructor branch_target branch_target) +(convert MachLabel BranchTarget branch_target) -(decl targets_jt_size (VecMachLabel) u32) -(extern constructor targets_jt_size targets_jt_size) - -(decl targets_jt_space (VecMachLabel) CodeOffset) +(decl targets_jt_space (BoxVecMachLabel) CodeOffset) (extern constructor targets_jt_space targets_jt_space) -(decl targets_jt_info (VecMachLabel) BoxJTSequenceInfo) -(extern constructor targets_jt_info targets_jt_info) - ;; Calculate the minimum floating-point bound for a conversion to floating ;; point from an integer type. ;; Accepts whether the output is signed, the size of the input @@ -2708,6 +2705,9 @@ (rule (and_vec x y size) (vec_rrr (VecALUOp.And) x y size)) ;; Helpers for generating `eor` instructions. +(decl eor (Type Reg Reg) Reg) +(rule (eor ty x y) (alu_rrr (ALUOp.Eor) ty x y)) + (decl eor_vec (Reg Reg VectorSize) Reg) (rule (eor_vec x y size) (vec_rrr (VecALUOp.Eor) x y size)) @@ -3312,17 +3312,6 @@ (rule (splat_const n size) (vec_dup (imm $I64 (ImmExtend.Zero) n) size)) -;; Each of these extractors tests whether the upper half of the input equals the -;; lower half of the input -(decl u128_replicated_u64 (u64) u128) -(extern extractor u128_replicated_u64 u128_replicated_u64) -(decl u64_replicated_u32 (u64) u64) -(extern extractor u64_replicated_u32 u64_replicated_u32) -(decl u32_replicated_u16 (u64) u64) -(extern extractor u32_replicated_u16 u32_replicated_u16) -(decl u16_replicated_u8 (u64) u64) -(extern extractor u16_replicated_u8 u16_replicated_u8) - ;; Lower a FloatCC to a Cond. (decl fp_cond_code (FloatCC) Cond) ;; TODO: Port lower_fp_condcode() to ISLE. @@ -3776,7 +3765,8 @@ (decl elf_tls_get_addr (ExternalName) Reg) (rule (elf_tls_get_addr name) (let ((dst WritableReg (temp_writable_reg $I64)) - (_ Unit (emit (MInst.ElfTlsGetAddr name dst)))) + (tmp WritableReg (temp_writable_reg $I64)) + (_ Unit (emit (MInst.ElfTlsGetAddr (box_external_name name) dst tmp)))) dst)) (decl macho_tls_get_addr (ExternalName) Reg) @@ -4076,12 +4066,12 @@ ;; PC-rel offset to the jumptable would be incorrect. ;; (The alternative is to introduce a relocation pass ;; for inlined jumptables, which is much worse, IMHO.) -(decl jt_sequence (Reg BoxJTSequenceInfo) ConsumesFlags) -(rule (jt_sequence ridx info) +(decl jt_sequence (Reg MachLabel BoxVecMachLabel) ConsumesFlags) +(rule (jt_sequence ridx default targets) (let ((rtmp1 WritableReg (temp_writable_reg $I64)) (rtmp2 WritableReg (temp_writable_reg $I64))) (ConsumesFlags.ConsumesFlagsSideEffect - (MInst.JTSequence info ridx rtmp1 rtmp2)))) + (MInst.JTSequence default targets ridx rtmp1 rtmp2)))) ;; Helper for emitting `MInst.CondBr` instructions. (decl cond_br (BranchTarget BranchTarget CondBrKind) ConsumesFlags) @@ -4102,18 +4092,16 @@ (MInst.EmitIsland needed_space))) ;; Helper for emitting `br_table` sequences. -(decl br_table_impl (u64 Reg VecMachLabel) Unit) -(rule (br_table_impl (imm12_from_u64 jt_size) ridx targets) - (let ((jt_info BoxJTSequenceInfo (targets_jt_info targets))) - (emit_side_effect (with_flags_side_effect - (cmp_imm (OperandSize.Size32) ridx jt_size) - (jt_sequence ridx jt_info))))) -(rule -1 (br_table_impl jt_size ridx targets) - (let ((jt_size Reg (imm $I64 (ImmExtend.Zero) jt_size)) - (jt_info BoxJTSequenceInfo (targets_jt_info targets))) +(decl br_table_impl (u64 Reg MachLabel BoxVecMachLabel) Unit) +(rule (br_table_impl (imm12_from_u64 jt_size) ridx default targets) + (emit_side_effect (with_flags_side_effect + (cmp_imm (OperandSize.Size32) ridx jt_size) + (jt_sequence ridx default targets)))) +(rule -1 (br_table_impl jt_size ridx default targets) + (let ((jt_size Reg (imm $I64 (ImmExtend.Zero) jt_size))) (emit_side_effect (with_flags_side_effect (cmp (OperandSize.Size32) ridx jt_size) - (jt_sequence ridx jt_info))))) + (jt_sequence ridx default targets))))) ;; Helper for emitting the `uzp1` instruction (decl vec_uzp1 (Reg Reg VectorSize) Reg) diff --git a/cranelift/codegen/src/isa/aarch64/inst/args.rs b/cranelift/codegen/src/isa/aarch64/inst/args.rs index cf1d6d05a671..c6394e6596f3 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/args.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/args.rs @@ -11,7 +11,7 @@ use std::string::String; // Instruction sub-components: shift and extend descriptors /// A shift operator for a register or immediate. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum ShiftOp { /// Logical shift left. @@ -580,6 +580,14 @@ impl OperandSize { OperandSize::Size64 => 1, } } + + /// The maximum unsigned value representable in a value of this size. + pub fn max_value(&self) -> u64 { + match self { + OperandSize::Size32 => u32::MAX as u64, + OperandSize::Size64 => u64::MAX, + } + } } /// Type used to communicate the size of a scalar SIMD & FP operand. @@ -639,6 +647,17 @@ impl ScalarSize { ScalarSize::Size128 => ScalarSize::Size64, } } + + /// Return a type with the same size as this scalar. + pub fn ty(&self) -> Type { + match self { + ScalarSize::Size8 => I8, + ScalarSize::Size16 => I16, + ScalarSize::Size32 => I32, + ScalarSize::Size64 => I64, + ScalarSize::Size128 => I128, + } + } } /// Type used to communicate the size of a vector operand. diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs index 43bdd4a3e981..39a49dfdd275 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs @@ -4,7 +4,7 @@ use cranelift_control::ControlPlane; use regalloc2::Allocation; use crate::binemit::{Reloc, StackMap}; -use crate::ir::{self, types::*, LibCall, MemFlags, RelSourceLoc, TrapCode}; +use crate::ir::{self, types::*, MemFlags, RelSourceLoc, TrapCode}; use crate::isa::aarch64::inst::*; use crate::machinst::{ty_bits, Reg, RegClass, Writable}; use crate::trace; @@ -3275,7 +3275,8 @@ impl MachInstEmit for Inst { ridx, rtmp1, rtmp2, - ref info, + default, + ref targets, .. } => { let ridx = allocs.next(ridx); @@ -3287,7 +3288,7 @@ impl MachInstEmit for Inst { // Branch to default when condition code from prior comparison indicates. let br = enc_conditional_br( - info.default_target, + BranchTarget::Label(default), CondBrKind::Cond(Cond::Hs), &mut AllocationConsumer::default(), ); @@ -3296,9 +3297,7 @@ impl MachInstEmit for Inst { // will not be merged with any other branch, flipped, or elided (it is not preceded // or succeeded by any other branch). Just emit it with the label use. let default_br_offset = sink.cur_offset(); - if let BranchTarget::Label(l) = info.default_target { - sink.use_label_at_offset(default_br_offset, l, LabelUse::Branch19); - } + sink.use_label_at_offset(default_br_offset, default, LabelUse::Branch19); sink.put4(br); // Overwrite the index with a zero when the above @@ -3347,18 +3346,14 @@ impl MachInstEmit for Inst { inst.emit(&[], sink, emit_info, state); // Emit jump table (table of 32-bit offsets). let jt_off = sink.cur_offset(); - for &target in info.targets.iter() { + for &target in targets.iter() { let word_off = sink.cur_offset(); // off_into_table is an addend here embedded in the label to be later patched // at the end of codegen. The offset is initially relative to this jump table // entry; with the extra addend, it'll be relative to the jump table's start, // after patching. let off_into_table = word_off - jt_off; - sink.use_label_at_offset( - word_off, - target.as_label().unwrap(), - LabelUse::PCRel32, - ); + sink.use_label_at_offset(word_off, target, LabelUse::PCRel32); sink.put4(off_into_table); } @@ -3542,32 +3537,81 @@ impl MachInstEmit for Inst { } } - &Inst::ElfTlsGetAddr { ref symbol, rd } => { + &Inst::ElfTlsGetAddr { + ref symbol, + rd, + tmp, + } => { let rd = allocs.next_writable(rd); + let tmp = allocs.next_writable(tmp); assert_eq!(xreg(0), rd.to_reg()); + // See the original proposal for TLSDESC. + // http://www.fsfla.org/~lxoliva/writeups/TLS/paper-lk2006.pdf + // + // Implement the TLSDESC instruction sequence: + // adrp x0, :tlsdesc:tlsvar + // ldr tmp, [x0, :tlsdesc_lo12:tlsvar] + // add x0, x0, :tlsdesc_lo12:tlsvar + // blr tmp + // mrs tmp, tpidr_el0 + // add x0, x0, tmp + // // This is the instruction sequence that GCC emits for ELF GD TLS Relocations in aarch64 - // See: https://gcc.godbolt.org/z/KhMh5Gvra + // See: https://gcc.godbolt.org/z/e4j7MdErh - // adrp x0,