diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 63e272dc2134..a53b85b42ec8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,7 +80,7 @@ jobs: # Note that `wasmtime-platform.h` is excluded here as it's auto-generated. clangformat: name: Clang format - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: @@ -89,7 +89,7 @@ jobs: git ls-files '*.h' '*.c' '*.cpp' | \ grep -v wasmtime-platform.h | \ grep -v wasm.h | \ - xargs clang-format-15 --dry-run --Werror --verbose + xargs clang-format-18 --dry-run --Werror --verbose # common logic to cancel the entire run if this job fails - run: gh run cancel ${{ github.run_id }} @@ -358,11 +358,12 @@ jobs: -p wasmtime --no-default-features --features profiling -p wasmtime --no-default-features --features cache -p wasmtime --no-default-features --features async + -p wasmtime --no-default-features --features std -p wasmtime --no-default-features --features pooling-allocator -p wasmtime --no-default-features --features cranelift -p wasmtime --no-default-features --features component-model -p wasmtime --no-default-features --features runtime,component-model - -p wasmtime --no-default-features --features cranelift,wat,async,cache + -p wasmtime --no-default-features --features cranelift,wat,async,std,cache -p wasmtime --no-default-features --features winch -p wasmtime --no-default-features --features wmemcheck -p wasmtime --no-default-features --features wmemcheck,cranelift,runtime @@ -386,6 +387,12 @@ jobs: -p wasmtime --features incremental-cache -p wasmtime --all-features + - name: wasmtime-fiber + checks: | + -p wasmtime-fiber --no-default-features + -p wasmtime-fiber --no-default-features --features std + -p wasmtime-fiber --all-features + - name: wasmtime-cli checks: | -p wasmtime-cli --no-default-features @@ -434,6 +441,18 @@ jobs: env: GH_TOKEN: ${{ github.token }} + fiber_tests: + name: wasmtime-fiber tests + runs-on: ubuntu-latest + env: + CARGO_NDK_VERSION: 2.12.2 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - uses: ./.github/actions/install-rust + - run: cargo test -p wasmtime-fiber --no-default-features + # Checks for no_std support, ensure that crates can build on a no_std target no_std_checks: name: no_std checks @@ -654,12 +673,8 @@ jobs: - run: cmake -Sexamples -Bexamples/build -DBUILD_SHARED_LIBS=OFF - run: cmake --build examples/build --config Debug - run: cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target RUN_TESTS - env: - RUST_BACKTRACE: 1 if: matrix.os == 'windows-latest' - run: cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target test - env: - RUST_BACKTRACE: 1 if: matrix.os != 'windows-latest' # Perform all tests (debug mode) for `wasmtime`. @@ -672,7 +687,7 @@ jobs: name: ${{ matrix.name }} runs-on: ${{ matrix.os }} env: - QEMU_BUILD_VERSION: 8.1.5 + QEMU_BUILD_VERSION: 9.1.2 strategy: fail-fast: ${{ github.event_name != 'pull_request' }} matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }} @@ -707,7 +722,7 @@ jobs: set -ex sudo apt-get update - sudo apt-get install -y ${{ matrix.gcc_package }} ninja-build + sudo apt-get install -y ${{ matrix.gcc_package }} # Configure Cargo for cross compilation and tell it how it can run # cross executables @@ -740,6 +755,9 @@ jobs: exit 0 fi + # Install build dependencies of QEMU itself. + sudo apt-get install -y libglib2.0-dev ninja-build + # Download and build qemu from source since the most recent release is # way faster at arm emulation than the current version github actions' # ubuntu image uses. Disable as much as we can to get it to build @@ -784,8 +802,6 @@ jobs: # Build and test all features - run: ./ci/run-tests.sh --locked ${{ matrix.bucket }} - env: - RUST_BACKTRACE: 1 # NB: the test job here is explicitly lacking in cancellation of this run if # something goes wrong. These take the longest anyway and otherwise if @@ -832,8 +848,6 @@ jobs: # Run the tests! - run: cargo test -p wasmtime-wasi-nn --features ${{ matrix.feature }} - env: - RUST_BACKTRACE: 1 # common logic to cancel the entire run if this job fails - run: gh run cancel ${{ github.run_id }} @@ -858,8 +872,6 @@ jobs: # Run the tests - run: | cargo test -p wasmtime-fuzzing -p wasm-spec-interpreter - env: - RUST_BACKTRACE: 1 # common logic to cancel the entire run if this job fails - run: gh run cancel ${{ github.run_id }} @@ -872,7 +884,7 @@ jobs: needs: determine if: needs.determine.outputs.run-dwarf name: Test DWARF debugging - runs-on: 'ubuntu-latest' + runs-on: ubuntu-22.04 # FIXME: fails on `ubuntu-24.04` right now steps: - uses: actions/checkout@v4 with: @@ -886,7 +898,6 @@ jobs: sudo ln -s /usr/lib/llvm-15/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/ cargo test --test all -- --ignored --test-threads 1 debug:: env: - RUST_BACKTRACE: 1 LLDB: lldb-15 # override default version, 14 # Test baseline implementation @@ -1235,6 +1246,7 @@ jobs: - cargo_vet - doc - micro_checks + - fiber_tests - no_std_checks - clippy - monolith_checks diff --git a/.github/workflows/publish-artifacts.yml b/.github/workflows/publish-artifacts.yml index 4a108ff083a4..3f6565e2f28a 100644 --- a/.github/workflows/publish-artifacts.yml +++ b/.github/workflows/publish-artifacts.yml @@ -6,6 +6,8 @@ on: permissions: contents: write + id-token: write + attestations: write jobs: publish: @@ -34,6 +36,10 @@ jobs: with: path: "./gh-pages/gh-pages" + - uses: actions/attest-build-provenance@v1 + with: + subject-path: 'dist/*' + - run: npm install --production working-directory: .github/actions/github-release - name: Publish Release diff --git a/Cargo.lock b/Cargo.lock index 88ee65e813c7..09a2fb0e88c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,9 +133,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arbitrary" @@ -160,7 +160,7 @@ checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -227,7 +227,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.60", + "syn 2.0.90", "which 4.4.2", ] @@ -289,7 +289,7 @@ dependencies = [ [[package]] name = "byte-array-literals" -version = "28.0.0" +version = "29.0.0" [[package]] name = "byteorder" @@ -579,7 +579,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -627,7 +627,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -694,7 +694,7 @@ dependencies = [ [[package]] name = "cranelift" -version = "0.115.0" +version = "0.116.0" dependencies = [ "cranelift-codegen", "cranelift-frontend", @@ -707,14 +707,14 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.115.0" +version = "0.116.0" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.115.0" +version = "0.116.0" dependencies = [ "arbitrary", "serde", @@ -723,7 +723,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.115.0" +version = "0.116.0" dependencies = [ "anyhow", "bumpalo", @@ -755,25 +755,25 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.115.0" +version = "0.116.0" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.115.0" +version = "0.116.0" [[package]] name = "cranelift-control" -version = "0.115.0" +version = "0.116.0" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.115.0" +version = "0.116.0" dependencies = [ "cranelift-bitset", "serde", @@ -812,7 +812,7 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.115.0" +version = "0.116.0" dependencies = [ "cranelift-codegen", "env_logger 0.11.5", @@ -836,7 +836,7 @@ dependencies = [ [[package]] name = "cranelift-interpreter" -version = "0.115.0" +version = "0.116.0" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -850,7 +850,7 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.115.0" +version = "0.116.0" dependencies = [ "codespan-reporting", "log", @@ -859,7 +859,7 @@ dependencies = [ [[package]] name = "cranelift-jit" -version = "0.115.0" +version = "0.116.0" dependencies = [ "anyhow", "cranelift", @@ -880,7 +880,7 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.115.0" +version = "0.116.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -892,7 +892,7 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.115.0" +version = "0.116.0" dependencies = [ "cranelift-codegen", "libc", @@ -901,7 +901,7 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.115.0" +version = "0.116.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -916,7 +916,7 @@ dependencies = [ [[package]] name = "cranelift-reader" -version = "0.115.0" +version = "0.116.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -926,7 +926,7 @@ dependencies = [ [[package]] name = "cranelift-serde" -version = "0.115.0" +version = "0.116.0" dependencies = [ "clap", "cranelift-codegen", @@ -957,6 +957,7 @@ dependencies = [ "indicatif", "log", "pretty_env_logger", + "pulley-interpreter", "rayon", "regalloc2", "rustc-hash 2.0.0", @@ -1086,7 +1087,7 @@ checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -1184,7 +1185,7 @@ checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" [[package]] name = "embedding" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "dlmalloc", @@ -2019,7 +2020,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.8.5", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -2100,7 +2101,7 @@ dependencies = [ [[package]] name = "min-platform-host" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "libloading", @@ -2233,12 +2234,12 @@ checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a" [[package]] name = "object" -version = "0.36.0" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", - "hashbrown 0.14.3", + "hashbrown 0.15.2", "indexmap 2.2.6", "memchr", ] @@ -2440,14 +2441,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2483,7 +2484,7 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "arbitrary", @@ -2844,22 +2845,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.188" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -3086,9 +3087,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -3231,7 +3232,7 @@ checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -3322,7 +3323,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -3417,7 +3418,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -3606,7 +3607,7 @@ version = "0.1.0" [[package]] name = "verify-component-adapter" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "wasmparser 0.221.2", @@ -3656,7 +3657,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi-common" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -3695,7 +3696,7 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter" -version = "28.0.0" +version = "29.0.0" dependencies = [ "bitflags 2.6.0", "byte-array-literals", @@ -3726,7 +3727,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", "wasm-bindgen-shared", ] @@ -3748,7 +3749,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3941,7 +3942,7 @@ dependencies = [ [[package]] name = "wasmtime" -version = "28.0.0" +version = "29.0.0" dependencies = [ "addr2line", "anyhow", @@ -4004,14 +4005,14 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "28.0.0" +version = "29.0.0" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-bench-api" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "cap-std", @@ -4027,14 +4028,14 @@ dependencies = [ [[package]] name = "wasmtime-c-api" -version = "28.0.0" +version = "29.0.0" dependencies = [ "wasmtime-c-api-impl", ] [[package]] name = "wasmtime-c-api-impl" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "cap-std", @@ -4051,7 +4052,7 @@ dependencies = [ [[package]] name = "wasmtime-c-api-macros" -version = "28.0.0" +version = "29.0.0" dependencies = [ "proc-macro2", "quote", @@ -4059,7 +4060,7 @@ dependencies = [ [[package]] name = "wasmtime-cache" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "base64 0.21.0", @@ -4080,7 +4081,7 @@ dependencies = [ [[package]] name = "wasmtime-cli" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "async-trait", @@ -4152,7 +4153,7 @@ dependencies = [ [[package]] name = "wasmtime-cli-flags" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "clap", @@ -4165,7 +4166,7 @@ dependencies = [ [[package]] name = "wasmtime-component-macro" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "component-macro-test-helpers", @@ -4175,7 +4176,7 @@ dependencies = [ "serde", "serde_json", "similar", - "syn 2.0.60", + "syn 2.0.90", "tracing", "wasmtime", "wasmtime-component-util", @@ -4185,18 +4186,18 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "28.0.0" +version = "29.0.0" [[package]] name = "wasmtime-continuations" -version = "28.0.0" +version = "29.0.0" dependencies = [ "memoffset", ] [[package]] name = "wasmtime-cranelift" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "cfg-if", @@ -4221,7 +4222,7 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "clap", @@ -4264,7 +4265,7 @@ dependencies = [ [[package]] name = "wasmtime-explorer" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "capstone", @@ -4279,7 +4280,7 @@ dependencies = [ [[package]] name = "wasmtime-fiber" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "backtrace", @@ -4351,7 +4352,7 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "28.0.0" +version = "29.0.0" dependencies = [ "object", "rustix", @@ -4360,7 +4361,7 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "cfg-if", @@ -4370,7 +4371,7 @@ dependencies = [ [[package]] name = "wasmtime-slab" -version = "28.0.0" +version = "29.0.0" [[package]] name = "wasmtime-test-macros" @@ -4379,22 +4380,22 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", "wasmtime-wast-util", ] [[package]] name = "wasmtime-versioned-export-macros" -version = "28.0.0" +version = "29.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] name = "wasmtime-wasi" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "async-trait", @@ -4426,7 +4427,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi-config" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "test-programs-artifacts", @@ -4437,7 +4438,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi-http" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "async-trait", @@ -4463,7 +4464,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi-keyvalue" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "test-programs-artifacts", @@ -4474,7 +4475,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi-nn" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "cap-std", @@ -4495,7 +4496,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi-threads" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "log", @@ -4507,7 +4508,7 @@ dependencies = [ [[package]] name = "wasmtime-wast" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "log", @@ -4517,7 +4518,7 @@ dependencies = [ [[package]] name = "wasmtime-wast-util" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "serde", @@ -4527,7 +4528,7 @@ dependencies = [ [[package]] name = "wasmtime-winch" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -4542,7 +4543,7 @@ dependencies = [ [[package]] name = "wasmtime-wit-bindgen" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "heck 0.5.0", @@ -4552,7 +4553,7 @@ dependencies = [ [[package]] name = "wasmtime-wmemcheck" -version = "28.0.0" +version = "29.0.0" [[package]] name = "wast" @@ -4628,7 +4629,7 @@ dependencies = [ [[package]] name = "wiggle" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "async-trait", @@ -4645,24 +4646,24 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "heck 0.5.0", "proc-macro2", "quote", "shellexpand", - "syn 2.0.60", + "syn 2.0.90", "witx", ] [[package]] name = "wiggle-macro" -version = "28.0.0" +version = "29.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", "wiggle", "wiggle-generate", ] @@ -4713,7 +4714,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "28.0.0" +version = "29.0.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -4755,7 +4756,7 @@ checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -4766,7 +4767,7 @@ checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -4978,7 +4979,7 @@ dependencies = [ "heck 0.5.0", "indexmap 2.2.6", "prettyplease", - "syn 2.0.60", + "syn 2.0.90", "wasm-metadata 0.220.0", "wit-bindgen-core", "wit-component 0.220.0", @@ -4993,7 +4994,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -5108,7 +5109,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 54c71eaec89e..c19050e8da0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -163,7 +163,7 @@ exclude = [ ] [workspace.package] -version = "28.0.0" +version = "29.0.0" authors = ["The Wasmtime Project Developers"] edition = "2021" # Wasmtime's current policy is that this number can be no larger than the @@ -199,61 +199,61 @@ allow_attributes_without_reason = 'warn' [workspace.dependencies] arbitrary = { version = "1.3.1" } -wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "=28.0.0" } -wasmtime = { path = "crates/wasmtime", version = "28.0.0", default-features = false } -wasmtime-c-api-macros = { path = "crates/c-api-macros", version = "=28.0.0" } -wasmtime-cache = { path = "crates/cache", version = "=28.0.0" } -wasmtime-cli-flags = { path = "crates/cli-flags", version = "=28.0.0" } -wasmtime-cranelift = { path = "crates/cranelift", version = "=28.0.0" } -wasmtime-continuations = { path = "crates/continuations", version = "=28.0.0" } -wasmtime-winch = { path = "crates/winch", version = "=28.0.0" } -wasmtime-environ = { path = "crates/environ", version = "=28.0.0" } -wasmtime-explorer = { path = "crates/explorer", version = "=28.0.0" } -wasmtime-fiber = { path = "crates/fiber", version = "=28.0.0" } -wasmtime-jit-debug = { path = "crates/jit-debug", version = "=28.0.0" } -wasmtime-wast = { path = "crates/wast", version = "=28.0.0" } -wasmtime-wasi = { path = "crates/wasi", version = "28.0.0", default-features = false } -wasmtime-wasi-http = { path = "crates/wasi-http", version = "=28.0.0", default-features = false } -wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "28.0.0" } -wasmtime-wasi-config = { path = "crates/wasi-config", version = "28.0.0" } -wasmtime-wasi-keyvalue = { path = "crates/wasi-keyvalue", version = "28.0.0" } -wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "28.0.0" } -wasmtime-component-util = { path = "crates/component-util", version = "=28.0.0" } -wasmtime-component-macro = { path = "crates/component-macro", version = "=28.0.0" } -wasmtime-asm-macros = { path = "crates/asm-macros", version = "=28.0.0" } -wasmtime-versioned-export-macros = { path = "crates/versioned-export-macros", version = "=28.0.0" } -wasmtime-slab = { path = "crates/slab", version = "=28.0.0" } +wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "=29.0.0" } +wasmtime = { path = "crates/wasmtime", version = "29.0.0", default-features = false } +wasmtime-c-api-macros = { path = "crates/c-api-macros", version = "=29.0.0" } +wasmtime-cache = { path = "crates/cache", version = "=29.0.0" } +wasmtime-cli-flags = { path = "crates/cli-flags", version = "=29.0.0" } +wasmtime-cranelift = { path = "crates/cranelift", version = "=29.0.0" } +wasmtime-continuations = { path = "crates/continuations", version = "=29.0.0" } +wasmtime-winch = { path = "crates/winch", version = "=29.0.0" } +wasmtime-environ = { path = "crates/environ", version = "=29.0.0" } +wasmtime-explorer = { path = "crates/explorer", version = "=29.0.0" } +wasmtime-fiber = { path = "crates/fiber", version = "=29.0.0" } +wasmtime-jit-debug = { path = "crates/jit-debug", version = "=29.0.0" } +wasmtime-wast = { path = "crates/wast", version = "=29.0.0" } +wasmtime-wasi = { path = "crates/wasi", version = "29.0.0", default-features = false } +wasmtime-wasi-http = { path = "crates/wasi-http", version = "=29.0.0", default-features = false } +wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "29.0.0" } +wasmtime-wasi-config = { path = "crates/wasi-config", version = "29.0.0" } +wasmtime-wasi-keyvalue = { path = "crates/wasi-keyvalue", version = "29.0.0" } +wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "29.0.0" } +wasmtime-component-util = { path = "crates/component-util", version = "=29.0.0" } +wasmtime-component-macro = { path = "crates/component-macro", version = "=29.0.0" } +wasmtime-asm-macros = { path = "crates/asm-macros", version = "=29.0.0" } +wasmtime-versioned-export-macros = { path = "crates/versioned-export-macros", version = "=29.0.0" } +wasmtime-slab = { path = "crates/slab", version = "=29.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 = "=28.0.0", default-features = false } -wiggle-macro = { path = "crates/wiggle/macro", version = "=28.0.0" } -wiggle-generate = { path = "crates/wiggle/generate", version = "=28.0.0" } -wasi-common = { path = "crates/wasi-common", version = "=28.0.0", default-features = false } +wiggle = { path = "crates/wiggle", version = "=29.0.0", default-features = false } +wiggle-macro = { path = "crates/wiggle/macro", version = "=29.0.0" } +wiggle-generate = { path = "crates/wiggle/generate", version = "=29.0.0" } +wasi-common = { path = "crates/wasi-common", version = "=29.0.0", default-features = false } wasmtime-fuzzing = { path = "crates/fuzzing" } -wasmtime-jit-icache-coherence = { path = "crates/jit-icache-coherence", version = "=28.0.0" } -wasmtime-wit-bindgen = { path = "crates/wit-bindgen", version = "=28.0.0" } +wasmtime-jit-icache-coherence = { path = "crates/jit-icache-coherence", version = "=29.0.0" } +wasmtime-wit-bindgen = { path = "crates/wit-bindgen", version = "=29.0.0" } test-programs-artifacts = { path = 'crates/test-programs/artifacts' } -pulley-interpreter = { path = 'pulley', version = "=28.0.0" } +pulley-interpreter = { path = 'pulley', version = "=29.0.0" } pulley-interpreter-fuzz = { path = 'pulley/fuzz' } -cranelift-codegen = { path = "cranelift/codegen", version = "0.115.0", default-features = false, features = ["std", "unwind"] } -cranelift-frontend = { path = "cranelift/frontend", version = "0.115.0" } -cranelift-entity = { path = "cranelift/entity", version = "0.115.0" } -cranelift-native = { path = "cranelift/native", version = "0.115.0" } -cranelift-module = { path = "cranelift/module", version = "0.115.0" } -cranelift-interpreter = { path = "cranelift/interpreter", version = "0.115.0" } -cranelift-reader = { path = "cranelift/reader", version = "0.115.0" } +cranelift-codegen = { path = "cranelift/codegen", version = "0.116.0", default-features = false, features = ["std", "unwind"] } +cranelift-frontend = { path = "cranelift/frontend", version = "0.116.0" } +cranelift-entity = { path = "cranelift/entity", version = "0.116.0" } +cranelift-native = { path = "cranelift/native", version = "0.116.0" } +cranelift-module = { path = "cranelift/module", version = "0.116.0" } +cranelift-interpreter = { path = "cranelift/interpreter", version = "0.116.0" } +cranelift-reader = { path = "cranelift/reader", version = "0.116.0" } cranelift-filetests = { path = "cranelift/filetests" } -cranelift-object = { path = "cranelift/object", version = "0.115.0" } -cranelift-jit = { path = "cranelift/jit", version = "0.115.0" } +cranelift-object = { path = "cranelift/object", version = "0.116.0" } +cranelift-jit = { path = "cranelift/jit", version = "0.116.0" } cranelift-fuzzgen = { path = "cranelift/fuzzgen" } -cranelift-bforest = { path = "cranelift/bforest", version = "0.115.0" } -cranelift-bitset = { path = "cranelift/bitset", version = "0.115.0" } -cranelift-control = { path = "cranelift/control", version = "0.115.0" } -cranelift = { path = "cranelift/umbrella", version = "0.115.0" } +cranelift-bforest = { path = "cranelift/bforest", version = "0.116.0" } +cranelift-bitset = { path = "cranelift/bitset", version = "0.116.0" } +cranelift-control = { path = "cranelift/control", version = "0.116.0" } +cranelift = { path = "cranelift/umbrella", version = "0.116.0" } -winch-codegen = { path = "winch/codegen", version = "=28.0.0" } +winch-codegen = { path = "winch/codegen", version = "=29.0.0" } wasi-preview1-component-adapter = { path = "crates/wasi-preview1-component-adapter" } byte-array-literals = { path = "crates/wasi-preview1-component-adapter/byte-array-literals" } @@ -294,10 +294,10 @@ wasm-wave = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.221. # Non-Bytecode Alliance maintained dependencies: # -------------------------- cc = "1.0" -object = { version = "0.36", default-features = false, features = ['read_core', 'elf'] } +object = { version = "0.36.5", default-features = false, features = ['read_core', 'elf'] } gimli = { version = "0.31.0", default-features = false, features = ['read'] } addr2line = { version = "0.24.1", default-features = false } -anyhow = { version = "1.0.22", default-features = false } +anyhow = { version = "1.0.93", default-features = false } windows-sys = "0.59.0" env_logger = "0.11.5" log = { version = "0.4.8", default-features = false } @@ -320,7 +320,7 @@ proptest = "1.0.0" rand = { version = "0.8.3", features = ["small_rng"] } sptr = "0.3.2" # serde and serde_derive must have the same version -serde = { version = "1.0.188", default-features = false, features = ['alloc'] } +serde = { version = "1.0.215", default-features = false, features = ['alloc'] } serde_derive = "1.0.188" serde_json = "1.0.80" glob = "0.3.0" diff --git a/RELEASES.md b/RELEASES.md index 868e9f306393..095959a5e42d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,4 @@ -## 28.0.0 +## 29.0.0 Unreleased. @@ -12,6 +12,7 @@ Release notes for previous releases of Wasmtime can be found on the respective release branches of the Wasmtime repository. +* [28.0.x](https://github.com/bytecodealliance/wasmtime/blob/release-28.0.0/RELEASES.md) * [27.0.x](https://github.com/bytecodealliance/wasmtime/blob/release-27.0.0/RELEASES.md) * [26.0.x](https://github.com/bytecodealliance/wasmtime/blob/release-26.0.0/RELEASES.md) * [25.0.x](https://github.com/bytecodealliance/wasmtime/blob/release-25.0.0/RELEASES.md) diff --git a/benches/call.rs b/benches/call.rs index 9eca3bc6cd53..8e7d95aa8ffb 100644 --- a/benches/call.rs +++ b/benches/call.rs @@ -1,5 +1,3 @@ -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] - use criterion::measurement::WallTime; use criterion::{criterion_group, criterion_main, BenchmarkGroup, Criterion}; use std::fmt::Debug; @@ -445,7 +443,7 @@ trait ToVals { macro_rules! tuples { ($($t:ident)*) => ( - #[allow(non_snake_case)] + #[allow(non_snake_case, reason = "macro-generated code")] impl<$($t:Copy + Into,)*> ToVals for ($($t,)*) { fn to_vals(&self) -> Vec { let mut _dst = Vec::new(); @@ -534,7 +532,7 @@ mod component { macro_rules! tuples { ($($t:ident)*) => ( - #[allow(non_snake_case)] + #[allow(non_snake_case, reason = "macro-generated code")] impl<$($t:Copy + ToComponentVal,)*> ToComponentVals for ($($t,)*) { fn to_component_vals(&self) -> Vec { let mut _dst = Vec::new(); diff --git a/ci/build-build-matrix.js b/ci/build-build-matrix.js index e865172017ad..42e81114651e 100644 --- a/ci/build-build-matrix.js +++ b/ci/build-build-matrix.js @@ -4,13 +4,17 @@ // 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 ubuntu = 'ubuntu-24.04'; +const windows = 'windows-2022'; +const macos = 'macos-14'; + 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", + "os": ubuntu, // The Rust target that will be used for the build. "target": "x86_64-unknown-linux-gnu", }, @@ -18,57 +22,57 @@ const array = [ // than x86_64 Linux. // { // "build": "aarch64-linux", - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "aarch64-unknown-linux-gnu", // }, // { // "build": "s390x-linux", - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "s390x-unknown-linux-gnu", // }, // { // "build": "riscv64gc-linux", - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "riscv64gc-unknown-linux-gnu", // }, // { // "build": "x86_64-macos", - // "os": "macos-latest", + // "os": macos, // "target": "x86_64-apple-darwin", // }, // { // "build": "aarch64-macos", - // "os": "macos-latest", + // "os": macos, // "target": "aarch64-apple-darwin", // }, // { // "build": "x86_64-windows", - // "os": "windows-latest", + // "os": windows, // "target": "x86_64-pc-windows-msvc", // }, // { // "build": "x86_64-mingw", - // "os": "windows-latest", + // "os": windows, // "target": "x86_64-pc-windows-gnu", // }, // { // "build": "aarch64-android", - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "aarch64-linux-android", // }, // { // "build": "x86_64-android", - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "x86_64-linux-android", // }, // { // "build": "x86_64-musl", - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "x86_64-unknown-linux-musl", // }, // { // "build": "aarch64-windows", - // "os": "windows-latest", + // "os": windows, // "target": "aarch64-pc-windows-msvc", // }, ]; diff --git a/ci/build-test-matrix.js b/ci/build-test-matrix.js index 10b5fcd73939..8e7da72f6710 100644 --- a/ci/build-test-matrix.js +++ b/ci/build-test-matrix.js @@ -15,11 +15,15 @@ const GENERIC_BUCKETS = 3; // compile-and-test crates. const SINGLE_CRATE_BUCKETS = ["wasmtime", "wasmtime-cli", "wasmtime-wasi"]; +const ubuntu = 'ubuntu-24.04'; +const windows = 'windows-2022'; +const macos = 'macos-14'; + // This is the small, fast-to-execute matrix we use for PRs before they enter // the merge queue. Same schema as `FULL_MATRIX`. const FAST_MATRIX = [ { - "os": "ubuntu-latest", + "os": ubuntu, "name": "Test Linux x86_64", "filter": "linux-x64", "isa": "x64", @@ -64,19 +68,18 @@ function supports32Bit(pkg) { const FULL_MATRIX = [ ...FAST_MATRIX, { - "os": "ubuntu-latest", + "os": ubuntu, "name": "Test MSRV on Linux x86_64", "filter": "linux-x64", "isa": "x64", "rust": "msrv", }, { - "os": "ubuntu-latest", + "os": ubuntu, "name": "Test Linux x86_64 with MPK", "filter": "linux-x64", "isa": "x64" }, - // TODO(dhil): Disabled as long as we don't support other platforms // than x86_64 Linux. // { @@ -85,24 +88,24 @@ const FULL_MATRIX = [ // "filter": "macos-x64", // }, // { - // "os": "macos-14", + // "os": macos, // "name": "Test macOS arm64", // "filter": "macos-arm64", // "target": "aarch64-apple-darwin", // }, // { - // "os": "windows-latest", + // "os": windows, // "name": "Test Windows MSVC x86_64", // "filter": "windows-x64", // }, // { - // "os": "windows-latest", + // "os": windows, // "target": "x86_64-pc-windows-gnu", // "name": "Test Windows MinGW x86_64", // "filter": "mingw-x64" // }, // { - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "aarch64-unknown-linux-gnu", // "gcc_package": "gcc-aarch64-linux-gnu", // "gcc": "aarch64-linux-gnu-gcc", @@ -113,7 +116,7 @@ const FULL_MATRIX = [ // "isa": "aarch64", // }, // { - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "s390x-unknown-linux-gnu", // "gcc_package": "gcc-s390x-linux-gnu", // "gcc": "s390x-linux-gnu-gcc", @@ -124,11 +127,11 @@ const FULL_MATRIX = [ // "isa": "s390x" // }, // { - // "os": "ubuntu-latest", + // "os": ubuntu, // "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,Zfa=true,Zfh=true,zba=true,zbb=true,zbc=true,zbs=true,zbkb=true,zcb=true,x-zicond=true -L /usr/riscv64-linux-gnu", + // "qemu": "qemu-riscv64 -cpu rv64,v=true,vlen=256,vext_spec=v1.0,zfa=true,zfh=true,zba=true,zbb=true,zbc=true,zbs=true,zbkb=true,zcb=true,zicond=true -L /usr/riscv64-linux-gnu", // "qemu_target": "riscv64-linux-user", // "name": "Test Linux riscv64", // "filter": "linux-riscv64", @@ -137,7 +140,7 @@ const FULL_MATRIX = [ // { // "name": "Tests on i686-unknown-linux-gnu", // "32-bit": true, - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "i686-unknown-linux-gnu", // "gcc_package": "gcc-i686-linux-gnu", // "gcc": "i686-linux-gnu-gcc", @@ -145,7 +148,7 @@ const FULL_MATRIX = [ // { // "name": "Tests on armv7-unknown-linux-gnueabihf", // "32-bit": true, - // "os": "ubuntu-latest", + // "os": ubuntu, // "target": "armv7-unknown-linux-gnueabihf", // "gcc_package": "gcc-arm-linux-gnueabihf", // "gcc": "arm-linux-gnueabihf-gcc", diff --git a/cranelift/Cargo.toml b/cranelift/Cargo.toml index 4cca318de5a5..6a82b6c35078 100644 --- a/cranelift/Cargo.toml +++ b/cranelift/Cargo.toml @@ -52,6 +52,7 @@ rustc-hash = { workspace = true } # Note that this just enables `trace-log` for `clif-util` and doesn't turn it on # for all of Cranelift, which would be bad. regalloc2 = { workspace = true, features = ["trace-log"] } +pulley-interpreter = { workspace = true, optional = true } [features] default = [ @@ -64,3 +65,4 @@ disas = ["capstone"] souper-harvest = ["cranelift-codegen/souper-harvest", "rayon"] all-arch = ["cranelift-codegen/all-arch"] all-native-arch = ["cranelift-codegen/all-native-arch"] +pulley = ['cranelift-codegen/pulley', 'dep:pulley-interpreter'] diff --git a/cranelift/bforest/Cargo.toml b/cranelift/bforest/Cargo.toml index 55e3b6aef8c4..02f38e8a3ff8 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.115.0" +version = "0.116.0" description = "A forest of B+-trees" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift-bforest" diff --git a/cranelift/bitset/Cargo.toml b/cranelift/bitset/Cargo.toml index 4835ad8fbb4f..f9cd4521dd5f 100644 --- a/cranelift/bitset/Cargo.toml +++ b/cranelift/bitset/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-bitset" -version = "0.115.0" +version = "0.116.0" description = "Various bitset stuff for use inside Cranelift" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift-bitset" diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index c8fa87090860..8c4a0a97f5b3 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.115.0" +version = "0.116.0" description = "Low-level code generator library" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift-codegen" @@ -24,7 +24,7 @@ features = ["all-arch"] anyhow = { workspace = true, optional = true, features = ['std'] } bumpalo = "3" capstone = { workspace = true, optional = true } -cranelift-codegen-shared = { path = "./shared", version = "0.115.0" } +cranelift-codegen-shared = { path = "./shared", version = "0.116.0" } cranelift-entity = { workspace = true } cranelift-bforest = { workspace = true } cranelift-bitset = { workspace = true } @@ -53,8 +53,8 @@ similar = "2.1.0" env_logger = { workspace = true } [build-dependencies] -cranelift-codegen-meta = { path = "meta", version = "0.115.0" } -cranelift-isle = { path = "../isle/isle", version = "=0.115.0" } +cranelift-codegen-meta = { path = "meta", version = "0.116.0" } +cranelift-isle = { path = "../isle/isle", version = "=0.116.0" } [features] default = ["std", "unwind", "host-arch", "timing"] diff --git a/cranelift/codegen/meta/Cargo.toml b/cranelift/codegen/meta/Cargo.toml index f89aef993796..52e3df080ff9 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.115.0" +version = "0.116.0" description = "Metaprogram for cranelift-codegen code generator library" license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/bytecodealliance/wasmtime" @@ -16,4 +16,4 @@ workspace = true rustdoc-args = [ "--document-private-items" ] [dependencies] -cranelift-codegen-shared = { path = "../shared", version = "0.115.0" } +cranelift-codegen-shared = { path = "../shared", version = "0.116.0" } diff --git a/cranelift/codegen/shared/Cargo.toml b/cranelift/codegen/shared/Cargo.toml index e2718a34a1db..8e8fde7efce8 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.115.0" +version = "0.116.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/isa/pulley_shared/abi.rs b/cranelift/codegen/src/isa/pulley_shared/abi.rs index 067f593caf02..3d2bfe43f8b2 100644 --- a/cranelift/codegen/src/isa/pulley_shared/abi.rs +++ b/cranelift/codegen/src/isa/pulley_shared/abi.rs @@ -220,18 +220,8 @@ where ] } - fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec { - smallvec![Inst::TrapIf { - cond: ir::condcodes::IntCC::UnsignedLessThan, - size: match P::pointer_width() { - super::PointerWidth::PointerWidth32 => OperandSize::Size32, - super::PointerWidth::PointerWidth64 => OperandSize::Size64, - }, - src1: limit_reg.try_into().unwrap(), - src2: pulley_interpreter::regs::XReg::sp.into(), - code: ir::TrapCode::STACK_OVERFLOW, - } - .into()] + fn gen_stack_lower_bound_trap(_limit_reg: Reg) -> SmallInstVec { + unimplemented!("pulley shouldn't need stack bound checks") } fn gen_get_stack_addr(mem: StackAMode, dst: Writable) -> Self::I { @@ -254,29 +244,25 @@ where } fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec { - let temp = WritableXReg::try_from(writable_spilltmp_reg()).unwrap(); + if amount == 0 { + return smallvec![]; + } - let imm = if let Ok(x) = i8::try_from(amount) { - Inst::Xconst8 { dst: temp, imm: x }.into() - } else if let Ok(x) = i16::try_from(amount) { - Inst::Xconst16 { dst: temp, imm: x }.into() + let inst = if amount < 0 { + let amount = amount.checked_neg().unwrap(); + if let Ok(amt) = u32::try_from(amount) { + Inst::StackAlloc32 { amt } + } else { + unreachable!() + } } else { - Inst::Xconst32 { - dst: temp, - imm: amount, + if let Ok(amt) = u32::try_from(amount) { + Inst::StackFree32 { amt } + } else { + unreachable!() } - .into() }; - - smallvec![ - imm, - Inst::Xadd32 { - dst: WritableXReg::try_from(writable_stack_reg()).unwrap(), - src1: XReg::new(stack_reg()).unwrap(), - src2: temp.to_reg(), - } - .into() - ] + smallvec![inst.into()] } fn gen_prologue_frame_setup( @@ -288,29 +274,7 @@ where let mut insts = SmallVec::new(); if frame_layout.setup_area_size > 0 { - // sp = sub sp, 16 ;; alloc stack space for frame pointer and return address. - // store sp+8, lr ;; save return address. - // store sp, fp ;; save old fp. - // mov sp, fp ;; set fp to sp. - insts.extend(Self::gen_sp_reg_adjust(-16)); - insts.push( - Inst::gen_store( - Amode::SpOffset { offset: 8 }, - link_reg(), - I64, - MemFlags::trusted(), - ) - .into(), - ); - insts.push( - Inst::gen_store( - Amode::SpOffset { offset: 0 }, - fp_reg(), - I64, - MemFlags::trusted(), - ) - .into(), - ); + insts.push(Inst::PushFrame.into()); if flags.unwind_info() { insts.push( Inst::Unwind { @@ -321,13 +285,6 @@ where .into(), ); } - insts.push( - Inst::Xmov { - dst: Writable::from_reg(XReg::new(fp_reg()).unwrap()), - src: XReg::new(stack_reg()).unwrap(), - } - .into(), - ); } insts @@ -343,25 +300,7 @@ where let mut insts = SmallVec::new(); if frame_layout.setup_area_size > 0 { - insts.push( - Inst::gen_load( - writable_link_reg(), - Amode::SpOffset { offset: 8 }, - I64, - MemFlags::trusted(), - ) - .into(), - ); - insts.push( - Inst::gen_load( - writable_fp_reg(), - Amode::SpOffset { offset: 0 }, - I64, - MemFlags::trusted(), - ) - .into(), - ); - insts.extend(Self::gen_sp_reg_adjust(16)); + insts.push(Inst::PopFrame.into()); } if frame_layout.tail_args_size > 0 { @@ -382,7 +321,8 @@ where } fn gen_probestack(_insts: &mut SmallInstVec, _frame_size: u32) { - todo!() + // Pulley doesn't implement stack probes since all stack pointer + // decrements are checked already. } fn gen_clobber_save( @@ -405,7 +345,7 @@ where insts.push( Inst::gen_store( Amode::SpOffset { offset: 8 }, - link_reg(), + lr_reg(), I64, MemFlags::trusted(), ) @@ -578,11 +518,15 @@ where } fn get_number_of_spillslots_for_value( - _rc: RegClass, + rc: RegClass, _target_vector_bytes: u32, _isa_flags: &PulleyFlags, ) -> u32 { - todo!() + match rc { + RegClass::Int => 1, + RegClass::Float => todo!(), + RegClass::Vector => unreachable!(), + } } fn get_machine_env(_flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv { @@ -647,7 +591,8 @@ where _frame_size: u32, _guard_size: u32, ) { - todo!() + // Pulley doesn't need inline probestacks because it always checks stack + // decrements. } } diff --git a/cranelift/codegen/src/isa/pulley_shared/inst.isle b/cranelift/codegen/src/isa/pulley_shared/inst.isle index 2ad356f622fd..6a15e140148c 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst.isle +++ b/cranelift/codegen/src/isa/pulley_shared/inst.isle @@ -39,8 +39,11 @@ ;; Nothing. (Nop) - ;; Get the stack pointer. - (GetSp (dst WritableXReg)) + ;; Move a special register (e.g. sp, fp, lr, etc) in to a general-purpose + ;; register. + (GetSpecial + (dst WritableXReg) + (reg XReg)) ;; Return. (Ret) @@ -117,6 +120,12 @@ (BitcastIntFromFloat64 (dst WritableXReg) (src FReg)) (BitcastFloatFromInt32 (dst WritableFReg) (src XReg)) (BitcastFloatFromInt64 (dst WritableFReg) (src XReg)) + + ;; Stack manipulations + (PushFrame) + (PopFrame) + (StackAlloc32 (amt u32)) + (StackFree32 (amt u32)) ) ) @@ -378,11 +387,20 @@ (rule (pulley_trap_if cond size src1 src2 code) (SideEffectNoResult.Inst (MInst.TrapIf cond size src1 src2 code))) -(decl pulley_get_sp () XReg) -(rule (pulley_get_sp) - (let ((reg WritableXReg (temp_writable_xreg)) - (_ Unit (emit (MInst.GetSp reg)))) - reg)) +(decl sp_reg () XReg) +(extern constructor sp_reg sp_reg) + +(decl fp_reg () XReg) +(extern constructor fp_reg fp_reg) + +(decl lr_reg () XReg) +(extern constructor lr_reg lr_reg) + +(decl pulley_get_special (XReg) XReg) +(rule (pulley_get_special reg) + (let ((dst WritableXReg (temp_writable_xreg)) + (_ Unit (emit (MInst.GetSpecial dst reg)))) + dst)) (decl pulley_xconst8 (i8) XReg) (rule (pulley_xconst8 x) diff --git a/cranelift/codegen/src/isa/pulley_shared/inst/args.rs b/cranelift/codegen/src/isa/pulley_shared/inst/args.rs index 468f31a13643..e70dfbaf2249 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst/args.rs +++ b/cranelift/codegen/src/isa/pulley_shared/inst/args.rs @@ -126,6 +126,20 @@ impl XReg { /// Index of the first "special" register, or the end of which registers /// regalloc is allowed to use. pub const SPECIAL_START: u8 = pulley_interpreter::regs::XReg::SPECIAL_START; + + /// Returns whether this is a "special" physical register for pulley. + pub fn is_special(&self) -> bool { + match self.as_pulley() { + Some(reg) => reg.is_special(), + None => false, + } + } + + /// Returns the pulley-typed register, if this is a phyiscal register. + pub fn as_pulley(&self) -> Option { + let enc = self.to_real_reg()?.hw_enc(); + Some(pulley_interpreter::XReg::new(enc).unwrap()) + } } pub use super::super::lower::isle::generated_code::ExtKind; @@ -166,7 +180,7 @@ impl Amode { + frame_layout.outgoing_args_size; i64::from(sp_offset) - offset } - StackAMode::Slot(offset) => *offset + state.virtual_sp_offset, + StackAMode::Slot(offset) => *offset, StackAMode::OutgoingArg(offset) => *offset, }, } diff --git a/cranelift/codegen/src/isa/pulley_shared/inst/emit.rs b/cranelift/codegen/src/isa/pulley_shared/inst/emit.rs index 3382fc1d1ee2..b103e4fee04d 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst/emit.rs +++ b/cranelift/codegen/src/isa/pulley_shared/inst/emit.rs @@ -4,7 +4,6 @@ use super::*; use crate::ir; use crate::isa::pulley_shared::abi::PulleyMachineDeps; use crate::isa::pulley_shared::PointerWidth; -use crate::trace; use core::marker::PhantomData; use cranelift_control::ControlPlane; use pulley_interpreter::encode as enc; @@ -40,7 +39,6 @@ where _phantom: PhantomData

, ctrl_plane: ControlPlane, user_stack_map: Option, - pub virtual_sp_offset: i64, frame_layout: FrameLayout, } @@ -51,13 +49,6 @@ where fn take_stack_map(&mut self) -> Option { self.user_stack_map.take() } - - pub(crate) fn adjust_virtual_sp_offset(&mut self, amount: i64) { - let old = self.virtual_sp_offset; - let new = self.virtual_sp_offset + amount; - trace!("adjust virtual sp offset by {amount:#x}: {old:#x} -> {new:#x}",); - self.virtual_sp_offset = new; - } } impl

MachInstEmitState> for EmitState

@@ -69,7 +60,6 @@ where _phantom: PhantomData, ctrl_plane, user_stack_map: None, - virtual_sp_offset: 0, frame_layout: abi.frame_layout().clone(), } } @@ -188,7 +178,7 @@ fn pulley_emit

( Inst::Nop => todo!(), - Inst::GetSp { dst } => enc::get_sp(sink, dst), + Inst::GetSpecial { dst, reg } => enc::xmov(sink, dst, reg), Inst::Ret => enc::ret(sink), @@ -211,8 +201,10 @@ fn pulley_emit

( } sink.add_call_site(); - let callee_pop_size = i64::from(info.callee_pop_size); - state.adjust_virtual_sp_offset(-callee_pop_size); + let adjust = -i32::try_from(info.callee_pop_size).unwrap(); + for i in PulleyMachineDeps::

::gen_sp_reg_adjust(adjust) { + >::from(i).emit(sink, emit_info, state); + } } Inst::IndirectCall { info } => { @@ -225,8 +217,10 @@ fn pulley_emit

( sink.add_call_site(); - let callee_pop_size = i64::from(info.callee_pop_size); - state.adjust_virtual_sp_offset(-callee_pop_size); + let adjust = -i32::try_from(info.callee_pop_size).unwrap(); + for i in PulleyMachineDeps::

::gen_sp_reg_adjust(adjust) { + >::from(i).emit(sink, emit_info, state); + } } Inst::IndirectCallHost { info } => { @@ -554,6 +548,11 @@ fn pulley_emit

( // the assertion that we're always under worst-case-size. *start_offset = sink.cur_offset(); } + + Inst::PushFrame => enc::push_frame(sink), + Inst::PopFrame => enc::pop_frame(sink), + Inst::StackAlloc32 { amt } => enc::stack_alloc32(sink, *amt), + Inst::StackFree32 { amt } => enc::stack_free32(sink, *amt), } } diff --git a/cranelift/codegen/src/isa/pulley_shared/inst/mod.rs b/cranelift/codegen/src/isa/pulley_shared/inst/mod.rs index 2bfb34cdc8a7..7b8768c1ec99 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst/mod.rs +++ b/cranelift/codegen/src/isa/pulley_shared/inst/mod.rs @@ -79,8 +79,12 @@ fn pulley_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) { collector.reg_use(src2); } - Inst::GetSp { dst } => { + Inst::GetSpecial { dst, reg } => { collector.reg_def(dst); + // Note that this is explicitly ignored as this is only used for + // special registers that don't participate in register allocation + // such as the stack pointer, frame pointer, etc. + assert!(reg.is_special()); } Inst::LoadExtName { @@ -248,6 +252,9 @@ fn pulley_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) { Inst::BrTable { idx, .. } => { collector.reg_use(idx); } + + Inst::StackAlloc32 { .. } | Inst::StackFree32 { .. } | Inst::PushFrame | Inst::PopFrame => { + } } } @@ -568,9 +575,10 @@ impl Inst { Inst::Ret => format!("ret"), - Inst::GetSp { dst } => { + Inst::GetSpecial { dst, reg } => { let dst = format_reg(*dst.to_reg()); - format!("{dst} = get_sp") + let reg = format_reg(**reg); + format!("xmov {dst}, {reg}") } Inst::LoadExtName { dst, name, offset } => { @@ -857,6 +865,15 @@ impl Inst { let idx = format_reg(**idx); format!("br_table {idx} {default:?} {targets:?}") } + + Inst::StackAlloc32 { amt } => { + format!("stack_alloc32 {amt:#x}") + } + Inst::StackFree32 { amt } => { + format!("stack_free32 {amt:#x}") + } + Inst::PushFrame => format!("push_frame"), + Inst::PopFrame => format!("pop_frame"), } } } diff --git a/cranelift/codegen/src/isa/pulley_shared/inst/regs.rs b/cranelift/codegen/src/isa/pulley_shared/inst/regs.rs index 16da50b582f0..f274db871142 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst/regs.rs +++ b/cranelift/codegen/src/isa/pulley_shared/inst/regs.rs @@ -91,7 +91,7 @@ define_registers! { x_reg(26) => x26, writable_x26; x_reg(27) => stack_reg, writable_stack_reg; - x_reg(28) => link_reg, writable_link_reg; + x_reg(28) => lr_reg, writable_lr_reg; x_reg(29) => fp_reg, writable_fp_reg; x_reg(30) => spilltmp_reg, writable_spilltmp_reg; x_reg(31) => spilltmp2_reg, writable_spilltmp2_reg; diff --git a/cranelift/codegen/src/isa/pulley_shared/lower.isle b/cranelift/codegen/src/isa/pulley_shared/lower.isle index b03d3b1e33d5..00de3b70838c 100644 --- a/cranelift/codegen/src/isa/pulley_shared/lower.isle +++ b/cranelift/codegen/src/isa/pulley_shared/lower.isle @@ -114,7 +114,17 @@ ;;;; Rules for `get_stack_pointer` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (rule (lower (get_stack_pointer)) - (pulley_get_sp)) + (pulley_get_special (sp_reg))) + +;;;; Rules for `get_frame_pointer` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (get_frame_pointer)) + (pulley_get_special (fp_reg))) + +;;;; Rules for `get_return_address` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(rule (lower (get_return_address)) + (pulley_get_special (lr_reg))) ;;;; Rules for `return` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/cranelift/codegen/src/isa/pulley_shared/lower/isle.rs b/cranelift/codegen/src/isa/pulley_shared/lower/isle.rs index f75fe027f239..ae61bbc18fbc 100644 --- a/cranelift/codegen/src/isa/pulley_shared/lower/isle.rs +++ b/cranelift/codegen/src/isa/pulley_shared/lower/isle.rs @@ -10,6 +10,7 @@ use crate::ir::{condcodes::*, immediates::*, types::*, *}; use crate::isa::pulley_shared::{ abi::*, inst::{FReg, OperandSize, VReg, WritableFReg, WritableVReg, WritableXReg, XReg}, + lower::regs, *, }; use crate::machinst::{ @@ -101,6 +102,18 @@ where fn emit(&mut self, arg0: &MInst) -> Unit { self.lower_ctx.emit(arg0.clone().into()); } + + fn sp_reg(&mut self) -> XReg { + XReg::new(regs::stack_reg()).unwrap() + } + + fn fp_reg(&mut self) -> XReg { + XReg::new(regs::fp_reg()).unwrap() + } + + fn lr_reg(&mut self) -> XReg { + XReg::new(regs::lr_reg()).unwrap() + } } /// The main entry point for lowering with ISLE. diff --git a/cranelift/codegen/src/isa/s390x/abi.rs b/cranelift/codegen/src/isa/s390x/abi.rs index 986663160300..57b213e4ea81 100644 --- a/cranelift/codegen/src/isa/s390x/abi.rs +++ b/cranelift/codegen/src/isa/s390x/abi.rs @@ -738,14 +738,29 @@ impl ABIMachineSpec for S390xMachineDeps { // Use STMG to save clobbered GPRs into save area. // Note that we always save SP (%r15) here if anything is saved. if let Some((first_clobbered_gpr, _)) = get_clobbered_gprs(frame_layout) { + let mut last_clobbered_gpr = 15; let offset = 8 * first_clobbered_gpr as i64 + incoming_tail_args_size as i64; insts.push(Inst::StoreMultiple64 { rt: gpr(first_clobbered_gpr), - rt2: gpr(15), + rt2: gpr(last_clobbered_gpr), mem: MemArg::reg_plus_off(stack_reg(), offset, MemFlags::trusted()), }); if flags.unwind_info() { - for i in first_clobbered_gpr..16 { + // Normally, we instruct the unwinder to restore the stack pointer + // from its slot in the save area. However, if we have incoming + // tail-call arguments, the value saved in that slot is incorrect. + // In that case, we instead instruct the unwinder to compute the + // unwound SP relative to the current CFA, as CFA == SP + 160. + if incoming_tail_args_size != 0 { + insts.push(Inst::Unwind { + inst: UnwindInst::RegStackOffset { + clobber_offset: frame_layout.clobber_size, + reg: gpr(last_clobbered_gpr).to_real_reg().unwrap(), + }, + }); + last_clobbered_gpr = last_clobbered_gpr - 1; + } + for i in first_clobbered_gpr..(last_clobbered_gpr + 1) { insts.push(Inst::Unwind { inst: UnwindInst::SaveReg { clobber_offset: frame_layout.clobber_size + (i * 8) as u32, diff --git a/cranelift/codegen/src/isa/unwind.rs b/cranelift/codegen/src/isa/unwind.rs index 305e7b4704a2..ada37b03ccbb 100644 --- a/cranelift/codegen/src/isa/unwind.rs +++ b/cranelift/codegen/src/isa/unwind.rs @@ -196,6 +196,15 @@ pub enum UnwindInst { /// The saved register. reg: RealReg, }, + /// Computes the value of the given register in the caller as stack offset. + /// Typically used to unwind the stack pointer if the default rule does not apply. + /// The `clobber_offset` is computed the same way as for the `SaveReg` rule. + RegStackOffset { + /// The offset from the start of the clobber area to this register's value. + clobber_offset: u32, + /// The register whose value is to be set. + reg: RealReg, + }, /// Defines if the aarch64-specific pointer authentication available for ARM v8.3+ devices /// is enabled for certain pointers or not. Aarch64SetPointerAuth { diff --git a/cranelift/codegen/src/isa/unwind/systemv.rs b/cranelift/codegen/src/isa/unwind/systemv.rs index ba77103394c5..5a721fbd8232 100644 --- a/cranelift/codegen/src/isa/unwind/systemv.rs +++ b/cranelift/codegen/src/isa/unwind/systemv.rs @@ -247,6 +247,19 @@ pub(crate) fn create_unwind_info_from_insts>( let off = (clobber_offset as i32) - (clobber_offset_to_cfa as i32); instructions.push((instruction_offset, CallFrameInstruction::Offset(reg, off))); } + &UnwindInst::RegStackOffset { + clobber_offset, + reg, + } => { + let reg = mr + .map(reg.into()) + .map_err(|e| CodegenError::RegisterMappingError(e))?; + let off = (clobber_offset as i32) - (clobber_offset_to_cfa as i32); + instructions.push(( + instruction_offset, + CallFrameInstruction::ValOffset(reg, off), + )); + } &UnwindInst::Aarch64SetPointerAuth { return_addresses } => { instructions.push(( instruction_offset, diff --git a/cranelift/codegen/src/isa/unwind/winarm64.rs b/cranelift/codegen/src/isa/unwind/winarm64.rs index a4ab147fb439..58a1b38b9df4 100644 --- a/cranelift/codegen/src/isa/unwind/winarm64.rs +++ b/cranelift/codegen/src/isa/unwind/winarm64.rs @@ -301,6 +301,9 @@ pub(crate) fn create_unwind_info_from_insts( } } } + &UnwindInst::RegStackOffset { .. } => { + unreachable!("only supported with DWARF"); + } &UnwindInst::Aarch64SetPointerAuth { return_addresses } => { assert!( return_addresses, diff --git a/cranelift/codegen/src/isa/unwind/winx64.rs b/cranelift/codegen/src/isa/unwind/winx64.rs index 8a23494b1f43..55014518b54f 100644 --- a/cranelift/codegen/src/isa/unwind/winx64.rs +++ b/cranelift/codegen/src/isa/unwind/winx64.rs @@ -285,6 +285,9 @@ pub(crate) fn create_unwind_info_from_insts { + unreachable!("only supported with DWARF"); + } &UnwindInst::Aarch64SetPointerAuth { .. } => { unreachable!("no aarch64 on x64"); } diff --git a/cranelift/control/Cargo.toml b/cranelift/control/Cargo.toml index 5b49a10733dc..10f44466b860 100644 --- a/cranelift/control/Cargo.toml +++ b/cranelift/control/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-control" -version = "0.115.0" +version = "0.116.0" description = "White-box fuzz testing framework" license = "Apache-2.0 WITH LLVM-exception" repository = "https://github.com/bytecodealliance/wasmtime" diff --git a/cranelift/entity/Cargo.toml b/cranelift/entity/Cargo.toml index 62625d33e128..3ea4fd842f81 100644 --- a/cranelift/entity/Cargo.toml +++ b/cranelift/entity/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-entity" -version = "0.115.0" +version = "0.116.0" description = "Data structures using entity references as mapping keys" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift-entity" diff --git a/cranelift/entity/src/list.rs b/cranelift/entity/src/list.rs index 65d54d43e0e6..29a6293c19bc 100644 --- a/cranelift/entity/src/list.rs +++ b/cranelift/entity/src/list.rs @@ -45,7 +45,7 @@ use serde_derive::{Deserialize, Serialize}; /// The `EntityList` itself is designed to have the smallest possible footprint. This is important /// because it is used inside very compact data structures like `InstructionData`. The list /// contains only a 32-bit index into the pool's memory vector, pointing to the first element of -/// the list. +/// the list. A zero value represents the empty list, which is returned by `EntityList::default`. /// /// The pool is just a single `Vec` containing all of the allocated lists. Each list is /// represented as three contiguous parts: @@ -64,6 +64,7 @@ use serde_derive::{Deserialize, Serialize}; /// reserved for the empty list which isn't allocated in the vector. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[repr(C)] pub struct EntityList { index: u32, unused: PhantomData, diff --git a/cranelift/entity/src/packed_option.rs b/cranelift/entity/src/packed_option.rs index e6d0eed1468c..e4b949f34818 100644 --- a/cranelift/entity/src/packed_option.rs +++ b/cranelift/entity/src/packed_option.rs @@ -22,8 +22,12 @@ pub trait ReservedValue { } /// Packed representation of `Option`. +/// +/// This is a wrapper around a `T`, using `T::reserved_value` to represent +/// `None`. #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[repr(transparent)] pub struct PackedOption(T); impl PackedOption { diff --git a/cranelift/filetests/filetests/isa/pulley32/call.clif b/cranelift/filetests/filetests/isa/pulley32/call.clif index b458e181a31c..6a162d085b50 100644 --- a/cranelift/filetests/filetests/isa/pulley32/call.clif +++ b/cranelift/filetests/filetests/isa/pulley32/call.clif @@ -13,34 +13,20 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; x0 = xconst8 0 ; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }], clobbers: PRegSet { bits: [65534, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } ; x0 = xconst8 1 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; xconst8 x0, 0 -; call 0x0 // target = 0x13 +; call 0x0 // target = 0x4 ; xconst8 x0, 1 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame ; ret function %colocated_args_i32_rets_i32() -> i32 { @@ -54,34 +40,20 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; x0 = xconst8 0 ; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }], clobbers: PRegSet { bits: [65534, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } ; x0 = xconst8 1 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; xconst8 x0, 0 -; call 0x0 // target = 0x13 +; call 0x0 // target = 0x4 ; xconst8 x0, 1 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame ; ret function %colocated_args_i64_i32_i64_i32() { @@ -97,38 +69,24 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; x0 = xconst8 0 ; x1 = xconst8 1 ; x2 = xconst8 2 ; x3 = xconst8 3 ; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }, CallArgPair { vreg: p1i, preg: p1i }, CallArgPair { vreg: p2i, preg: p2i }, CallArgPair { vreg: p3i, preg: p3i }], defs: [], clobbers: PRegSet { bits: [65535, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; xconst8 x0, 0 ; xconst8 x1, 1 ; xconst8 x2, 2 ; xconst8 x3, 3 -; call 0x0 // target = 0x1c -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; call 0x0 // target = 0xd +; pop_frame ; ret function %colocated_rets_i64_i64_i64_i64() -> i64 { @@ -143,36 +101,22 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; call CallInfo { dest: TestCase(%g), uses: [], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }, CallRetPair { vreg: Writable { reg: p1i }, preg: p1i }, CallRetPair { vreg: Writable { reg: p2i }, preg: p2i }, CallRetPair { vreg: Writable { reg: p3i }, preg: p3i }], clobbers: PRegSet { bits: [65520, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } ; x4 = xadd64 x0, x2 ; x3 = xadd64 x1, x3 ; x0 = xadd64 x4, x3 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp -; call 0x0 // target = 0x10 +; push_frame +; call 0x0 // target = 0x1 ; xadd64 x4, x0, x2 ; xadd64 x3, x1, x3 ; xadd64 x0, x4, x3 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame ; ret function %colocated_stack_args() { @@ -185,13 +129,8 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 -; x30 = xconst8 -48 -; x27 = xadd32 x27, x30 +; push_frame +; stack_alloc32 0x30 ; block0: ; x15 = xconst8 0 ; store64 OutgoingArg(0), x15 // flags = notrap aligned @@ -216,22 +155,13 @@ block0: ; x13 = xmov x15 ; x14 = xmov x15 ; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }, CallArgPair { vreg: p1i, preg: p1i }, CallArgPair { vreg: p2i, preg: p2i }, CallArgPair { vreg: p3i, preg: p3i }, CallArgPair { vreg: p4i, preg: p4i }, CallArgPair { vreg: p5i, preg: p5i }, CallArgPair { vreg: p6i, preg: p6i }, CallArgPair { vreg: p7i, preg: p7i }, CallArgPair { vreg: p8i, preg: p8i }, CallArgPair { vreg: p9i, preg: p9i }, CallArgPair { vreg: p10i, preg: p10i }, CallArgPair { vreg: p11i, preg: p11i }, CallArgPair { vreg: p12i, preg: p12i }, CallArgPair { vreg: p13i, preg: p13i }, CallArgPair { vreg: p14i, preg: p14i }, CallArgPair { vreg: p15i, preg: p15i }], defs: [], clobbers: PRegSet { bits: [65535, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } -; x30 = xconst8 48 -; x27 = xadd32 x27, x30 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; stack_free32 0x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp -; xconst8 spilltmp0, -48 -; xadd32 sp, sp, spilltmp0 +; push_frame +; stack_alloc32 48 ; xconst8 x15, 0 ; store64 sp, x15 ; store64_offset8 sp, 8, x15 @@ -254,13 +184,9 @@ block0: ; xmov x12, x15 ; xmov x13, x15 ; xmov x14, x15 -; call 0x0 // target = 0x5d -; xconst8 spilltmp0, 48 -; xadd32 sp, sp, spilltmp0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; call 0x0 // target = 0x4d +; stack_free32 48 +; pop_frame ; ret function %colocated_stack_rets() -> i64 { @@ -300,13 +226,8 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 -; x30 = xconst8 -64 -; x27 = xadd32 x27, x30 +; push_frame +; stack_alloc32 0x40 ; store64 sp+56, x18 // flags = notrap aligned ; store64 sp+48, x20 // flags = notrap aligned ; block0: @@ -346,26 +267,17 @@ block0: ; x0 = xadd64 x14, x13 ; x18 = load64_u sp+56 // flags = notrap aligned ; x20 = load64_u sp+48 // flags = notrap aligned -; x30 = xconst8 64 -; x27 = xadd32 x27, x30 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; stack_free32 0x40 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp -; xconst8 spilltmp0, -64 -; xadd32 sp, sp, spilltmp0 +; push_frame +; stack_alloc32 64 ; store64_offset8 sp, 56, x18 ; store64_offset8 sp, 48, x20 ; xmov x0, sp -; call 0x0 // target = 0x21 +; call 0x0 // target = 0x11 ; xmov x18, x13 ; xmov x20, x11 ; load64 x24, sp @@ -400,12 +312,8 @@ block0: ; xadd64 x0, x14, x13 ; load64_offset8 x18, sp, 56 ; load64_offset8 x20, sp, 48 -; xconst8 spilltmp0, 64 -; xadd32 sp, sp, spilltmp0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; stack_free32 64 +; pop_frame ; ret function %call_indirect(i32) -> i64 { @@ -417,29 +325,15 @@ block0(v0: i32): } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; indirect_call x0, CallInfo { dest: XReg(p0i), uses: [], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }], clobbers: PRegSet { bits: [65534, 65279, 4294967295, 0] }, callee_conv: Tail, caller_conv: Fast, callee_pop_size: 0 } -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; call_indirect x0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame ; ret diff --git a/cranelift/filetests/filetests/isa/pulley32/get_stack_pointer.clif b/cranelift/filetests/filetests/isa/pulley32/get_stack_pointer.clif deleted file mode 100644 index f269efa92e36..000000000000 --- a/cranelift/filetests/filetests/isa/pulley32/get_stack_pointer.clif +++ /dev/null @@ -1,18 +0,0 @@ -test compile precise-output -target pulley32 - -function %get_stack_pointer() -> i32 { -block0: - v0 = get_stack_pointer.i32 - return v0 -} - -; VCode: -; block0: -; x0 = get_sp -; ret -; -; Disassembled: -; get_sp x0 -; ret - diff --git a/cranelift/filetests/filetests/isa/pulley32/special_regs.clif b/cranelift/filetests/filetests/isa/pulley32/special_regs.clif new file mode 100644 index 000000000000..bdad9d89b973 --- /dev/null +++ b/cranelift/filetests/filetests/isa/pulley32/special_regs.clif @@ -0,0 +1,61 @@ +test compile precise-output +set preserve_frame_pointers +target pulley32 + +function %get_stack_pointer() -> i32 { +block0: + v0 = get_stack_pointer.i32 + return v0 +} + +; VCode: +; push_frame +; block0: +; xmov x0, x27 +; pop_frame +; ret +; +; Disassembled: +; push_frame +; xmov x0, sp +; pop_frame +; ret + +function %get_frame_pointer() -> i32 { +block0: + v0 = get_frame_pointer.i32 + return v0 +} + +; VCode: +; push_frame +; block0: +; xmov x0, x29 +; pop_frame +; ret +; +; Disassembled: +; push_frame +; xmov x0, fp +; pop_frame +; ret + +function %get_return_address() -> i32 { +block0: + v0 = get_return_address.i32 + return v0 +} + +; VCode: +; push_frame +; block0: +; xmov x0, x28 +; pop_frame +; ret +; +; Disassembled: +; push_frame +; xmov x0, lr +; pop_frame +; ret + diff --git a/cranelift/filetests/filetests/isa/pulley32/stack_addr.clif b/cranelift/filetests/filetests/isa/pulley32/stack_addr.clif index c7c8261c14ad..ef6087e21c79 100644 --- a/cranelift/filetests/filetests/isa/pulley32/stack_addr.clif +++ b/cranelift/filetests/filetests/isa/pulley32/stack_addr.clif @@ -9,37 +9,19 @@ block0(): } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 +; push_frame +; stack_alloc32 0x10 ; block0: ; x0 = load_addr Slot(0) -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; stack_free32 0x10 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 +; push_frame +; stack_alloc32 16 ; xmov x0, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; stack_free32 16 +; pop_frame ; ret diff --git a/cranelift/filetests/filetests/isa/pulley64/call.clif b/cranelift/filetests/filetests/isa/pulley64/call.clif index de51731bf798..9470d04a4a02 100644 --- a/cranelift/filetests/filetests/isa/pulley64/call.clif +++ b/cranelift/filetests/filetests/isa/pulley64/call.clif @@ -13,34 +13,20 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; x0 = xconst8 0 ; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }], clobbers: PRegSet { bits: [65534, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } ; x0 = xconst8 1 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; xconst8 x0, 0 -; call 0x0 // target = 0x13 +; call 0x0 // target = 0x4 ; xconst8 x0, 1 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame ; ret function %colocated_args_i32_rets_i32() -> i32 { @@ -54,34 +40,20 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; x0 = xconst8 0 ; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }], clobbers: PRegSet { bits: [65534, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } ; x0 = xconst8 1 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; xconst8 x0, 0 -; call 0x0 // target = 0x13 +; call 0x0 // target = 0x4 ; xconst8 x0, 1 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame ; ret function %colocated_args_i64_i32_i64_i32() { @@ -97,38 +69,24 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; x0 = xconst8 0 ; x1 = xconst8 1 ; x2 = xconst8 2 ; x3 = xconst8 3 ; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }, CallArgPair { vreg: p1i, preg: p1i }, CallArgPair { vreg: p2i, preg: p2i }, CallArgPair { vreg: p3i, preg: p3i }], defs: [], clobbers: PRegSet { bits: [65535, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; xconst8 x0, 0 ; xconst8 x1, 1 ; xconst8 x2, 2 ; xconst8 x3, 3 -; call 0x0 // target = 0x1c -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; call 0x0 // target = 0xd +; pop_frame ; ret function %colocated_rets_i64_i64_i64_i64() -> i64 { @@ -143,36 +101,22 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; call CallInfo { dest: TestCase(%g), uses: [], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }, CallRetPair { vreg: Writable { reg: p1i }, preg: p1i }, CallRetPair { vreg: Writable { reg: p2i }, preg: p2i }, CallRetPair { vreg: Writable { reg: p3i }, preg: p3i }], clobbers: PRegSet { bits: [65520, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } ; x4 = xadd64 x0, x2 ; x3 = xadd64 x1, x3 ; x0 = xadd64 x4, x3 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp -; call 0x0 // target = 0x10 +; push_frame +; call 0x0 // target = 0x1 ; xadd64 x4, x0, x2 ; xadd64 x3, x1, x3 ; xadd64 x0, x4, x3 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame ; ret function %colocated_stack_args() { @@ -185,13 +129,8 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 -; x30 = xconst8 -48 -; x27 = xadd32 x27, x30 +; push_frame +; stack_alloc32 0x30 ; block0: ; x15 = xconst8 0 ; store64 OutgoingArg(0), x15 // flags = notrap aligned @@ -216,22 +155,13 @@ block0: ; x13 = xmov x15 ; x14 = xmov x15 ; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }, CallArgPair { vreg: p1i, preg: p1i }, CallArgPair { vreg: p2i, preg: p2i }, CallArgPair { vreg: p3i, preg: p3i }, CallArgPair { vreg: p4i, preg: p4i }, CallArgPair { vreg: p5i, preg: p5i }, CallArgPair { vreg: p6i, preg: p6i }, CallArgPair { vreg: p7i, preg: p7i }, CallArgPair { vreg: p8i, preg: p8i }, CallArgPair { vreg: p9i, preg: p9i }, CallArgPair { vreg: p10i, preg: p10i }, CallArgPair { vreg: p11i, preg: p11i }, CallArgPair { vreg: p12i, preg: p12i }, CallArgPair { vreg: p13i, preg: p13i }, CallArgPair { vreg: p14i, preg: p14i }, CallArgPair { vreg: p15i, preg: p15i }], defs: [], clobbers: PRegSet { bits: [65535, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } -; x30 = xconst8 48 -; x27 = xadd32 x27, x30 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; stack_free32 0x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp -; xconst8 spilltmp0, -48 -; xadd32 sp, sp, spilltmp0 +; push_frame +; stack_alloc32 48 ; xconst8 x15, 0 ; store64 sp, x15 ; store64_offset8 sp, 8, x15 @@ -254,13 +184,9 @@ block0: ; xmov x12, x15 ; xmov x13, x15 ; xmov x14, x15 -; call 0x0 // target = 0x5d -; xconst8 spilltmp0, 48 -; xadd32 sp, sp, spilltmp0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; call 0x0 // target = 0x4d +; stack_free32 48 +; pop_frame ; ret function %colocated_stack_rets() -> i64 { @@ -300,13 +226,8 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 -; x30 = xconst8 -64 -; x27 = xadd32 x27, x30 +; push_frame +; stack_alloc32 0x40 ; store64 sp+56, x18 // flags = notrap aligned ; store64 sp+48, x20 // flags = notrap aligned ; block0: @@ -346,26 +267,17 @@ block0: ; x0 = xadd64 x14, x13 ; x18 = load64_u sp+56 // flags = notrap aligned ; x20 = load64_u sp+48 // flags = notrap aligned -; x30 = xconst8 64 -; x27 = xadd32 x27, x30 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; stack_free32 0x40 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp -; xconst8 spilltmp0, -64 -; xadd32 sp, sp, spilltmp0 +; push_frame +; stack_alloc32 64 ; store64_offset8 sp, 56, x18 ; store64_offset8 sp, 48, x20 ; xmov x0, sp -; call 0x0 // target = 0x21 +; call 0x0 // target = 0x11 ; xmov x18, x13 ; xmov x20, x11 ; load64 x24, sp @@ -400,12 +312,8 @@ block0: ; xadd64 x0, x14, x13 ; load64_offset8 x18, sp, 56 ; load64_offset8 x20, sp, 48 -; xconst8 spilltmp0, 64 -; xadd32 sp, sp, spilltmp0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; stack_free32 64 +; pop_frame ; ret function %call_indirect(i64) -> i64 { @@ -417,29 +325,97 @@ block0(v0: i64): } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; indirect_call x0, CallInfo { dest: XReg(p0i), uses: [], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }], clobbers: PRegSet { bits: [65534, 65279, 4294967295, 0] }, callee_conv: Tail, caller_conv: Fast, callee_pop_size: 0 } -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; call_indirect x0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame +; ret + +function %colocated_with_stack_args() { + fn0 = colocated %g( + i64, i64, i64, i64, i64, i64, i64, i64, + i64, i64, i64, i64, i64, i64, i64, i64, + i64, i64, i64, i64, i64, i64, i64, i64 + ) + +block0: + v0 = iconst.i64 0 + call fn0( + v0, v0, v0, v0, v0, v0, v0, v0, + v0, v0, v0, v0, v0, v0, v0, v0, + v0, v0, v0, v0, v0, v0, v0, v0 + ) + return +} + +; VCode: +; push_frame +; stack_alloc32 0x40 +; block0: +; x15 = xconst8 0 +; store64 OutgoingArg(0), x15 // flags = notrap aligned +; store64 OutgoingArg(8), x15 // flags = notrap aligned +; store64 OutgoingArg(16), x15 // flags = notrap aligned +; store64 OutgoingArg(24), x15 // flags = notrap aligned +; store64 OutgoingArg(32), x15 // flags = notrap aligned +; store64 OutgoingArg(40), x15 // flags = notrap aligned +; store64 OutgoingArg(48), x15 // flags = notrap aligned +; store64 OutgoingArg(56), x15 // flags = notrap aligned +; x0 = xmov x15 +; x1 = xmov x15 +; x2 = xmov x15 +; x3 = xmov x15 +; x4 = xmov x15 +; x5 = xmov x15 +; x6 = xmov x15 +; x7 = xmov x15 +; x8 = xmov x15 +; x9 = xmov x15 +; x10 = xmov x15 +; x11 = xmov x15 +; x12 = xmov x15 +; x13 = xmov x15 +; x14 = xmov x15 +; call CallInfo { dest: TestCase(%g), uses: [CallArgPair { vreg: p0i, preg: p0i }, CallArgPair { vreg: p1i, preg: p1i }, CallArgPair { vreg: p2i, preg: p2i }, CallArgPair { vreg: p3i, preg: p3i }, CallArgPair { vreg: p4i, preg: p4i }, CallArgPair { vreg: p5i, preg: p5i }, CallArgPair { vreg: p6i, preg: p6i }, CallArgPair { vreg: p7i, preg: p7i }, CallArgPair { vreg: p8i, preg: p8i }, CallArgPair { vreg: p9i, preg: p9i }, CallArgPair { vreg: p10i, preg: p10i }, CallArgPair { vreg: p11i, preg: p11i }, CallArgPair { vreg: p12i, preg: p12i }, CallArgPair { vreg: p13i, preg: p13i }, CallArgPair { vreg: p14i, preg: p14i }, CallArgPair { vreg: p15i, preg: p15i }], defs: [], clobbers: PRegSet { bits: [65535, 65279, 4294967295, 0] }, callee_conv: Fast, caller_conv: Fast, callee_pop_size: 0 } +; stack_free32 0x40 +; pop_frame +; ret +; +; Disassembled: +; push_frame +; stack_alloc32 64 +; xconst8 x15, 0 +; store64 sp, x15 +; store64_offset8 sp, 8, x15 +; store64_offset8 sp, 16, x15 +; store64_offset8 sp, 24, x15 +; store64_offset8 sp, 32, x15 +; store64_offset8 sp, 40, x15 +; store64_offset8 sp, 48, x15 +; store64_offset8 sp, 56, x15 +; xmov x0, x15 +; xmov x1, x15 +; xmov x2, x15 +; xmov x3, x15 +; xmov x4, x15 +; xmov x5, x15 +; xmov x6, x15 +; xmov x7, x15 +; xmov x8, x15 +; xmov x9, x15 +; xmov x10, x15 +; xmov x11, x15 +; xmov x12, x15 +; xmov x13, x15 +; xmov x14, x15 +; call 0x0 // target = 0x55 +; stack_free32 64 +; pop_frame ; ret diff --git a/cranelift/filetests/filetests/isa/pulley64/call_indirect_host.clif b/cranelift/filetests/filetests/isa/pulley64/call_indirect_host.clif index 4592004936bb..0d2b206dc972 100644 --- a/cranelift/filetests/filetests/isa/pulley64/call_indirect_host.clif +++ b/cranelift/filetests/filetests/isa/pulley64/call_indirect_host.clif @@ -9,29 +9,15 @@ block0: } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 +; push_frame ; block0: ; indirect_call_host CallInfo { dest: User(userextname0), uses: [], defs: [], clobbers: PRegSet { bits: [65535, 65279, 4294967295, 0] }, callee_conv: SystemV, caller_conv: Fast, callee_pop_size: 0 } -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp +; push_frame ; call_indirect_host 0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; pop_frame ; ret diff --git a/cranelift/filetests/filetests/isa/pulley64/get_stack_pointer.clif b/cranelift/filetests/filetests/isa/pulley64/get_stack_pointer.clif deleted file mode 100644 index e3df1187e779..000000000000 --- a/cranelift/filetests/filetests/isa/pulley64/get_stack_pointer.clif +++ /dev/null @@ -1,18 +0,0 @@ -test compile precise-output -target pulley64 - -function %get_stack_pointer() -> i64 { -block0: - v0 = get_stack_pointer.i64 - return v0 -} - -; VCode: -; block0: -; x0 = get_sp -; ret -; -; Disassembled: -; get_sp x0 -; ret - diff --git a/cranelift/filetests/filetests/isa/pulley64/special_regs.clif b/cranelift/filetests/filetests/isa/pulley64/special_regs.clif new file mode 100644 index 000000000000..448a806b6500 --- /dev/null +++ b/cranelift/filetests/filetests/isa/pulley64/special_regs.clif @@ -0,0 +1,61 @@ +test compile precise-output +set preserve_frame_pointers +target pulley64 + +function %get_stack_pointer() -> i64 { +block0: + v0 = get_stack_pointer.i64 + return v0 +} + +; VCode: +; push_frame +; block0: +; xmov x0, x27 +; pop_frame +; ret +; +; Disassembled: +; push_frame +; xmov x0, sp +; pop_frame +; ret + +function %get_frame_pointer() -> i64 { +block0: + v0 = get_frame_pointer.i64 + return v0 +} + +; VCode: +; push_frame +; block0: +; xmov x0, x29 +; pop_frame +; ret +; +; Disassembled: +; push_frame +; xmov x0, fp +; pop_frame +; ret + +function %get_return_address() -> i64 { +block0: + v0 = get_return_address.i64 + return v0 +} + +; VCode: +; push_frame +; block0: +; xmov x0, x28 +; pop_frame +; ret +; +; Disassembled: +; push_frame +; xmov x0, lr +; pop_frame +; ret + diff --git a/cranelift/filetests/filetests/isa/pulley64/stack_addr.clif b/cranelift/filetests/filetests/isa/pulley64/stack_addr.clif index d642b2492ec0..b9190587fc21 100644 --- a/cranelift/filetests/filetests/isa/pulley64/stack_addr.clif +++ b/cranelift/filetests/filetests/isa/pulley64/stack_addr.clif @@ -9,37 +9,19 @@ block0(): } ; VCode: -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 -; store64 sp+8, x28 // flags = notrap aligned -; store64 sp+0, x29 // flags = notrap aligned -; x29 = xmov x27 -; x30 = xconst8 -16 -; x27 = xadd32 x27, x30 +; push_frame +; stack_alloc32 0x10 ; block0: ; x0 = load_addr Slot(0) -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 -; x28 = load64_u sp+8 // flags = notrap aligned -; x29 = load64_u sp+0 // flags = notrap aligned -; x30 = xconst8 16 -; x27 = xadd32 x27, x30 +; stack_free32 0x10 +; pop_frame ; ret ; ; Disassembled: -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 -; store64_offset8 sp, 8, lr -; store64 sp, fp -; xmov fp, sp -; xconst8 spilltmp0, -16 -; xadd32 sp, sp, spilltmp0 +; push_frame +; stack_alloc32 16 ; xmov x0, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 -; load64_offset8 lr, sp, 8 -; load64 fp, sp -; xconst8 spilltmp0, 16 -; xadd32 sp, sp, spilltmp0 +; stack_free32 16 +; pop_frame ; ret diff --git a/cranelift/filetests/src/function_runner.rs b/cranelift/filetests/src/function_runner.rs index 2feae28e0183..bc00b1be7dbc 100644 --- a/cranelift/filetests/src/function_runner.rs +++ b/cranelift/filetests/src/function_runner.rs @@ -528,7 +528,10 @@ fn make_trampoline(name: UserFuncName, signature: &ir::Signature, isa: &dyn Targ #[cfg(target_arch = "x86_64")] use std::arch::x86_64::__m128i; #[cfg(target_arch = "x86_64")] -#[allow(improper_ctypes_definitions)] +#[expect( + improper_ctypes_definitions, + reason = "manually verified to work for now" +)] extern "C" fn __cranelift_x86_pshufb(a: __m128i, b: __m128i) -> __m128i { union U { reg: __m128i, diff --git a/cranelift/filetests/src/lib.rs b/cranelift/filetests/src/lib.rs index ab776ba5ea90..b09ba6560737 100644 --- a/cranelift/filetests/src/lib.rs +++ b/cranelift/filetests/src/lib.rs @@ -4,7 +4,6 @@ //! available filetest commands. #![deny(missing_docs)] -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] pub use crate::function_runner::TestFileCompiler; use crate::runner::TestRunner; diff --git a/cranelift/filetests/src/subtest.rs b/cranelift/filetests/src/subtest.rs index a0761ad9ba21..5321a4e1c9f0 100644 --- a/cranelift/filetests/src/subtest.rs +++ b/cranelift/filetests/src/subtest.rs @@ -29,7 +29,7 @@ pub struct Context<'a> { pub isa: Option<&'a dyn TargetIsa>, /// Full path to the file containing the test. - #[allow(dead_code)] + #[expect(dead_code, reason = "may get used later")] pub file_path: &'a str, /// Context used to update the original `file_path` in-place with its test diff --git a/cranelift/filetests/src/test_unwind.rs b/cranelift/filetests/src/test_unwind.rs index f9fe196dff02..7b01873af06d 100644 --- a/cranelift/filetests/src/test_unwind.rs +++ b/cranelift/filetests/src/test_unwind.rs @@ -108,7 +108,7 @@ mod windowsx64 { version: u8, flags: u8, prologue_size: u8, - #[allow(dead_code)] + #[expect(dead_code, reason = "may get used later")] unwind_code_count_raw: u8, frame_register: u8, frame_register_offset: u8, diff --git a/cranelift/frontend/Cargo.toml b/cranelift/frontend/Cargo.toml index 705465a795cd..88878c9ff153 100644 --- a/cranelift/frontend/Cargo.toml +++ b/cranelift/frontend/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-frontend" -version = "0.115.0" +version = "0.116.0" description = "Cranelift IR builder helper" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift-frontend" diff --git a/cranelift/frontend/src/lib.rs b/cranelift/frontend/src/lib.rs index 8f97474b2486..7a9c80919910 100644 --- a/cranelift/frontend/src/lib.rs +++ b/cranelift/frontend/src/lib.rs @@ -157,10 +157,7 @@ #![deny(missing_docs)] #![no_std] -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] -#[allow(unused_imports)] // #[macro_use] is required for no_std -#[macro_use] extern crate alloc; #[cfg(feature = "std")] diff --git a/cranelift/frontend/src/switch.rs b/cranelift/frontend/src/switch.rs index 24d0fb714bac..9605557a980a 100644 --- a/cranelift/frontend/src/switch.rs +++ b/cranelift/frontend/src/switch.rs @@ -348,8 +348,8 @@ mod tests { let block = bx.create_block(); bx.switch_to_block(block); let val = bx.ins().iconst(types::I8, 0); - #[allow(unused_mut)] let mut switch = Switch::new(); + let _ = &mut switch; $( let block = bx.create_block(); switch.set_entry($index, block); diff --git a/cranelift/interpreter/Cargo.toml b/cranelift/interpreter/Cargo.toml index 35682924b644..96c2055011c6 100644 --- a/cranelift/interpreter/Cargo.toml +++ b/cranelift/interpreter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cranelift-interpreter" -version = "0.115.0" +version = "0.116.0" authors = ["The Cranelift Project Developers"] description = "Interpret Cranelift IR" repository = "https://github.com/bytecodealliance/wasmtime" diff --git a/cranelift/isle/isle/Cargo.toml b/cranelift/isle/isle/Cargo.toml index 0f86584ed5f5..2707bffe8bee 100644 --- a/cranelift/isle/isle/Cargo.toml +++ b/cranelift/isle/isle/Cargo.toml @@ -7,7 +7,7 @@ license = "Apache-2.0 WITH LLVM-exception" name = "cranelift-isle" readme = "../README.md" repository = "https://github.com/bytecodealliance/wasmtime/tree/main/cranelift/isle" -version = "0.115.0" +version = "0.116.0" [lints] workspace = true diff --git a/cranelift/jit/Cargo.toml b/cranelift/jit/Cargo.toml index d07d33f2dbc2..201b478e745a 100644 --- a/cranelift/jit/Cargo.toml +++ b/cranelift/jit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cranelift-jit" -version = "0.115.0" +version = "0.116.0" authors = ["The Cranelift Project Developers"] description = "A JIT library backed by Cranelift" repository = "https://github.com/bytecodealliance/wasmtime" diff --git a/cranelift/module/Cargo.toml b/cranelift/module/Cargo.toml index 999d878f9ae4..78e3391d8fa4 100644 --- a/cranelift/module/Cargo.toml +++ b/cranelift/module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cranelift-module" -version = "0.115.0" +version = "0.116.0" authors = ["The Cranelift Project Developers"] description = "Support for linking functions and data with Cranelift" repository = "https://github.com/bytecodealliance/wasmtime" diff --git a/cranelift/module/src/lib.rs b/cranelift/module/src/lib.rs index eb78fcd5c46e..7528ad67caad 100644 --- a/cranelift/module/src/lib.rs +++ b/cranelift/module/src/lib.rs @@ -2,7 +2,6 @@ #![deny(missing_docs)] #![no_std] -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] #[cfg(not(feature = "std"))] #[macro_use] diff --git a/cranelift/module/src/module.rs b/cranelift/module/src/module.rs index d9494b851ed2..4a32837787ca 100644 --- a/cranelift/module/src/module.rs +++ b/cranelift/module/src/module.rs @@ -220,12 +220,10 @@ impl From for ModuleRelocTarget { feature = "enable-serde", derive(serde_derive::Serialize, serde_derive::Deserialize) )] +#[allow(missing_docs, reason = "self-describing fields")] pub struct FunctionDeclaration { - #[allow(missing_docs)] pub name: Option, - #[allow(missing_docs)] pub linkage: Linkage, - #[allow(missing_docs)] pub signature: ir::Signature, } @@ -379,14 +377,11 @@ pub type ModuleResult = Result; feature = "enable-serde", derive(serde_derive::Serialize, serde_derive::Deserialize) )] +#[allow(missing_docs, reason = "self-describing fields")] pub struct DataDeclaration { - #[allow(missing_docs)] pub name: Option, - #[allow(missing_docs)] pub linkage: Linkage, - #[allow(missing_docs)] pub writable: bool, - #[allow(missing_docs)] pub tls: bool, } diff --git a/cranelift/native/Cargo.toml b/cranelift/native/Cargo.toml index 9cdeab94e283..53b14b6fb625 100644 --- a/cranelift/native/Cargo.toml +++ b/cranelift/native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cranelift-native" -version = "0.115.0" +version = "0.116.0" authors = ["The Cranelift Project Developers"] description = "Support for targeting the host with Cranelift" documentation = "https://docs.rs/cranelift-native" diff --git a/cranelift/object/Cargo.toml b/cranelift/object/Cargo.toml index e596d64b1f63..299ac3dde7a3 100644 --- a/cranelift/object/Cargo.toml +++ b/cranelift/object/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cranelift-object" -version = "0.115.0" +version = "0.116.0" authors = ["The Cranelift Project Developers"] description = "Emit Cranelift output to native object files with `object`" repository = "https://github.com/bytecodealliance/wasmtime" diff --git a/cranelift/reader/Cargo.toml b/cranelift/reader/Cargo.toml index 62d568db1a2d..c19aad16b5a1 100644 --- a/cranelift/reader/Cargo.toml +++ b/cranelift/reader/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift-reader" -version = "0.115.0" +version = "0.116.0" description = "Cranelift textual IR reader" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift-reader" diff --git a/cranelift/reader/src/lexer.rs b/cranelift/reader/src/lexer.rs index 28d75feb5137..76b36e1920de 100644 --- a/cranelift/reader/src/lexer.rs +++ b/cranelift/reader/src/lexer.rs @@ -3,8 +3,6 @@ use crate::error::Location; use cranelift_codegen::ir::types; use cranelift_codegen::ir::{Block, Value}; -#[allow(unused_imports, deprecated)] -use std::ascii::AsciiExt; use std::str::CharIndices; use std::u16; diff --git a/cranelift/reader/src/lib.rs b/cranelift/reader/src/lib.rs index 7dbc732b28e6..e4d5ea95e030 100644 --- a/cranelift/reader/src/lib.rs +++ b/cranelift/reader/src/lib.rs @@ -4,7 +4,6 @@ //! testing Cranelift, but is not essential for a JIT compiler. #![deny(missing_docs)] -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] pub use crate::error::{Location, ParseError, ParseResult}; pub use crate::isaspec::{parse_option, parse_options, IsaSpec, ParseOptionError}; @@ -30,7 +29,7 @@ use std::str::FromStr; use target_lexicon::Triple; /// Like `FlagsOrIsa`, but holds ownership. -#[allow(missing_docs)] +#[allow(missing_docs, reason = "self-describing variants")] pub enum OwnedFlagsOrIsa { Flags(settings::Flags), Isa(OwnedTargetIsa), diff --git a/cranelift/reader/src/run_command.rs b/cranelift/reader/src/run_command.rs index 0c1b2876d362..2fa616539694 100644 --- a/cranelift/reader/src/run_command.rs +++ b/cranelift/reader/src/run_command.rs @@ -105,7 +105,7 @@ impl Display for Invocation { } /// A CLIF comparison operation; e.g. `==`. -#[allow(missing_docs)] +#[allow(missing_docs, reason = "self-describing variants")] #[derive(Debug, PartialEq)] pub enum Comparison { Equals, diff --git a/cranelift/serde/Cargo.toml b/cranelift/serde/Cargo.toml index 91df931730b1..753db4073bfc 100644 --- a/cranelift/serde/Cargo.toml +++ b/cranelift/serde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cranelift-serde" -version = "0.115.0" +version = "0.116.0" authors = ["The Cranelift Project Developers"] description = "Serializer/Deserializer for Cranelift IR" repository = "https://github.com/bytecodealliance/wasmtime" diff --git a/cranelift/src/disasm.rs b/cranelift/src/disasm.rs index 6947a5b977a9..574f72ec3bf6 100644 --- a/cranelift/src/disasm.rs +++ b/cranelift/src/disasm.rs @@ -39,9 +39,22 @@ pub fn print_traps(traps: &[MachTrap]) -> String { cfg_if! { if #[cfg(feature = "disas")] { pub fn print_disassembly(func: &Function, isa: &dyn TargetIsa, mem: &[u8]) -> Result<()> { + #[cfg(feature = "pulley")] + let is_pulley = match isa.triple().architecture { + target_lexicon::Architecture::Pulley32 | target_lexicon::Architecture::Pulley64 => true, + _ => false, + }; + println!("\nDisassembly of {} bytes <{}>:", mem.len(), func.name); + + #[cfg(feature = "pulley")] + if is_pulley { + let mut disas = pulley_interpreter::disas::Disassembler::new(mem); + pulley_interpreter::decode::Decoder::decode_all(&mut disas)?; + println!("{}", disas.disas()); + return Ok(()); + } let cs = isa.to_capstone().map_err(|e| anyhow::format_err!("{}", e))?; - println!("\nDisassembly of {} bytes <{}>:", mem.len(), func.name); let insns = cs.disasm_all(&mem, 0x0).unwrap(); for i in insns.iter() { let mut line = String::new(); diff --git a/cranelift/umbrella/Cargo.toml b/cranelift/umbrella/Cargo.toml index 1a941fe7af37..244bdfecaac9 100644 --- a/cranelift/umbrella/Cargo.toml +++ b/cranelift/umbrella/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["The Cranelift Project Developers"] name = "cranelift" -version = "0.115.0" +version = "0.116.0" description = "Umbrella for commonly-used cranelift crates" license = "Apache-2.0 WITH LLVM-exception" documentation = "https://docs.rs/cranelift" diff --git a/crates/asm-macros/src/lib.rs b/crates/asm-macros/src/lib.rs index 0fd62e8b382f..92b04380b489 100644 --- a/crates/asm-macros/src/lib.rs +++ b/crates/asm-macros/src/lib.rs @@ -13,7 +13,7 @@ cfg_if::cfg_if! { #[macro_export] macro_rules! asm_func { ($name:expr, $body:expr $(, $($args:tt)*)?) => { - std::arch::global_asm!( + core::arch::global_asm!( concat!( ".p2align 4\n", ".private_extern _", $name, "\n", @@ -29,7 +29,7 @@ cfg_if::cfg_if! { #[macro_export] macro_rules! asm_func { ($name:expr, $body:expr $(, $($args:tt)*)?) => { - std::arch::global_asm!( + core::arch::global_asm!( concat!( ".def ", $name, "\n", ".scl 2\n", @@ -65,7 +65,7 @@ cfg_if::cfg_if! { #[macro_export] macro_rules! asm_func { ($name:expr, $body:expr $(, $($args:tt)*)?) => { - std::arch::global_asm!( + core::arch::global_asm!( concat!( ".p2align 4\n", ".hidden ", $name, "\n", diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index 25ca60024719..5cf6f3aa08e9 100644 --- a/crates/c-api/include/wasmtime.h +++ b/crates/c-api/include/wasmtime.h @@ -206,11 +206,11 @@ /** * \brief Wasmtime version string. */ -#define WASMTIME_VERSION "28.0.0" +#define WASMTIME_VERSION "29.0.0" /** * \brief Wasmtime major version number. */ -#define WASMTIME_VERSION_MAJOR 28 +#define WASMTIME_VERSION_MAJOR 29 /** * \brief Wasmtime minor version number. */ diff --git a/crates/component-macro/tests/codegen.rs b/crates/component-macro/tests/codegen.rs index c9124aa665cb..73d61fd99539 100644 --- a/crates/component-macro/tests/codegen.rs +++ b/crates/component-macro/tests/codegen.rs @@ -1,5 +1,4 @@ -#![allow(dead_code)] -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] +#![allow(dead_code, reason = "lots of macro-generated code")] macro_rules! gentest { ($id:ident $name:tt $path:tt) => { @@ -135,7 +134,6 @@ mod trappable_errors_with_versioned_and_unversioned_packages { }, }); - #[allow(dead_code)] type MyX = u64; } @@ -177,7 +175,6 @@ mod trappable_errors { }, }); - #[allow(dead_code)] type MyX = u32; } diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index c4f9bfe05b77..4ec769398291 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -268,25 +268,27 @@ impl wasmtime_environ::Compiler for Compiler { // abort for the whole program since the runtime limits configured by // the embedder should cause wasm to trap before it reaches that // (ensuring the host has enough space as well for its functionality). - let vmctx = context - .func - .create_global_value(ir::GlobalValueData::VMContext); - let interrupts_ptr = context.func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: i32::from(func_env.offsets.ptr.vmctx_runtime_limits()).into(), - global_type: isa.pointer_type(), - flags: MemFlags::trusted().with_readonly(), - }); - let stack_limit = context.func.create_global_value(ir::GlobalValueData::Load { - base: interrupts_ptr, - offset: i32::from(func_env.offsets.ptr.vmruntime_limits_stack_limit()).into(), - global_type: isa.pointer_type(), - flags: MemFlags::trusted(), - }); - if func_env.signals_based_traps() { - context.func.stack_limit = Some(stack_limit); - } else { - func_env.stack_limit_at_function_entry = Some(stack_limit); + if !func_env.is_pulley() { + let vmctx = context + .func + .create_global_value(ir::GlobalValueData::VMContext); + let interrupts_ptr = context.func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: i32::from(func_env.offsets.ptr.vmctx_runtime_limits()).into(), + global_type: isa.pointer_type(), + flags: MemFlags::trusted().with_readonly(), + }); + let stack_limit = context.func.create_global_value(ir::GlobalValueData::Load { + base: interrupts_ptr, + offset: i32::from(func_env.offsets.ptr.vmruntime_limits_stack_limit()).into(), + global_type: isa.pointer_type(), + flags: MemFlags::trusted(), + }); + if func_env.signals_based_traps() { + context.func.stack_limit = Some(stack_limit); + } else { + func_env.stack_limit_at_function_entry = Some(stack_limit); + } } let FunctionBodyData { validator, body } = input; let mut validator = diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 523b4a6e7e52..2cbcd46247d2 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -1205,6 +1205,14 @@ impl<'module_environment> FuncEnvironment<'module_environment> { i32::from(self.offsets.ptr.vm_func_ref_type_index()), ) } + + pub fn is_pulley(&self) -> bool { + match self.isa.triple().architecture { + target_lexicon::Architecture::Pulley32 => true, + target_lexicon::Architecture::Pulley64 => true, + _ => false, + } + } } struct Call<'a, 'func, 'module_env> { diff --git a/crates/environ/src/compile/mod.rs b/crates/environ/src/compile/mod.rs index 51da11a9f672..de12ba29f3f0 100644 --- a/crates/environ/src/compile/mod.rs +++ b/crates/environ/src/compile/mod.rs @@ -59,8 +59,7 @@ impl From for CompileError { } } -#[cfg(feature = "std")] -impl std::error::Error for CompileError { +impl core::error::Error for CompileError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { CompileError::Wasm(e) => Some(e), diff --git a/crates/environ/src/obj.rs b/crates/environ/src/obj.rs index 2b904d76b48d..d50b5b1eca0a 100644 --- a/crates/environ/src/obj.rs +++ b/crates/environ/src/obj.rs @@ -1,6 +1,8 @@ //! Utilities for working with object files that operate as Wasmtime's //! serialization and intermediate format for compiled modules. +use core::fmt; + /// Filler for the `os_abi` field of the ELF header. /// /// This is just a constant that seems reasonable in the sense it's unlikely to @@ -177,3 +179,21 @@ libcalls! { FmaF64 = "libcall_fmaf64" X86Pshufb = "libcall_x86_pshufb" } + +/// Workaround to implement `core::error::Error` until +/// gimli-rs/object#747 is settled. +pub struct ObjectCrateErrorWrapper(pub object::Error); + +impl fmt::Debug for ObjectCrateErrorWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Display for ObjectCrateErrorWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl core::error::Error for ObjectCrateErrorWrapper {} diff --git a/crates/environ/src/prelude.rs b/crates/environ/src/prelude.rs index 43168d1f1748..94d30d3b1363 100644 --- a/crates/environ/src/prelude.rs +++ b/crates/environ/src/prelude.rs @@ -26,61 +26,3 @@ pub use alloc::string::{String, ToString}; pub use alloc::vec; pub use alloc::vec::Vec; pub use wasmparser::collections::{IndexMap, IndexSet}; - -/// Convenience trait for converting `Result` into `anyhow::Result` -/// -/// Typically this is automatically done with the `?` operator in Rust and -/// by default this trait isn't necessary. With the `anyhow` crate's `std` -/// feature disabled, however, the `?` operator won't work because the `Error` -/// trait is not defined. This trait helps to bridge this gap. -/// -/// This does the same thing as `?` when the `std` feature is enabled, and when -/// `std` is disabled it'll use different trait bounds to create an -/// `anyhow::Error`. -/// -/// This trait is not suitable as a public interface because features change -/// what implements the trait. It's good enough for a wasmtime internal -/// implementation detail, however. -pub trait Err2Anyhow { - /// Convert `self` to `anyhow::Result`. - fn err2anyhow(self) -> anyhow::Result; -} - -impl Err2Anyhow for Result { - fn err2anyhow(self) -> anyhow::Result { - match self { - Ok(e) => Ok(e), - Err(e) => Err(e.into_anyhow()), - } - } -} - -/// Convenience trait to convert a value into `anyhow::Error` -/// -/// This trait is not a suitable public interface of Wasmtime so it's just an -/// internal implementation detail for now. This trait is conditionally -/// implemented on the `std` feature with different bounds. -pub trait IntoAnyhow { - /// Converts `self` into an `anyhow::Error`. - fn into_anyhow(self) -> anyhow::Error; -} - -#[cfg(feature = "std")] -impl IntoAnyhow for T -where - T: Into, -{ - fn into_anyhow(self) -> anyhow::Error { - self.into() - } -} - -#[cfg(not(feature = "std"))] -impl IntoAnyhow for T -where - T: core::fmt::Display + core::fmt::Debug + Send + Sync + 'static, -{ - fn into_anyhow(self) -> anyhow::Error { - anyhow::Error::msg(self) - } -} diff --git a/crates/environ/src/trap_encoding.rs b/crates/environ/src/trap_encoding.rs index ebcad02c723d..caff00c68af6 100644 --- a/crates/environ/src/trap_encoding.rs +++ b/crates/environ/src/trap_encoding.rs @@ -173,8 +173,7 @@ impl fmt::Display for Trap { } } -#[cfg(feature = "std")] -impl std::error::Error for Trap {} +impl core::error::Error for Trap {} /// Decodes the provided trap information section and attempts to find the trap /// code corresponding to the `offset` specified. diff --git a/crates/environ/src/types.rs b/crates/environ/src/types.rs index 397e2d1a6743..c9a28b720ef9 100644 --- a/crates/environ/src/types.rs +++ b/crates/environ/src/types.rs @@ -2006,8 +2006,7 @@ impl fmt::Display for SizeOverflow { } } -#[cfg(feature = "std")] -impl std::error::Error for SizeOverflow {} +impl core::error::Error for SizeOverflow {} impl From for Memory { fn from(ty: wasmparser::MemoryType) -> Memory { diff --git a/crates/fiber/Cargo.toml b/crates/fiber/Cargo.toml index 8d83fd03553f..55f0087767ea 100644 --- a/crates/fiber/Cargo.toml +++ b/crates/fiber/Cargo.toml @@ -15,10 +15,10 @@ workspace = true anyhow = { workspace = true } cfg-if = { workspace = true } wasmtime-versioned-export-macros = { workspace = true } +wasmtime-asm-macros = { workspace = true } [target.'cfg(unix)'.dependencies] rustix = { workspace = true, features = ["mm", "param"] } -wasmtime-asm-macros = { workspace = true } [target.'cfg(windows)'.dependencies.windows-sys] workspace = true @@ -33,3 +33,9 @@ wasmtime-versioned-export-macros = { workspace = true } [dev-dependencies] backtrace = "0.3.68" + +[features] + +# Assume presence of the standard library. Allows propagating +# panic-unwinds across fiber invocations. +std = [] diff --git a/crates/fiber/build.rs b/crates/fiber/build.rs index 19e7a516259c..d14343fc0893 100644 --- a/crates/fiber/build.rs +++ b/crates/fiber/build.rs @@ -23,8 +23,8 @@ fn main() { build.file("src/windows.c"); build.define("VERSIONED_SUFFIX", Some(versioned_suffix!())); } else if arch == "s390x" { - println!("cargo:rerun-if-changed=src/unix/s390x.S"); - build.file("src/unix/s390x.S"); + println!("cargo:rerun-if-changed=src/stackswitch/s390x.S"); + build.file("src/stackswitch/s390x.S"); build.define("VERSIONED_SUFFIX", Some(versioned_suffix!())); } else { // assume that this is included via inline assembly in the crate itself, diff --git a/crates/fiber/src/lib.rs b/crates/fiber/src/lib.rs index 06a188a62330..11cbe912f11b 100644 --- a/crates/fiber/src/lib.rs +++ b/crates/fiber/src/lib.rs @@ -1,15 +1,22 @@ #![expect(clippy::allow_attributes, reason = "crate not migrated yet")] +#![no_std] +#[cfg(any(feature = "std", unix, windows))] +#[macro_use] +extern crate std; +extern crate alloc; + +use alloc::boxed::Box; use anyhow::Error; -use std::any::Any; -use std::cell::Cell; -use std::io; -use std::marker::PhantomData; -use std::ops::Range; -use std::panic::{self, AssertUnwindSafe}; +use core::cell::Cell; +use core::marker::PhantomData; +use core::ops::Range; cfg_if::cfg_if! { - if #[cfg(windows)] { + if #[cfg(not(feature = "std"))] { + mod nostd; + use nostd as imp; + } else if #[cfg(windows)] { mod windows; use windows as imp; } else if #[cfg(unix)] { @@ -20,6 +27,11 @@ cfg_if::cfg_if! { } } +// Our own stack switcher routines are used on Unix and no_std +// platforms, but not on Windows (it has its own fiber API). +#[cfg(any(unix, not(feature = "std")))] +pub(crate) mod stackswitch; + /// Represents an execution stack to use for a fiber. pub struct FiberStack(imp::FiberStack); @@ -31,14 +43,16 @@ fn _assert_send_sync() { _assert_sync::(); } +pub type Result = core::result::Result; + impl FiberStack { /// Creates a new fiber stack of the given size. - pub fn new(size: usize) -> io::Result { + pub fn new(size: usize) -> Result { Ok(Self(imp::FiberStack::new(size)?)) } /// Creates a new fiber stack of the given size. - pub fn from_custom(custom: Box) -> io::Result { + pub fn from_custom(custom: Box) -> Result { Ok(Self(imp::FiberStack::from_custom(custom)?)) } @@ -55,11 +69,7 @@ impl FiberStack { /// /// The caller must properly allocate the stack space with a guard page and /// make the pages accessible for correct behavior. - pub unsafe fn from_raw_parts( - bottom: *mut u8, - guard_size: usize, - len: usize, - ) -> io::Result { + pub unsafe fn from_raw_parts(bottom: *mut u8, guard_size: usize, len: usize) -> Result { Ok(Self(imp::FiberStack::from_raw_parts( bottom, guard_size, len, )?)) @@ -128,7 +138,8 @@ enum RunResult { Resuming(Resume), Yield(Yield), Returned(Return), - Panicked(Box), + #[cfg(feature = "std")] + Panicked(Box), } impl<'a, Resume, Yield, Return> Fiber<'a, Resume, Yield, Return> { @@ -140,7 +151,7 @@ impl<'a, Resume, Yield, Return> Fiber<'a, Resume, Yield, Return> { pub fn new( stack: FiberStack, func: impl FnOnce(Resume, &mut Suspend) -> Return + 'a, - ) -> io::Result { + ) -> Result { let inner = imp::Fiber::new(&stack.0, func)?; Ok(Self { @@ -177,7 +188,11 @@ impl<'a, Resume, Yield, Return> Fiber<'a, Resume, Yield, Return> { Err(y) } RunResult::Returned(r) => Ok(r), - RunResult::Panicked(payload) => std::panic::resume_unwind(payload), + #[cfg(feature = "std")] + RunResult::Panicked(_payload) => { + use std::panic; + panic::resume_unwind(_payload); + } } } @@ -222,11 +237,27 @@ impl Suspend { inner, _phantom: PhantomData, }; - let result = panic::catch_unwind(AssertUnwindSafe(|| (func)(initial, &mut suspend))); - suspend.inner.switch::(match result { - Ok(result) => RunResult::Returned(result), - Err(panic) => RunResult::Panicked(panic), - }); + + #[cfg(feature = "std")] + { + use std::panic::{self, AssertUnwindSafe}; + let result = panic::catch_unwind(AssertUnwindSafe(|| (func)(initial, &mut suspend))); + suspend.inner.switch::(match result { + Ok(result) => RunResult::Returned(result), + Err(panic) => RunResult::Panicked(panic), + }); + } + // Note that it is sound to omit the `catch_unwind` here: it + // will not result in unwinding going off the top of the fiber + // stack, because the code on the fiber stack is invoked via + // an extern "C" boundary which will panic on unwinds. + #[cfg(not(feature = "std"))] + { + let result = (func)(initial, &mut suspend); + suspend + .inner + .switch::(RunResult::Returned(result)); + } } } @@ -236,11 +267,11 @@ impl Drop for Fiber<'_, A, B, C> { } } -#[cfg(test)] +#[cfg(all(test))] mod tests { use super::{Fiber, FiberStack}; + use alloc::string::ToString; use std::cell::Cell; - use std::panic::{self, AssertUnwindSafe}; use std::rc::Rc; #[test] @@ -332,7 +363,10 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn panics_propagated() { + use std::panic::{self, AssertUnwindSafe}; + let a = Rc::new(Cell::new(false)); let b = SetOnDrop(a.clone()); let fiber = diff --git a/crates/fiber/src/nostd.rs b/crates/fiber/src/nostd.rs new file mode 100644 index 000000000000..48bf3b6eae69 --- /dev/null +++ b/crates/fiber/src/nostd.rs @@ -0,0 +1,178 @@ +//! no_std implementation of fibers. +//! +//! This is a very stripped-down version of the Unix platform support, +//! but without mmap or guard pages, because on no_std systems we do +//! not assume that virtual memory exists. +//! +//! The stack layout is nevertheless the same (modulo the guard page) +//! as on Unix because we share its low-level implementations: +//! +//! ```text +//! 0xB000 +-----------------------+ <- top of stack +//! | &Cell | <- where to store results +//! 0xAff8 +-----------------------+ +//! | *const u8 | <- last sp to resume from +//! 0xAff0 +-----------------------+ <- 16-byte aligned +//! | | +//! ~ ... ~ <- actual native stack space to use +//! | | +//! 0x0000 +-----------------------+ +//! ``` +//! +//! Here `0xAff8` is filled in temporarily while `resume` is running. The fiber +//! started with 0xB000 as a parameter so it knows how to find this. +//! Additionally `resumes` stores state at 0xAff0 to restart execution, and +//! `suspend`, which has 0xB000 so it can find this, will read that and write +//! its own resumption information into this slot as well. + +use crate::stackswitch::*; +use crate::{Result, RunResult, RuntimeFiberStack}; +use alloc::boxed::Box; +use alloc::{vec, vec::Vec}; +use core::cell::Cell; +use core::ops::Range; + +// The no_std implementation is infallible in practice, but we use +// `anyhow::Error` here absent any better alternative. +pub type Error = anyhow::Error; + +pub struct FiberStack { + base: BasePtr, + len: usize, + /// Backing storage, if owned. Allocated once at startup and then + /// not reallocated afterward. + storage: Vec, +} + +struct BasePtr(*mut u8); + +unsafe impl Send for BasePtr {} +unsafe impl Sync for BasePtr {} + +const STACK_ALIGN: usize = 16; + +/// Align a pointer by incrementing it up to `align - 1` +/// bytes. `align` must be a power of two. Also updates the length as +/// appropriate so that `ptr + len` points to the same endpoint. +fn align_ptr(ptr: *mut u8, len: usize, align: usize) -> (*mut u8, usize) { + let ptr = ptr as usize; + let aligned = (ptr + align - 1) & !(align - 1); + let new_len = len - (aligned - ptr); + (aligned as *mut u8, new_len) +} + +impl FiberStack { + pub fn new(size: usize) -> Result { + // Round up the size to at least one page. + let size = core::cmp::max(4096, size); + let mut storage = vec![0; size]; + let (base, len) = align_ptr(storage.as_mut_ptr(), size, STACK_ALIGN); + Ok(FiberStack { + storage, + base: BasePtr(base), + len, + }) + } + + pub unsafe fn from_raw_parts(base: *mut u8, guard_size: usize, len: usize) -> Result { + Ok(FiberStack { + storage: vec![], + base: BasePtr(base.offset(isize::try_from(guard_size).unwrap())), + len, + }) + } + + pub fn is_from_raw_parts(&self) -> bool { + self.storage.is_empty() + } + + pub fn from_custom(_custom: Box) -> Result { + unimplemented!("Custom fiber stacks not supported in no_std fiber library") + } + + pub fn top(&self) -> Option<*mut u8> { + Some(self.base.0.wrapping_byte_add(self.len)) + } + + pub fn range(&self) -> Option> { + let base = self.base.0 as usize; + Some(base..base + self.len) + } + + pub fn guard_range(&self) -> Option> { + None + } +} + +pub struct Fiber; + +pub struct Suspend { + top_of_stack: *mut u8, +} + +extern "C" fn fiber_start(arg0: *mut u8, top_of_stack: *mut u8) +where + F: FnOnce(A, &mut super::Suspend) -> C, +{ + unsafe { + let inner = Suspend { top_of_stack }; + let initial = inner.take_resume::(); + super::Suspend::::execute(inner, initial, Box::from_raw(arg0.cast::())) + } +} + +impl Fiber { + pub fn new(stack: &FiberStack, func: F) -> Result + where + F: FnOnce(A, &mut super::Suspend) -> C, + { + unsafe { + let data = Box::into_raw(Box::new(func)).cast(); + wasmtime_fiber_init(stack.top().unwrap(), fiber_start::, data); + } + + Ok(Self) + } + + pub(crate) fn resume(&self, stack: &FiberStack, result: &Cell>) { + unsafe { + // Store where our result is going at the very tip-top of the + // stack, otherwise known as our reserved slot for this information. + // + // In the diagram above this is updating address 0xAff8 + let addr = stack.top().unwrap().cast::().offset(-1); + addr.write(result as *const _ as usize); + + wasmtime_fiber_switch(stack.top().unwrap()); + + // null this out to help catch use-after-free + addr.write(0); + } + } +} + +impl Suspend { + pub(crate) fn switch(&mut self, result: RunResult) -> A { + unsafe { + // Calculate 0xAff8 and then write to it + (*self.result_location::()).set(result); + + wasmtime_fiber_switch(self.top_of_stack); + + self.take_resume::() + } + } + + unsafe fn take_resume(&self) -> A { + match (*self.result_location::()).replace(RunResult::Executing) { + RunResult::Resuming(val) => val, + _ => panic!("not in resuming state"), + } + } + + unsafe fn result_location(&self) -> *const Cell> { + let ret = self.top_of_stack.cast::<*const u8>().offset(-1).read(); + assert!(!ret.is_null()); + ret.cast() + } +} diff --git a/crates/fiber/src/stackswitch.rs b/crates/fiber/src/stackswitch.rs new file mode 100644 index 000000000000..5e32bb989fb8 --- /dev/null +++ b/crates/fiber/src/stackswitch.rs @@ -0,0 +1,38 @@ +//! ISA-specific stack-switching routines. + +// The bodies are defined in inline assembly in the conditionally +// included modules below; their symbols are visible in the binary and +// accessed via the `extern "C"` declarations below that. + +cfg_if::cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + } else if #[cfg(target_arch = "x86")] { + mod x86; + } else if #[cfg(target_arch = "arm")] { + mod arm; + } else if #[cfg(target_arch = "s390x")] { + // currently `global_asm!` isn't stable on s390x so this is an external + // assembler file built with the `build.rs`. + } else if #[cfg(target_arch = "riscv64")] { + mod riscv64; + } else { + compile_error!("fibers are not supported on this CPU architecture"); + } +} + +extern "C" { + #[wasmtime_versioned_export_macros::versioned_link] + pub(crate) fn wasmtime_fiber_init( + top_of_stack: *mut u8, + entry: extern "C" fn(*mut u8, *mut u8), + entry_arg0: *mut u8, + ); + #[wasmtime_versioned_export_macros::versioned_link] + pub(crate) fn wasmtime_fiber_switch(top_of_stack: *mut u8); + #[allow(dead_code, reason = "only used on some platforms for inline asm")] + #[wasmtime_versioned_export_macros::versioned_link] + pub(crate) fn wasmtime_fiber_start(); +} diff --git a/crates/fiber/src/unix/aarch64.rs b/crates/fiber/src/stackswitch/aarch64.rs similarity index 100% rename from crates/fiber/src/unix/aarch64.rs rename to crates/fiber/src/stackswitch/aarch64.rs diff --git a/crates/fiber/src/unix/arm.rs b/crates/fiber/src/stackswitch/arm.rs similarity index 100% rename from crates/fiber/src/unix/arm.rs rename to crates/fiber/src/stackswitch/arm.rs diff --git a/crates/fiber/src/unix/riscv64.rs b/crates/fiber/src/stackswitch/riscv64.rs similarity index 100% rename from crates/fiber/src/unix/riscv64.rs rename to crates/fiber/src/stackswitch/riscv64.rs diff --git a/crates/fiber/src/unix/s390x.S b/crates/fiber/src/stackswitch/s390x.S similarity index 100% rename from crates/fiber/src/unix/s390x.S rename to crates/fiber/src/stackswitch/s390x.S diff --git a/crates/fiber/src/unix/x86.rs b/crates/fiber/src/stackswitch/x86.rs similarity index 100% rename from crates/fiber/src/unix/x86.rs rename to crates/fiber/src/stackswitch/x86.rs diff --git a/crates/fiber/src/unix/x86_64.rs b/crates/fiber/src/stackswitch/x86_64.rs similarity index 100% rename from crates/fiber/src/unix/x86_64.rs rename to crates/fiber/src/stackswitch/x86_64.rs diff --git a/crates/fiber/src/unix.rs b/crates/fiber/src/unix.rs index 65d6c78d5cff..a3e8dd6b7f6a 100644 --- a/crates/fiber/src/unix.rs +++ b/crates/fiber/src/unix.rs @@ -29,12 +29,16 @@ //! `suspend`, which has 0xB000 so it can find this, will read that and write //! its own resumption information into this slot as well. +use crate::stackswitch::*; use crate::{RunResult, RuntimeFiberStack}; +use std::boxed::Box; use std::cell::Cell; use std::io; use std::ops::Range; use std::ptr; +pub type Error = io::Error; + pub struct FiberStack { base: BasePtr, len: usize, @@ -192,20 +196,6 @@ pub struct Suspend { previous: asan::PreviousStack, } -extern "C" { - #[wasmtime_versioned_export_macros::versioned_link] - fn wasmtime_fiber_init( - top_of_stack: *mut u8, - entry: extern "C" fn(*mut u8, *mut u8), - entry_arg0: *mut u8, - ); - #[wasmtime_versioned_export_macros::versioned_link] - fn wasmtime_fiber_switch(top_of_stack: *mut u8); - #[allow(dead_code, reason = "only used on some platforms for inline asm")] - #[wasmtime_versioned_export_macros::versioned_link] - fn wasmtime_fiber_start(); -} - extern "C" fn fiber_start(arg0: *mut u8, top_of_stack: *mut u8) where F: FnOnce(A, &mut super::Suspend) -> C, @@ -288,25 +278,6 @@ impl Suspend { } } -cfg_if::cfg_if! { - if #[cfg(target_arch = "aarch64")] { - mod aarch64; - } else if #[cfg(target_arch = "x86_64")] { - mod x86_64; - } else if #[cfg(target_arch = "x86")] { - mod x86; - } else if #[cfg(target_arch = "arm")] { - mod arm; - } else if #[cfg(target_arch = "s390x")] { - // currently `global_asm!` isn't stable on s390x so this is an external - // assembler file built with the `build.rs`. - } else if #[cfg(target_arch = "riscv64")] { - mod riscv64; - } else { - compile_error!("fibers are not supported on this CPU architecture"); - } -} - /// Support for AddressSanitizer to support stack manipulations we do in this /// fiber implementation. /// @@ -320,6 +291,8 @@ cfg_if::cfg_if! { #[cfg(asan)] mod asan { use super::{FiberStack, MmapFiberStack, RuntimeFiberStack}; + use alloc::boxed::Box; + use alloc::vec::Vec; use rustix::param::page_size; use std::mem::ManuallyDrop; use std::ops::Range; @@ -481,6 +454,7 @@ mod asan { #[cfg(not(asan))] mod asan_disabled { use super::{FiberStack, RuntimeFiberStack}; + use std::boxed::Box; #[derive(Default)] pub struct PreviousStack; diff --git a/crates/fiber/src/windows.rs b/crates/fiber/src/windows.rs index 16203bd5c926..2ce5f8464cc0 100644 --- a/crates/fiber/src/windows.rs +++ b/crates/fiber/src/windows.rs @@ -1,4 +1,5 @@ use crate::{RunResult, RuntimeFiberStack}; +use alloc::boxed::Box; use std::cell::Cell; use std::ffi::c_void; use std::io; @@ -7,6 +8,8 @@ use std::ptr; use windows_sys::Win32::Foundation::*; use windows_sys::Win32::System::Threading::*; +pub type Error = io::Error; + #[derive(Debug)] pub struct FiberStack(usize); diff --git a/crates/test-programs/src/bin/http_outbound_request_large_post.rs b/crates/test-programs/src/bin/http_outbound_request_large_post.rs index 4e07493694a6..2f66daae7710 100644 --- a/crates/test-programs/src/bin/http_outbound_request_large_post.rs +++ b/crates/test-programs/src/bin/http_outbound_request_large_post.rs @@ -3,8 +3,11 @@ use std::io::{self, Read}; use test_programs::wasi::http::types::{Method, Scheme}; fn main() { - // TODO: ensure more than 700 bytes is allowed without error - const LEN: usize = 700; + // Make sure the final body is larger than 1024*1024, but we cannot allocate + // so much memory directly in the wasm program, so we use the `repeat` + // method to increase the body size. + const LEN: usize = 1024; + const REPEAT: usize = 1025; let mut buffer = [0; LEN]; let addr = std::env::var("HTTP_SERVER").unwrap(); io::repeat(0b001).read_exact(&mut buffer).unwrap(); @@ -13,7 +16,7 @@ fn main() { Scheme::Http, &addr, "/post", - Some(&buffer), + Some(&buffer.repeat(REPEAT)), None, None, None, @@ -26,5 +29,5 @@ fn main() { assert_eq!(res.status, 200); let method = res.header("x-wasmtime-test-method").unwrap(); assert_eq!(std::str::from_utf8(method).unwrap(), "POST"); - assert_eq!(res.body.len(), LEN); + assert_eq!(res.body.len(), LEN * REPEAT); } diff --git a/crates/test-programs/src/http.rs b/crates/test-programs/src/http.rs index cde88cb621d6..b2272699f6f2 100644 --- a/crates/test-programs/src/http.rs +++ b/crates/test-programs/src/http.rs @@ -74,6 +74,20 @@ pub fn request( .body() .map_err(|_| anyhow!("outgoing request write failed"))?; + let options = http_types::RequestOptions::new(); + options + .set_connect_timeout(connect_timeout) + .map_err(|()| anyhow!("failed to set connect_timeout"))?; + options + .set_first_byte_timeout(first_by_timeout) + .map_err(|()| anyhow!("failed to set first_byte_timeout"))?; + options + .set_between_bytes_timeout(between_bytes_timeout) + .map_err(|()| anyhow!("failed to set between_bytes_timeout"))?; + let options = Some(options); + + let future_response = outgoing_handler::handle(request, options)?; + if let Some(mut buf) = body { let request_body = outgoing_body .write() @@ -110,21 +124,6 @@ pub fn request( Err(_) => anyhow::bail!("output stream error"), }; } - - let options = http_types::RequestOptions::new(); - options - .set_connect_timeout(connect_timeout) - .map_err(|()| anyhow!("failed to set connect_timeout"))?; - options - .set_first_byte_timeout(first_by_timeout) - .map_err(|()| anyhow!("failed to set first_byte_timeout"))?; - options - .set_between_bytes_timeout(between_bytes_timeout) - .map_err(|()| anyhow!("failed to set between_bytes_timeout"))?; - let options = Some(options); - - let future_response = outgoing_handler::handle(request, options)?; - http_types::OutgoingBody::finish(outgoing_body, None)?; let incoming_response = match future_response.get() { diff --git a/crates/wasi-http/src/body.rs b/crates/wasi-http/src/body.rs index 5913a4922df9..96c783964746 100644 --- a/crates/wasi-http/src/body.rs +++ b/crates/wasi-http/src/body.rs @@ -423,7 +423,14 @@ pub struct HostOutgoingBody { impl HostOutgoingBody { /// Create a new `HostOutgoingBody` - pub fn new(context: StreamContext, size: Option) -> (Self, HyperOutgoingBody) { + pub fn new( + context: StreamContext, + size: Option, + buffer_chunks: usize, + chunk_size: usize, + ) -> (Self, HyperOutgoingBody) { + assert!(buffer_chunks >= 1); + let written = size.map(WrittenState::new); use tokio::sync::oneshot::error::RecvError; @@ -469,7 +476,8 @@ impl HostOutgoingBody { } } - let (body_sender, body_receiver) = mpsc::channel(2); + // always add 1 buffer here because one empty slot is required + let (body_sender, body_receiver) = mpsc::channel(buffer_chunks + 1); let (finish_sender, finish_receiver) = oneshot::channel(); let body_impl = BodyImpl { body_receiver, @@ -477,9 +485,7 @@ impl HostOutgoingBody { } .boxed(); - // TODO: this capacity constant is arbitrary, and should be configurable - let output_stream = - BodyWriteStream::new(context, 1024 * 1024, body_sender, written.clone()); + let output_stream = BodyWriteStream::new(context, chunk_size, body_sender, written.clone()); ( Self { diff --git a/crates/wasi-http/src/types.rs b/crates/wasi-http/src/types.rs index 4821e65c2ee7..912c72513b0e 100644 --- a/crates/wasi-http/src/types.rs +++ b/crates/wasi-http/src/types.rs @@ -125,6 +125,19 @@ pub trait WasiHttpView: Send { fn is_forbidden_header(&mut self, _name: &HeaderName) -> bool { false } + + /// Number of distinct write calls to the outgoing body's output-stream + /// that the implementation will buffer. + /// Default: 1. + fn outgoing_body_buffer_chunks(&mut self) -> usize { + 1 + } + + /// Maximum size allowed in a write call to the outgoing body's output-stream. + /// Default: 1024 * 1024. + fn outgoing_body_chunk_size(&mut self) -> usize { + 1024 * 1024 + } } impl WasiHttpView for &mut T { @@ -156,6 +169,14 @@ impl WasiHttpView for &mut T { fn is_forbidden_header(&mut self, name: &HeaderName) -> bool { T::is_forbidden_header(self, name) } + + fn outgoing_body_buffer_chunks(&mut self) -> usize { + T::outgoing_body_buffer_chunks(self) + } + + fn outgoing_body_chunk_size(&mut self) -> usize { + T::outgoing_body_chunk_size(self) + } } impl WasiHttpView for Box { @@ -187,6 +208,14 @@ impl WasiHttpView for Box { fn is_forbidden_header(&mut self, name: &HeaderName) -> bool { T::is_forbidden_header(self, name) } + + fn outgoing_body_buffer_chunks(&mut self) -> usize { + T::outgoing_body_buffer_chunks(self) + } + + fn outgoing_body_chunk_size(&mut self) -> usize { + T::outgoing_body_chunk_size(self) + } } /// A concrete structure that all generated `Host` traits are implemented for. @@ -233,6 +262,14 @@ impl WasiHttpView for WasiHttpImpl { fn is_forbidden_header(&mut self, name: &HeaderName) -> bool { self.0.is_forbidden_header(name) } + + fn outgoing_body_buffer_chunks(&mut self) -> usize { + self.0.outgoing_body_buffer_chunks() + } + + fn outgoing_body_chunk_size(&mut self) -> usize { + self.0.outgoing_body_chunk_size() + } } /// Returns `true` when the header is forbidden according to this [`WasiHttpView`] implementation. diff --git a/crates/wasi-http/src/types_impl.rs b/crates/wasi-http/src/types_impl.rs index 2b6b5c15b04e..337c1a3c76f7 100644 --- a/crates/wasi-http/src/types_impl.rs +++ b/crates/wasi-http/src/types_impl.rs @@ -391,6 +391,8 @@ where &mut self, request: Resource, ) -> wasmtime::Result, ()>> { + let buffer_chunks = self.outgoing_body_buffer_chunks(); + let chunk_size = self.outgoing_body_chunk_size(); let req = self .table() .get_mut(&request) @@ -405,7 +407,8 @@ where Err(e) => return Ok(Err(e)), }; - let (host_body, hyper_body) = HostOutgoingBody::new(StreamContext::Request, size); + let (host_body, hyper_body) = + HostOutgoingBody::new(StreamContext::Request, size, buffer_chunks, chunk_size); req.body = Some(hyper_body); @@ -751,6 +754,8 @@ where &mut self, id: Resource, ) -> wasmtime::Result, ()>> { + let buffer_chunks = self.outgoing_body_buffer_chunks(); + let chunk_size = self.outgoing_body_chunk_size(); let resp = self.table().get_mut(&id)?; if resp.body.is_some() { @@ -762,7 +767,8 @@ where Err(e) => return Ok(Err(e)), }; - let (host, body) = HostOutgoingBody::new(StreamContext::Response, size); + let (host, body) = + HostOutgoingBody::new(StreamContext::Response, size, buffer_chunks, chunk_size); resp.body.replace(body); diff --git a/crates/wasi-keyvalue/tests/main.rs b/crates/wasi-keyvalue/tests/main.rs index b84e9b059ad0..6ae8eee18a56 100644 --- a/crates/wasi-keyvalue/tests/main.rs +++ b/crates/wasi-keyvalue/tests/main.rs @@ -1,5 +1,3 @@ -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] - use anyhow::{anyhow, Result}; use test_programs_artifacts::{foreach_keyvalue, KEYVALUE_MAIN_COMPONENT}; use wasmtime::{ @@ -48,7 +46,7 @@ async fn run_wasi(path: &str, ctx: Ctx) -> Result<()> { macro_rules! assert_test_exists { ($name:ident) => { - #[allow(unused_imports)] + #[expect(unused_imports, reason = "just here to assert it exists")] use self::$name as _; }; } diff --git a/crates/wasi-nn/tests/check/mod.rs b/crates/wasi-nn/tests/check/mod.rs index ff21fee38d4d..32e175cdff7a 100644 --- a/crates/wasi-nn/tests/check/mod.rs +++ b/crates/wasi-nn/tests/check/mod.rs @@ -4,10 +4,6 @@ //! - that various backends can be located on the system (see sub-modules) //! - that certain ML model artifacts can be downloaded and cached. -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] - -#[allow(unused_imports)] -use anyhow::{anyhow, Context, Result}; use std::{ env, path::{Path, PathBuf}, @@ -15,7 +11,7 @@ use std::{ sync::Mutex, }; -#[cfg(any(feature = "onnx", feature = "winml"))] +#[cfg(any(feature = "onnx", all(feature = "winml", target_os = "windows")))] pub mod onnx; #[cfg(feature = "openvino")] pub mod openvino; diff --git a/crates/wasi-nn/tests/check/onnx.rs b/crates/wasi-nn/tests/check/onnx.rs index b5a451e0373f..cdbec420de22 100644 --- a/crates/wasi-nn/tests/check/onnx.rs +++ b/crates/wasi-nn/tests/check/onnx.rs @@ -1,8 +1,5 @@ -#![allow(unused)] - use super::{artifacts_dir, download, DOWNLOAD_LOCK}; use anyhow::{Context, Result}; -use std::sync::Mutex; use std::{env, fs}; /// Return `Ok` if we find the cached MobileNet test artifacts; this will diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 08f20b426556..93fca4616eda 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -186,7 +186,6 @@ async = [ "dep:async-trait", "wasmtime-component-macro?/async", "runtime", - "std", ] # Enables support for the pooling instance allocation strategy @@ -316,6 +315,7 @@ std = [ 'wasmtime-environ/std', 'object/std', 'once_cell', + 'wasmtime-fiber?/std', # technically this isn't necessary but once you have the standard library you # probably want things to go fast in which case you've probably got signal # handlers and such so implicitly enable this. This also helps reduce the diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs index 3d2cc5862747..8f4617ec18d0 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs @@ -57,7 +57,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R // a perf issue right now so doing that is left for another day's // refactoring. let obj = ElfFile64::::parse(mmap) - .err2anyhow() + .map_err(obj::ObjectCrateErrorWrapper) .context("failed to parse precompiled artifact as an ELF")?; let expected_e_flags = match expected { ObjectKind::Module => obj::EF_WASMTIME_MODULE, @@ -76,7 +76,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R .section_by_name(obj::ELF_WASM_ENGINE) .ok_or_else(|| anyhow!("failed to find section `{}`", obj::ELF_WASM_ENGINE))? .data() - .err2anyhow()?; + .map_err(obj::ObjectCrateErrorWrapper)?; let (first, data) = data .split_first() .ok_or_else(|| anyhow!("invalid engine section"))?; @@ -95,7 +95,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R match &engine.config().module_version { ModuleVersionStrategy::WasmtimeVersion => { - let version = core::str::from_utf8(version).err2anyhow()?; + let version = core::str::from_utf8(version)?; if version != env!("CARGO_PKG_VERSION") { bail!( "Module was compiled with incompatible Wasmtime version '{}'", @@ -104,7 +104,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R } } ModuleVersionStrategy::Custom(v) => { - let version = core::str::from_utf8(&version).err2anyhow()?; + let version = core::str::from_utf8(&version)?; if version != v { bail!( "Module was compiled with incompatible version '{}'", @@ -114,9 +114,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R } ModuleVersionStrategy::None => { /* ignore the version info, accept all */ } } - postcard::from_bytes::>(data) - .err2anyhow()? - .check_compatible(engine) + postcard::from_bytes::>(data)?.check_compatible(engine) } #[cfg(any(feature = "cranelift", feature = "winch"))] diff --git a/crates/wasmtime/src/runtime/code_memory.rs b/crates/wasmtime/src/runtime/code_memory.rs index b1eb98caef7a..8ad04f789b71 100644 --- a/crates/wasmtime/src/runtime/code_memory.rs +++ b/crates/wasmtime/src/runtime/code_memory.rs @@ -58,7 +58,7 @@ impl CodeMemory { /// `publish` method is used to actually make the memory executable. pub fn new(mmap: MmapVec) -> Result { let obj = ElfFile64::::parse(&mmap[..]) - .err2anyhow() + .map_err(obj::ObjectCrateErrorWrapper) .with_context(|| "failed to parse internal compilation artifact")?; let mut relocations = Vec::new(); @@ -75,8 +75,8 @@ impl CodeMemory { let mut info_data = 0..0; let mut wasm_dwarf = 0..0; for section in obj.sections() { - let data = section.data().err2anyhow()?; - let name = section.name().err2anyhow()?; + let data = section.data().map_err(obj::ObjectCrateErrorWrapper)?; + let name = section.name().map_err(obj::ObjectCrateErrorWrapper)?; let range = subslice_range(data, &mmap); // Double-check that sections are all aligned properly. diff --git a/crates/wasmtime/src/runtime/component/component.rs b/crates/wasmtime/src/runtime/component/component.rs index c32f319bdfb4..10af60dc94ec 100644 --- a/crates/wasmtime/src/runtime/component/component.rs +++ b/crates/wasmtime/src/runtime/component/component.rs @@ -388,7 +388,7 @@ impl Component { static_modules, } = match artifacts { Some(artifacts) => artifacts, - None => postcard::from_bytes(code_memory.wasmtime_info()).err2anyhow()?, + None => postcard::from_bytes(code_memory.wasmtime_info())?, }; // Validate that the component can be used with the current instance diff --git a/crates/wasmtime/src/runtime/component/func.rs b/crates/wasmtime/src/runtime/component/func.rs index 6643f6ecef7b..9ac5329af7ce 100644 --- a/crates/wasmtime/src/runtime/component/func.rs +++ b/crates/wasmtime/src/runtime/component/func.rs @@ -669,8 +669,8 @@ impl Func { src: &mut core::slice::Iter<'_, ValRaw>, ) -> Result<()> { // FIXME: needs to read an i64 for memory64 - let ptr = usize::try_from(src.next().unwrap().get_u32()).err2anyhow()?; - if ptr % usize::try_from(results_ty.abi.align32).err2anyhow()? != 0 { + let ptr = usize::try_from(src.next().unwrap().get_u32())?; + if ptr % usize::try_from(results_ty.abi.align32)? != 0 { bail!("return pointer not aligned"); } diff --git a/crates/wasmtime/src/runtime/component/func/host.rs b/crates/wasmtime/src/runtime/component/func/host.rs index f53df1b6b6f6..d55ac2ce5237 100644 --- a/crates/wasmtime/src/runtime/component/func/host.rs +++ b/crates/wasmtime/src/runtime/component/func/host.rs @@ -275,8 +275,8 @@ where fn validate_inbounds(memory: &[u8], ptr: &ValRaw) -> Result { // FIXME: needs memory64 support - let ptr = usize::try_from(ptr.get_u32()).err2anyhow()?; - if ptr % usize::try_from(T::ALIGN32).err2anyhow()? != 0 { + let ptr = usize::try_from(ptr.get_u32())?; + if ptr % usize::try_from(T::ALIGN32)? != 0 { bail!("pointer not aligned"); } let end = match ptr.checked_add(T::SIZE32) { @@ -407,8 +407,8 @@ where fn validate_inbounds_dynamic(abi: &CanonicalAbiInfo, memory: &[u8], ptr: &ValRaw) -> Result { // FIXME: needs memory64 support - let ptr = usize::try_from(ptr.get_u32()).err2anyhow()?; - if ptr % usize::try_from(abi.align32).err2anyhow()? != 0 { + let ptr = usize::try_from(ptr.get_u32())?; + if ptr % usize::try_from(abi.align32)? != 0 { bail!("pointer not aligned"); } let end = match ptr.checked_add(usize::try_from(abi.size32).unwrap()) { diff --git a/crates/wasmtime/src/runtime/component/func/options.rs b/crates/wasmtime/src/runtime/component/func/options.rs index 83accf3dee97..cd0482965e21 100644 --- a/crates/wasmtime/src/runtime/component/func/options.rs +++ b/crates/wasmtime/src/runtime/component/func/options.rs @@ -89,10 +89,10 @@ impl Options { let realloc = self.realloc.unwrap(); let params = ( - u32::try_from(old).err2anyhow()?, - u32::try_from(old_size).err2anyhow()?, + u32::try_from(old)?, + u32::try_from(old_size)?, old_align, - u32::try_from(new_size).err2anyhow()?, + u32::try_from(new_size)?, ); type ReallocFunc = crate::TypedFunc<(u32, u32, u32, u32), u32>; @@ -108,7 +108,7 @@ impl Options { if result % old_align != 0 { bail!("realloc return: result not aligned"); } - let result = usize::try_from(result).err2anyhow()?; + let result = usize::try_from(result)?; let memory = self.memory_mut(store.0); diff --git a/crates/wasmtime/src/runtime/component/func/typed.rs b/crates/wasmtime/src/runtime/component/func/typed.rs index a2ab99c55ba8..4dd5050e000d 100644 --- a/crates/wasmtime/src/runtime/component/func/typed.rs +++ b/crates/wasmtime/src/runtime/component/func/typed.rs @@ -315,8 +315,8 @@ where ) -> Result { assert!(Return::flatten_count() > MAX_FLAT_RESULTS); // FIXME: needs to read an i64 for memory64 - let ptr = usize::try_from(dst.get_u32()).err2anyhow()?; - if ptr % usize::try_from(Return::ALIGN32).err2anyhow()? != 0 { + let ptr = usize::try_from(dst.get_u32())?; + if ptr % usize::try_from(Return::ALIGN32)? != 0 { bail!("return pointer not aligned"); } @@ -1053,7 +1053,7 @@ unsafe impl Lift for char { #[inline] fn lift(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result { debug_assert!(matches!(ty, InterfaceType::Char)); - Ok(char::try_from(src.get_u32()).err2anyhow()?) + Ok(char::try_from(src.get_u32())?) } #[inline] @@ -1061,7 +1061,7 @@ unsafe impl Lift for char { debug_assert!(matches!(ty, InterfaceType::Char)); debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0); let bits = u32::from_le_bytes(bytes.try_into().unwrap()); - Ok(char::try_from(bits).err2anyhow()?) + Ok(char::try_from(bits)?) } } @@ -1337,9 +1337,7 @@ impl WasmStr { // Note that bounds-checking already happen in construction of `WasmStr` // so this is never expected to panic. This could theoretically be // unchecked indexing if we're feeling wild enough. - Ok(str::from_utf8(&memory[self.ptr..][..self.len]) - .err2anyhow()? - .into()) + Ok(str::from_utf8(&memory[self.ptr..][..self.len])?.into()) } fn decode_utf16<'a>(&self, memory: &'a [u8], len: usize) -> Result> { @@ -1350,8 +1348,7 @@ impl WasmStr { .chunks(2) .map(|chunk| u16::from_le_bytes(chunk.try_into().unwrap())), ) - .collect::>() - .err2anyhow()? + .collect::>()? .into()) } @@ -1385,10 +1382,7 @@ unsafe impl Lift for WasmStr { // FIXME: needs memory64 treatment let ptr = src[0].get_u32(); let len = src[1].get_u32(); - let (ptr, len) = ( - usize::try_from(ptr).err2anyhow()?, - usize::try_from(len).err2anyhow()?, - ); + let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); WasmStr::new(ptr, len, cx) } @@ -1399,10 +1393,7 @@ unsafe impl Lift for WasmStr { // FIXME: needs memory64 treatment let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); - let (ptr, len) = ( - usize::try_from(ptr).err2anyhow()?, - usize::try_from(len).err2anyhow()?, - ); + let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); WasmStr::new(ptr, len, cx) } } @@ -1539,7 +1530,7 @@ impl WasmList { Some(n) if n <= cx.memory().len() => {} _ => bail!("list pointer/length out of bounds of memory"), } - if ptr % usize::try_from(T::ALIGN32).err2anyhow()? != 0 { + if ptr % usize::try_from(T::ALIGN32)? != 0 { bail!("list pointer is not aligned") } Ok(WasmList { @@ -1695,10 +1686,7 @@ unsafe impl Lift for WasmList { // FIXME: needs memory64 treatment let ptr = src[0].get_u32(); let len = src[1].get_u32(); - let (ptr, len) = ( - usize::try_from(ptr).err2anyhow()?, - usize::try_from(len).err2anyhow()?, - ); + let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); WasmList::new(ptr, len, cx, elem) } @@ -1711,10 +1699,7 @@ unsafe impl Lift for WasmList { // FIXME: needs memory64 treatment let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); - let (ptr, len) = ( - usize::try_from(ptr).err2anyhow()?, - usize::try_from(len).err2anyhow()?, - ); + let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); WasmList::new(ptr, len, cx, elem) } } diff --git a/crates/wasmtime/src/runtime/component/values.rs b/crates/wasmtime/src/runtime/component/values.rs index 423158c0047d..15d99847897d 100644 --- a/crates/wasmtime/src/runtime/component/values.rs +++ b/crates/wasmtime/src/runtime/component/values.rs @@ -439,9 +439,7 @@ impl Val { ty: InterfaceType, offset: usize, ) -> Result<()> { - debug_assert!( - offset % usize::try_from(cx.types.canonical_abi(&ty).align32).err2anyhow()? == 0 - ); + debug_assert!(offset % usize::try_from(cx.types.canonical_abi(&ty).align32)? == 0); match (ty, self) { (InterfaceType::Bool, Val::Bool(value)) => value.store(cx, ty, offset), @@ -832,7 +830,7 @@ fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize Some(n) if n <= cx.memory().len() => {} _ => bail!("list pointer/length out of bounds of memory"), } - if ptr % usize::try_from(element_alignment).err2anyhow()? != 0 { + if ptr % usize::try_from(element_alignment)? != 0 { bail!("list pointer is not aligned") } @@ -914,7 +912,7 @@ fn lower_list( items: &[Val], ) -> Result<(usize, usize)> { let abi = cx.types.canonical_abi(&element_type); - let elt_size = usize::try_from(abi.size32).err2anyhow()?; + let elt_size = usize::try_from(abi.size32)?; let elt_align = abi.align32; let size = items .len() diff --git a/crates/wasmtime/src/runtime/debug.rs b/crates/wasmtime/src/runtime/debug.rs index 6636e19b56e0..1fa4d430b88d 100644 --- a/crates/wasmtime/src/runtime/debug.rs +++ b/crates/wasmtime/src/runtime/debug.rs @@ -7,6 +7,7 @@ use object::{ File, NativeEndian as NE, Object, ObjectSection, ObjectSymbol, RelocationEncoding, RelocationKind, RelocationTarget, U64Bytes, }; +use wasmtime_environ::obj; pub(crate) fn create_gdbjit_image( mut bytes: Vec, @@ -32,7 +33,7 @@ pub(crate) fn create_gdbjit_image( fn relocate_dwarf_sections(bytes: &mut [u8], code_region: (*const u8, usize)) -> Result<(), Error> { let mut relocations = Vec::new(); - let obj = File::parse(&bytes[..]).err2anyhow()?; + let obj = File::parse(&bytes[..]).map_err(obj::ObjectCrateErrorWrapper)?; for section in obj.sections() { let section_start = match section.file_range() { Some((start, _)) => start, diff --git a/crates/wasmtime/src/runtime/externals/table.rs b/crates/wasmtime/src/runtime/externals/table.rs index 0a9f5b07f739..6a38611032c8 100644 --- a/crates/wasmtime/src/runtime/externals/table.rs +++ b/crates/wasmtime/src/runtime/externals/table.rs @@ -111,9 +111,7 @@ impl Table { unsafe { let table = Table::from_wasmtime_table(wasmtime_export, store); let wasmtime_table = table.wasmtime_table(store, iter::empty()); - (*wasmtime_table) - .fill(store.optional_gc_store_mut()?, 0, init, ty.minimum()) - .err2anyhow()?; + (*wasmtime_table).fill(store.optional_gc_store_mut()?, 0, init, ty.minimum())?; Ok(table) } } @@ -346,8 +344,7 @@ impl Table { dst_index, src_index, len, - ) - .err2anyhow()?; + )?; } Ok(()) } @@ -375,9 +372,7 @@ impl Table { let table = self.wasmtime_table(store, iter::empty()); unsafe { - (*table) - .fill(store.optional_gc_store_mut()?, dst, val, len) - .err2anyhow()?; + (*table).fill(store.optional_gc_store_mut()?, dst, val, len)?; } Ok(()) diff --git a/crates/wasmtime/src/runtime/gc.rs b/crates/wasmtime/src/runtime/gc.rs index bcce10e76f62..6c972e287c8d 100644 --- a/crates/wasmtime/src/runtime/gc.rs +++ b/crates/wasmtime/src/runtime/gc.rs @@ -80,8 +80,7 @@ impl fmt::Display for GcHeapOutOfMemory { } } -#[cfg(feature = "std")] -impl std::error::Error for GcHeapOutOfMemory {} +impl core::error::Error for GcHeapOutOfMemory {} impl GcHeapOutOfMemory { pub(crate) fn new(inner: T) -> Self { diff --git a/crates/wasmtime/src/runtime/gc/enabled/arrayref.rs b/crates/wasmtime/src/runtime/gc/enabled/arrayref.rs index a8abc6b9f534..ed1347e17976 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/arrayref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/arrayref.rs @@ -321,10 +321,8 @@ impl ArrayRef { let arrayref = store .gc_store_mut()? .alloc_uninit_array(allocator.type_index(), len, allocator.layout()) - .err2anyhow() .context("unrecoverable error when allocating new `arrayref`")? - .ok_or_else(|| GcHeapOutOfMemory::new(())) - .err2anyhow()?; + .ok_or_else(|| GcHeapOutOfMemory::new(()))?; // From this point on, if we get any errors, then the array is not // fully initialized, so we need to eagerly deallocate it before the diff --git a/crates/wasmtime/src/runtime/gc/enabled/externref.rs b/crates/wasmtime/src/runtime/gc/enabled/externref.rs index 3db2fc5dbdd4..995477f2fa73 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/externref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/externref.rs @@ -209,10 +209,8 @@ impl ExternRef { let gc_ref = ctx .gc_store_mut()? .alloc_externref(value) - .err2anyhow() .context("unrecoverable error when allocating new `externref`")? .map_err(|x| GcHeapOutOfMemory::::new(*x.downcast().unwrap())) - .err2anyhow() .context("failed to allocate `externref`")?; let mut ctx = AutoAssertNoGc::new(ctx); @@ -320,10 +318,8 @@ impl ExternRef { let gc_ref = ctx .gc_store_mut()? .alloc_externref(value) - .err2anyhow() .context("unrecoverable error when allocating new `externref`")? .map_err(|x| GcHeapOutOfMemory::::new(*x.downcast().unwrap())) - .err2anyhow() .context("failed to allocate `externref`")?; let mut ctx = AutoAssertNoGc::new(ctx); diff --git a/crates/wasmtime/src/runtime/gc/enabled/structref.rs b/crates/wasmtime/src/runtime/gc/enabled/structref.rs index a138c13f081d..eb9233b00b15 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/structref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/structref.rs @@ -269,10 +269,8 @@ impl StructRef { let structref = store .gc_store_mut()? .alloc_uninit_struct(allocator.type_index(), &allocator.layout()) - .err2anyhow() .context("unrecoverable error when allocating new `structref`")? - .ok_or_else(|| GcHeapOutOfMemory::new(())) - .err2anyhow()?; + .ok_or_else(|| GcHeapOutOfMemory::new(()))?; // From this point on, if we get any errors, then the struct is not // fully initialized, so we need to eagerly deallocate it before the diff --git a/crates/wasmtime/src/runtime/linker.rs b/crates/wasmtime/src/runtime/linker.rs index 6af98396e28a..19e1e1bcf6e3 100644 --- a/crates/wasmtime/src/runtime/linker.rs +++ b/crates/wasmtime/src/runtime/linker.rs @@ -1200,8 +1200,7 @@ impl Linker { let mut imports = module .imports() .map(|import| self._get_by_import(&import)) - .collect::, _>>() - .err2anyhow()?; + .collect::, _>>()?; if let Some(store) = store { for import in imports.iter_mut() { import.update_size(store); @@ -1497,5 +1496,4 @@ impl fmt::Display for UnknownImportError { } } -#[cfg(feature = "std")] -impl std::error::Error for UnknownImportError {} +impl core::error::Error for UnknownImportError {} diff --git a/crates/wasmtime/src/runtime/module.rs b/crates/wasmtime/src/runtime/module.rs index 92450efd5944..9f2c99a540b9 100644 --- a/crates/wasmtime/src/runtime/module.rs +++ b/crates/wasmtime/src/runtime/module.rs @@ -476,7 +476,7 @@ impl Module { // already. let (info, types) = match info_and_types { Some((info, types)) => (info, types), - None => postcard::from_bytes(code_memory.wasmtime_info()).err2anyhow()?, + None => postcard::from_bytes(code_memory.wasmtime_info())?, }; // Register function type signatures into the engine for the lifetime @@ -546,8 +546,8 @@ impl Module { let mut functions = Vec::new(); for payload in Parser::new(0).parse_all(binary) { - let payload = payload.err2anyhow()?; - if let ValidPayload::Func(a, b) = validator.payload(&payload).err2anyhow()? { + let payload = payload?; + if let ValidPayload::Func(a, b) = validator.payload(&payload)? { functions.push((a, b)); } if let wasmparser::Payload::Version { encoding, .. } = &payload { @@ -557,15 +557,13 @@ impl Module { } } - engine - .run_maybe_parallel(functions, |(validator, body)| { - // FIXME: it would be best here to use a rayon-specific parallel - // iterator that maintains state-per-thread to share the function - // validator allocations (`Default::default` here) across multiple - // functions. - validator.into_validator(Default::default()).validate(&body) - }) - .err2anyhow()?; + engine.run_maybe_parallel(functions, |(validator, body)| { + // FIXME: it would be best here to use a rayon-specific parallel + // iterator that maintains state-per-thread to share the function + // validator allocations (`Default::default` here) across multiple + // functions. + validator.into_validator(Default::default()).validate(&body) + })?; Ok(()) } diff --git a/crates/wasmtime/src/runtime/stack.rs b/crates/wasmtime/src/runtime/stack.rs index 94f5732ec40f..458558525c73 100644 --- a/crates/wasmtime/src/runtime/stack.rs +++ b/crates/wasmtime/src/runtime/stack.rs @@ -1,5 +1,6 @@ use crate::prelude::*; -use std::{ops::Range, sync::Arc}; +use alloc::sync::Arc; +use core::ops::Range; use wasmtime_fiber::{RuntimeFiberStack, RuntimeFiberStackCreator}; /// A stack creator. Can be used to provide a stack creator to wasmtime diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs index c030d63b94d9..f6a794912e1f 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs @@ -2676,7 +2676,7 @@ unsafe impl crate::runtime::vm::VMStore for StoreInner { fn out_of_gas(&mut self) -> Result<()> { if !self.refuel() { - return Err(Trap::OutOfFuel).err2anyhow(); + return Err(Trap::OutOfFuel.into()); } #[cfg(feature = "async")] if self.fuel_yield_interval.is_some() { @@ -2690,7 +2690,7 @@ unsafe impl crate::runtime::vm::VMStore for StoreInner { // multiple times. let mut behavior = self.epoch_deadline_behavior.take(); let delta_result = match &mut behavior { - None => Err(Trap::Interrupt).err2anyhow(), + None => Err(Trap::Interrupt.into()), Some(callback) => callback((&mut *self).as_context_mut()).and_then(|update| { let delta = match update { UpdateDeadline::Continue(delta) => delta, diff --git a/crates/wasmtime/src/runtime/trap.rs b/crates/wasmtime/src/runtime/trap.rs index 608f055756f6..358a96519abb 100644 --- a/crates/wasmtime/src/runtime/trap.rs +++ b/crates/wasmtime/src/runtime/trap.rs @@ -99,7 +99,7 @@ pub(crate) fn from_runtime_box( faulting_addr, trap, } => { - let mut err: Error = trap.into_anyhow(); + let mut err: Error = trap.into(); // If a fault address was present, for example with segfaults, // then simultaneously assert that it's within a known linear memory @@ -110,7 +110,7 @@ pub(crate) fn from_runtime_box( } (err, Some(pc)) } - crate::runtime::vm::TrapReason::Wasm(trap_code) => (trap_code.into_anyhow(), None), + crate::runtime::vm::TrapReason::Wasm(trap_code) => (trap_code.into(), None), }; if let Some(bt) = backtrace { diff --git a/crates/wasmtime/src/runtime/type_registry.rs b/crates/wasmtime/src/runtime/type_registry.rs index d850951271cd..3b908dcf1131 100644 --- a/crates/wasmtime/src/runtime/type_registry.rs +++ b/crates/wasmtime/src/runtime/type_registry.rs @@ -1236,11 +1236,16 @@ impl TypeRegistry { } /// Is type `sub` a subtype of `sup`? + #[inline] pub fn is_subtype(&self, sub: VMSharedTypeIndex, sup: VMSharedTypeIndex) -> bool { if sub == sup { return true; } + self.is_subtype_slow(sub, sup) + } + + fn is_subtype_slow(&self, sub: VMSharedTypeIndex, sup: VMSharedTypeIndex) -> bool { // Do the O(1) subtype checking trick: // // In a type system with single inheritance, the subtyping relationships diff --git a/crates/wasmtime/src/runtime/types.rs b/crates/wasmtime/src/runtime/types.rs index ebf21dd98e1d..7389aab99f05 100644 --- a/crates/wasmtime/src/runtime/types.rs +++ b/crates/wasmtime/src/runtime/types.rs @@ -1510,7 +1510,14 @@ impl StorageType { /// Panics if either type is associated with a different engine from the /// other. pub fn eq(a: &Self, b: &Self) -> bool { - a.matches(b) && b.matches(a) + match (a, b) { + (StorageType::I8, StorageType::I8) => true, + (StorageType::I8, _) => false, + (StorageType::I16, StorageType::I16) => true, + (StorageType::I16, _) => false, + (StorageType::ValType(a), StorageType::ValType(b)) => ValType::eq(a, b), + (StorageType::ValType(_), _) => false, + } } pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { @@ -1605,8 +1612,21 @@ impl FieldType { /// Panics if either type is associated with a different engine from the /// other. pub fn matches(&self, other: &Self) -> bool { - (other.mutability == Mutability::Var || self.mutability == Mutability::Const) - && self.element_type.matches(&other.element_type) + // Our storage type must match `other`'s storage type and either + // + // 1. Both field types are immutable, or + // + // 2. Both field types are mutable and `other`'s storage type must match + // ours, i.e. the storage types are exactly the same. + use Mutability as M; + match (self.mutability, other.mutability) { + // Case 1 + (M::Const, M::Const) => self.element_type.matches(&other.element_type), + // Case 2 + (M::Var, M::Var) => StorageType::eq(&self.element_type, &other.element_type), + // Does not match. + _ => false, + } } /// Is field type `a` precisely equal to field type `b`? @@ -1824,13 +1844,9 @@ impl StructType { pub fn matches(&self, other: &StructType) -> bool { assert!(self.comes_from_same_engine(other.engine())); - // Avoid matching on structure for subtyping checks when we have - // precisely the same type. - if self.type_index() == other.type_index() { - return true; - } - - Self::fields_match(self.fields(), other.fields()) + self.engine() + .signatures() + .is_subtype(self.type_index(), other.type_index()) } fn fields_match( @@ -2088,13 +2104,9 @@ impl ArrayType { pub fn matches(&self, other: &ArrayType) -> bool { assert!(self.comes_from_same_engine(other.engine())); - // Avoid matching on structure for subtyping checks when we have - // precisely the same type. - if self.type_index() == other.type_index() { - return true; - } - - self.field_type().matches(&other.field_type()) + self.engine() + .signatures() + .is_subtype(self.type_index(), other.type_index()) } /// Is array type `a` precisely equal to array type `b`? @@ -2827,7 +2839,6 @@ impl MemoryTypeBuilder { let min = self .ty .minimum_byte_size() - .err2anyhow() .context("memory's minimum byte size must fit in a u64")?; if min > absolute_max { bail!("minimum size is too large for this memory type's index type"); diff --git a/crates/wasmtime/src/runtime/vm/byte_count.rs b/crates/wasmtime/src/runtime/vm/byte_count.rs index 4fff11a51ca3..5c963b2faad5 100644 --- a/crates/wasmtime/src/runtime/vm/byte_count.rs +++ b/crates/wasmtime/src/runtime/vm/byte_count.rs @@ -233,8 +233,7 @@ impl fmt::Display for ByteCountNotAligned { } } -#[cfg(feature = "std")] -impl std::error::Error for ByteCountNotAligned {} +impl core::error::Error for ByteCountNotAligned {} #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ByteCountOutOfBounds(ByteCountOutOfBoundsKind); @@ -245,8 +244,7 @@ impl fmt::Display for ByteCountOutOfBounds { } } -#[cfg(feature = "std")] -impl std::error::Error for ByteCountOutOfBounds {} +impl core::error::Error for ByteCountOutOfBounds {} #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum ByteCountOutOfBoundsKind { diff --git a/crates/wasmtime/src/runtime/vm/component/libcalls.rs b/crates/wasmtime/src/runtime/vm/component/libcalls.rs index 7135524bf0bf..31671f5fe6a6 100644 --- a/crates/wasmtime/src/runtime/vm/component/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/component/libcalls.rs @@ -566,5 +566,5 @@ unsafe fn resource_exit_call(vmctx: *mut VMComponentContext) -> Result<()> { } unsafe fn trap(_vmctx: *mut VMComponentContext, code: u8) -> Result<()> { - Err(wasmtime_environ::Trap::from_u8(code).unwrap()).err2anyhow() + Err(wasmtime_environ::Trap::from_u8(code).unwrap().into()) } diff --git a/crates/wasmtime/src/runtime/vm/cow.rs b/crates/wasmtime/src/runtime/vm/cow.rs index cad29faf7d77..37ba1864c140 100644 --- a/crates/wasmtime/src/runtime/vm/cow.rs +++ b/crates/wasmtime/src/runtime/vm/cow.rs @@ -119,7 +119,7 @@ impl MemoryImage { // If `mmap` doesn't come from a file then platform-specific mechanisms // may be used to place the data in a form that's amenable to an mmap. - if let Some(source) = MemoryImageSource::from_data(data).err2anyhow()? { + if let Some(source) = MemoryImageSource::from_data(data)? { return Ok(Some(MemoryImage { source, source_offset: 0, @@ -132,23 +132,19 @@ impl MemoryImage { } unsafe fn map_at(&self, base: *mut u8) -> Result<()> { - self.source - .map_at( - base.add(self.linear_memory_offset.byte_count()), - self.len.byte_count(), - self.source_offset, - ) - .err2anyhow()?; + self.source.map_at( + base.add(self.linear_memory_offset.byte_count()), + self.len.byte_count(), + self.source_offset, + )?; Ok(()) } unsafe fn remap_as_zeros_at(&self, base: *mut u8) -> Result<()> { - self.source - .remap_as_zeros_at( - base.add(self.linear_memory_offset.byte_count()), - self.len.byte_count(), - ) - .err2anyhow()?; + self.source.remap_as_zeros_at( + base.add(self.linear_memory_offset.byte_count()), + self.len.byte_count(), + )?; Ok(()) } } @@ -364,7 +360,7 @@ impl MemoryImageSlot { } pub(crate) fn set_heap_limit(&mut self, size_bytes: usize) -> Result<()> { - let size_bytes_aligned = HostAlignedByteCount::new_rounded_up(size_bytes).err2anyhow()?; + let size_bytes_aligned = HostAlignedByteCount::new_rounded_up(size_bytes)?; assert!(size_bytes <= self.static_size); assert!(size_bytes_aligned.byte_count() <= self.static_size); @@ -414,7 +410,7 @@ impl MemoryImageSlot { assert!(!self.dirty); assert!(initial_size_bytes <= self.static_size); let initial_size_bytes_page_aligned = - HostAlignedByteCount::new_rounded_up(initial_size_bytes).err2anyhow()?; + HostAlignedByteCount::new_rounded_up(initial_size_bytes)?; // First order of business is to blow away the previous linear memory // image if it doesn't match the image specified here. If one is @@ -707,9 +703,9 @@ impl MemoryImageSlot { unsafe { let start = self.base.as_ptr().add(range.start.byte_count()); if readwrite { - vm::expose_existing_mapping(start, len.byte_count()).err2anyhow()?; + vm::expose_existing_mapping(start, len.byte_count())?; } else { - vm::hide_existing_mapping(start, len.byte_count()).err2anyhow()?; + vm::hide_existing_mapping(start, len.byte_count())?; } } @@ -735,7 +731,7 @@ impl MemoryImageSlot { } unsafe { - vm::erase_existing_mapping(self.base.as_ptr(), self.static_size).err2anyhow()?; + vm::erase_existing_mapping(self.base.as_ptr(), self.static_size)?; } self.image = None; @@ -817,9 +813,33 @@ mod test { } } - fn mmap_4mib_inaccessible() -> Mmap { + fn mmap_4mib_inaccessible() -> Arc> { let four_mib = HostAlignedByteCount::new(4 << 20).expect("4 MiB is page aligned"); - Mmap::accessible_reserved(HostAlignedByteCount::ZERO, four_mib).unwrap() + Arc::new(Mmap::accessible_reserved(HostAlignedByteCount::ZERO, four_mib).unwrap()) + } + + /// Presents a part of an mmap as a mutable slice within a callback. + /// + /// The callback ensures that the reference no longer lives after the + /// function is done. + /// + /// # Safety + /// + /// The caller must ensure that during this function call, the only way this + /// region of memory is not accessed by (read from or written to) is via the + /// reference. Making the callback `'static` goes some way towards ensuring + /// that, but it's still possible to squirrel away a reference into global + /// state. So don't do that. + unsafe fn with_slice_mut( + mmap: &Arc>, + range: Range, + f: impl FnOnce(&mut [u8]) + 'static, + ) { + let ptr = mmap.as_ptr().cast_mut(); + let slice = unsafe { + core::slice::from_raw_parts_mut(ptr.add(range.start), range.end - range.start) + }; + f(slice); } #[test] @@ -830,7 +850,7 @@ mod test { ..Tunables::default_miri() }; // 4 MiB mmap'd area, not accessible - let mut mmap = mmap_4mib_inaccessible(); + let mmap = mmap_4mib_inaccessible(); // Create a MemoryImageSlot on top of it let mut memfd = MemoryImageSlot::create( mmap.as_mut_ptr() as *mut _, @@ -842,13 +862,18 @@ mod test { // instantiate with 64 KiB initial size memfd.instantiate(64 << 10, None, &ty, &tunables).unwrap(); assert!(memfd.is_dirty()); + // We should be able to access this 64 KiB (try both ends) and // it should consist of zeroes. - let slice = unsafe { mmap.slice_mut(0..65536) }; - assert_eq!(0, slice[0]); - assert_eq!(0, slice[65535]); - slice[1024] = 42; - assert_eq!(42, slice[1024]); + unsafe { + with_slice_mut(&mmap, 0..65536, |slice| { + assert_eq!(0, slice[0]); + assert_eq!(0, slice[65535]); + slice[1024] = 42; + assert_eq!(42, slice[1024]); + }); + } + // grow the heap memfd.set_heap_limit(128 << 10).unwrap(); let slice = unsafe { mmap.slice(0..1 << 20) }; @@ -876,7 +901,7 @@ mod test { ..Tunables::default_miri() }; // 4 MiB mmap'd area, not accessible - let mut mmap = mmap_4mib_inaccessible(); + let mmap = mmap_4mib_inaccessible(); // Create a MemoryImageSlot on top of it let mut memfd = MemoryImageSlot::create( mmap.as_mut_ptr() as *mut _, @@ -891,9 +916,14 @@ mod test { .instantiate(64 << 10, Some(&image), &ty, &tunables) .unwrap(); assert!(memfd.has_image()); - let slice = unsafe { mmap.slice_mut(0..65536) }; - assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); - slice[page_size] = 5; + + unsafe { + with_slice_mut(&mmap, 0..65536, move |slice| { + assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); + slice[page_size] = 5; + }); + } + // Clear and re-instantiate same image memfd .clear_and_remain_ready(HostAlignedByteCount::ZERO, |ptr, len| unsafe { @@ -903,9 +933,9 @@ mod test { memfd .instantiate(64 << 10, Some(&image), &ty, &tunables) .unwrap(); - let slice = unsafe { mmap.slice_mut(0..65536) }; - // Should not see mutation from above + let slice = unsafe { mmap.slice(0..65536) }; assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); + // Clear and re-instantiate no image memfd .clear_and_remain_ready(HostAlignedByteCount::ZERO, |ptr, len| unsafe { @@ -914,8 +944,9 @@ mod test { .unwrap(); memfd.instantiate(64 << 10, None, &ty, &tunables).unwrap(); assert!(!memfd.has_image()); - let slice = unsafe { mmap.slice_mut(0..65536) }; + let slice = unsafe { mmap.slice(0..65536) }; assert_eq!(&[0, 0, 0, 0], &slice[page_size..][..4]); + // Clear and re-instantiate image again memfd .clear_and_remain_ready(HostAlignedByteCount::ZERO, |ptr, len| unsafe { @@ -925,8 +956,9 @@ mod test { memfd .instantiate(64 << 10, Some(&image), &ty, &tunables) .unwrap(); - let slice = unsafe { mmap.slice_mut(0..65536) }; + let slice = unsafe { mmap.slice(0..65536) }; assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); + // Create another image with different data. let image2 = Arc::new(create_memfd_with_data(page_size, &[10, 11, 12, 13]).unwrap()); memfd @@ -937,8 +969,9 @@ mod test { memfd .instantiate(128 << 10, Some(&image2), &ty, &tunables) .unwrap(); - let slice = unsafe { mmap.slice_mut(0..65536) }; + let slice = unsafe { mmap.slice(0..65536) }; assert_eq!(&[10, 11, 12, 13], &slice[page_size..][..4]); + // Instantiate the original image again; we should notice it's // a different image and not reuse the mappings. memfd @@ -949,7 +982,7 @@ mod test { memfd .instantiate(64 << 10, Some(&image), &ty, &tunables) .unwrap(); - let slice = unsafe { mmap.slice_mut(0..65536) }; + let slice = unsafe { mmap.slice(0..65536) }; assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); } @@ -962,7 +995,7 @@ mod test { memory_reservation: 100 << 16, ..Tunables::default_miri() }; - let mut mmap = mmap_4mib_inaccessible(); + let mmap = mmap_4mib_inaccessible(); let mut memfd = MemoryImageSlot::create( mmap.as_mut_ptr() as *mut _, HostAlignedByteCount::ZERO, @@ -979,14 +1012,19 @@ mod test { .instantiate(64 << 10, Some(&image), &ty, &tunables) .unwrap(); assert!(memfd.has_image()); - let slice = unsafe { mmap.slice_mut(0..64 << 10) }; - if image_off > 0 { - assert_eq!(slice[image_off - 1], 0); - } - assert_eq!(slice[image_off + 5], 0); - assert_eq!(&[1, 2, 3, 4], &slice[image_off..][..4]); - slice[image_off] = 5; - assert_eq!(&[5, 2, 3, 4], &slice[image_off..][..4]); + + unsafe { + with_slice_mut(&mmap, 0..64 << 10, move |slice| { + if image_off > 0 { + assert_eq!(slice[image_off - 1], 0); + } + assert_eq!(slice[image_off + 5], 0); + assert_eq!(&[1, 2, 3, 4], &slice[image_off..][..4]); + slice[image_off] = 5; + assert_eq!(&[5, 2, 3, 4], &slice[image_off..][..4]); + }) + }; + memfd .clear_and_remain_ready(amt_to_memset, |ptr, len| unsafe { decommit_pages(ptr, len).unwrap() @@ -999,10 +1037,14 @@ mod test { for amt_to_memset in [0, page_size, page_size * 10, 1 << 20, 10 << 20] { let amt_to_memset = HostAlignedByteCount::new(amt_to_memset).unwrap(); memfd.instantiate(64 << 10, None, &ty, &tunables).unwrap(); - let mem = unsafe { mmap.slice_mut(0..64 << 10) }; - for chunk in mem.chunks_mut(1024) { - assert_eq!(chunk[0], 0); - chunk[0] = 5; + + unsafe { + with_slice_mut(&mmap, 0..64 << 10, |slice| { + for chunk in slice.chunks_mut(1024) { + assert_eq!(chunk[0], 0); + chunk[0] = 5; + } + }); } memfd .clear_and_remain_ready(amt_to_memset, |ptr, len| unsafe { @@ -1023,7 +1065,7 @@ mod test { ..Tunables::default_miri() }; - let mut mmap = mmap_4mib_inaccessible(); + let mmap = mmap_4mib_inaccessible(); let mut memfd = MemoryImageSlot::create( mmap.as_mut_ptr() as *mut _, HostAlignedByteCount::ZERO, @@ -1039,15 +1081,21 @@ mod test { .instantiate(initial, Some(&image), &ty, &tunables) .unwrap(); assert!(memfd.has_image()); - let slice = unsafe { mmap.slice_mut(0..(64 << 10) + page_size) }; - assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); - slice[page_size] = 5; - assert_eq!(&[5, 2, 3, 4], &slice[page_size..][..4]); + + unsafe { + with_slice_mut(&mmap, 0..(64 << 10) + page_size, move |slice| { + assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); + slice[page_size] = 5; + assert_eq!(&[5, 2, 3, 4], &slice[page_size..][..4]); + }); + } + memfd .clear_and_remain_ready(HostAlignedByteCount::ZERO, |ptr, len| unsafe { decommit_pages(ptr, len).unwrap() }) .unwrap(); + let slice = unsafe { mmap.slice(0..(64 << 10) + page_size) }; assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); // Re-instantiate make sure it preserves memory. Grow a bit and set data @@ -1056,10 +1104,17 @@ mod test { .instantiate(initial, Some(&image), &ty, &tunables) .unwrap(); assert_eq!(&[1, 2, 3, 4], &slice[page_size..][..4]); + memfd.set_heap_limit(initial * 2).unwrap(); - assert_eq!(&[0, 0], &slice[initial..initial + 2]); - slice[initial] = 100; - assert_eq!(&[100, 0], &slice[initial..initial + 2]); + + unsafe { + with_slice_mut(&mmap, 0..(64 << 10) + page_size, move |slice| { + assert_eq!(&[0, 0], &slice[initial..initial + 2]); + slice[initial] = 100; + assert_eq!(&[100, 0], &slice[initial..initial + 2]); + }); + } + memfd .clear_and_remain_ready(HostAlignedByteCount::ZERO, |ptr, len| unsafe { decommit_pages(ptr, len).unwrap() @@ -1076,9 +1131,15 @@ mod test { .unwrap(); assert_eq!(&[0, 0], &slice[initial..initial + 2]); memfd.set_heap_limit(initial * 2).unwrap(); - assert_eq!(&[0, 0], &slice[initial..initial + 2]); - slice[initial] = 100; - assert_eq!(&[100, 0], &slice[initial..initial + 2]); + + unsafe { + with_slice_mut(&mmap, 0..(64 << 10) + page_size, move |slice| { + assert_eq!(&[0, 0], &slice[initial..initial + 2]); + slice[initial] = 100; + assert_eq!(&[100, 0], &slice[initial..initial + 2]); + }); + } + memfd .clear_and_remain_ready(HostAlignedByteCount::ZERO, |ptr, len| unsafe { decommit_pages(ptr, len).unwrap() diff --git a/crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs b/crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs index 659717d83bd8..fa2b0d933c40 100644 --- a/crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs +++ b/crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs @@ -550,7 +550,7 @@ unsafe impl GcHeap for DrcHeap { let size = u32::try_from(layout.size()).unwrap(); if !VMGcKind::value_fits_in_unused_bits(size) { - return Err(crate::Trap::AllocationTooLarge.into_anyhow()); + return Err(crate::Trap::AllocationTooLarge.into()); } let gc_ref = match self.free_list.alloc(layout)? { diff --git a/crates/wasmtime/src/runtime/vm/gc/enabled/free_list.rs b/crates/wasmtime/src/runtime/vm/gc/enabled/free_list.rs index bc79d1c15b83..e1d2a3f923e6 100644 --- a/crates/wasmtime/src/runtime/vm/gc/enabled/free_list.rs +++ b/crates/wasmtime/src/runtime/vm/gc/enabled/free_list.rs @@ -60,7 +60,6 @@ impl FreeList { ); let alloc_size = u32::try_from(layout.size()) - .err2anyhow() .context("requested allocation's size does not fit in a u32")?; alloc_size .checked_next_multiple_of(ALIGN_U32) diff --git a/crates/wasmtime/src/runtime/vm/gc/enabled/null.rs b/crates/wasmtime/src/runtime/vm/gc/enabled/null.rs index a423bccb1537..776b3aabd1fb 100644 --- a/crates/wasmtime/src/runtime/vm/gc/enabled/null.rs +++ b/crates/wasmtime/src/runtime/vm/gc/enabled/null.rs @@ -111,7 +111,7 @@ impl VMNullExternRef { } fn oom() -> Error { - GcHeapOutOfMemory::new(()).into_anyhow() + GcHeapOutOfMemory::new(()).into() } impl NullHeap { @@ -144,7 +144,7 @@ impl NullHeap { } }) { Some(size) => size, - None => return Err(crate::Trap::AllocationTooLarge.into_anyhow()), + None => return Err(crate::Trap::AllocationTooLarge.into()), }; let next = *self.next.get_mut(); diff --git a/crates/wasmtime/src/runtime/vm/helpers.c b/crates/wasmtime/src/runtime/vm/helpers.c index cfae8f7c88e2..a3b5dc28287d 100644 --- a/crates/wasmtime/src/runtime/vm/helpers.c +++ b/crates/wasmtime/src/runtime/vm/helpers.c @@ -182,7 +182,7 @@ __declspec(dllexport) // important. __attribute__((weak)) #endif - struct JITDescriptor __jit_debug_descriptor = {1, 0, NULL, NULL}; +struct JITDescriptor __jit_debug_descriptor = {1, 0, NULL, NULL}; struct JITDescriptor *VERSIONED_SYMBOL(wasmtime_jit_debug_descriptor)() { return &__jit_debug_descriptor; diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator.rs b/crates/wasmtime/src/runtime/vm/instance/allocator.rs index 39cd52308853..0ad05091ecc6 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator.rs @@ -585,7 +585,7 @@ fn initialize_tables( let gc_store = store.gc_store_mut()?; let items = (0..table.size()) .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r))); - table.init_gc_refs(0, items).err2anyhow()?; + table.init_gc_refs(0, items)?; } WasmHeapTopType::Any => { @@ -593,13 +593,13 @@ fn initialize_tables( let gc_store = store.gc_store_mut()?; let items = (0..table.size()) .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r))); - table.init_gc_refs(0, items).err2anyhow()?; + table.init_gc_refs(0, items)?; } WasmHeapTopType::Func => { let funcref = NonNull::new(raw.get_funcref().cast::()); let items = (0..table.size()).map(|_| funcref); - table.init_func(0, items).err2anyhow()?; + table.init_func(0, items)?; } WasmHeapTopType::Cont => todo!(), // TODO(dhil): cont type table. @@ -621,18 +621,15 @@ fn initialize_tables( .eval(store, context, &segment.offset) .expect("const expression should be valid") }; - context - .instance - .table_init_segment( - store, - const_evaluator, - segment.table_index, - &segment.elements, - start.get_u64(), - 0, - segment.elements.len(), - ) - .err2anyhow()?; + context.instance.table_init_segment( + store, + const_evaluator, + segment.table_index, + &segment.elements, + start.get_u64(), + 0, + segment.elements.len(), + )?; } Ok(()) @@ -766,7 +763,7 @@ fn initialize_memories( const_evaluator, }); if !ok { - return Err(Trap::MemoryOutOfBounds).err2anyhow(); + return Err(Trap::MemoryOutOfBounds.into()); } Ok(()) diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs index d4a660307ac9..581d92526583 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs @@ -65,7 +65,7 @@ use crate::{ }; use std::ffi::c_void; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; use wasmtime_environ::{DefinedMemoryIndex, Module, Tunables}; /// A set of allocator slots. @@ -104,7 +104,7 @@ struct Stripe { /// ``` #[derive(Debug)] pub struct MemoryPool { - mapping: Mmap, + mapping: Arc>, /// This memory pool is stripe-aware. If using memory protection keys, this /// will contain one stripe per available key; otherwise, a single stripe /// with an empty key. @@ -244,7 +244,7 @@ impl MemoryPool { let pool = Self { stripes, - mapping, + mapping: Arc::new(mapping), image_slots, layout, memories_per_instance: usize::try_from(config.limits.max_memories_per_module).unwrap(), diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/table_pool.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/table_pool.rs index 336534abdca7..197ceb900e13 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/table_pool.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/table_pool.rs @@ -33,15 +33,13 @@ impl TablePool { crate::runtime::vm::table::MAX_TABLE_ELEM_SIZE .checked_mul(config.limits.table_elements) .ok_or_else(|| anyhow!("table size exceeds addressable memory"))?, - ) - .err2anyhow()?; + )?; let max_total_tables = usize::try_from(config.limits.total_tables).unwrap(); let tables_per_instance = usize::try_from(config.limits.max_tables_per_module).unwrap(); let allocation_size = table_size .checked_mul(max_total_tables) - .err2anyhow() .context("total size of tables exceeds addressable memory")?; let mapping = Mmap::accessible_reserved(allocation_size, allocation_size) diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs index c443adb228a9..c4ef3fd91bd1 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs @@ -40,7 +40,6 @@ impl StackPool { } else { HostAlignedByteCount::new_rounded_up(config.stack_size) .and_then(|size| size.checked_add(HostAlignedByteCount::host_page_size())) - .err2anyhow() .context("stack size exceeds addressable memory")? }; @@ -48,7 +47,6 @@ impl StackPool { let allocation_size = stack_size .checked_mul(max_stacks) - .err2anyhow() .context("total size of execution stacks exceeds addressable memory")?; let mapping = Mmap::accessible_reserved(allocation_size, allocation_size) diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/wasmfx_allocator.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/wasmfx_allocator.rs index a32203cdd9e6..a3e681f08232 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/wasmfx_allocator.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/wasmfx_allocator.rs @@ -101,7 +101,6 @@ pub mod wasmfx_pooling { } else { HostAlignedByteCount::new_rounded_up(config.stack_size) .and_then(|size| size.checked_add(HostAlignedByteCount::host_page_size())) - .err2anyhow() .context("stack size exceeds addressable memory")? }; @@ -109,7 +108,6 @@ pub mod wasmfx_pooling { let allocation_size = stack_size .checked_mul(max_stacks) - .err2anyhow() .context("total size of execution stacks exceeds addressable memory")?; let stack_mapping = Mmap::accessible_reserved(allocation_size, allocation_size) diff --git a/crates/wasmtime/src/runtime/vm/libcalls.rs b/crates/wasmtime/src/runtime/vm/libcalls.rs index 06f04bec77c3..31a1ef633a7a 100644 --- a/crates/wasmtime/src/runtime/vm/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/libcalls.rs @@ -319,9 +319,7 @@ unsafe fn table_fill_func_ref( match table.element_type() { TableElementType::Func => { let val = NonNull::new(val.cast::()); - table - .fill(store.optional_gc_store_mut()?, dst, val.into(), len) - .err2anyhow()?; + table.fill(store.optional_gc_store_mut()?, dst, val.into(), len)?; Ok(()) } TableElementType::GcRef => unreachable!(), @@ -346,9 +344,7 @@ unsafe fn table_fill_gc_ref( let gc_store = store.store_opaque_mut().unwrap_gc_store_mut(); let gc_ref = VMGcRef::from_raw_u32(val); let gc_ref = gc_ref.map(|r| gc_store.clone_gc_ref(&r)); - table - .fill(Some(gc_store), dst, gc_ref.into(), len) - .err2anyhow()?; + table.fill(Some(gc_store), dst, gc_ref.into(), len)?; Ok(()) } @@ -379,9 +375,7 @@ unsafe fn table_fill_cont_obj( Some(contobj) }; - table - .fill(store.optional_gc_store_mut()?, dst, contobj.into(), len) - .err2anyhow()?; + table.fill(store.optional_gc_store_mut()?, dst, contobj.into(), len)?; Ok(()) } _ => panic!("Wrong table filling function"), @@ -406,7 +400,7 @@ unsafe fn table_copy( let src_range = src..(src.checked_add(len).unwrap_or(u64::MAX)); let src_table = instance.get_table_with_lazy_init(src_table_index, src_range); let gc_store = store.optional_gc_store_mut()?; - Table::copy(gc_store, dst_table, src_table, dst, src, len).err2anyhow()?; + Table::copy(gc_store, dst_table, src_table, dst, src, len)?; Ok(()) } @@ -613,8 +607,7 @@ unsafe fn gc_alloc_raw( store .unwrap_gc_store_mut() .alloc_raw(header, layout)? - .ok_or_else(|| GcHeapOutOfMemory::new(())) - .err2anyhow()? + .ok_or_else(|| GcHeapOutOfMemory::new(()))? } }; @@ -707,15 +700,15 @@ unsafe fn array_new_data( let byte_len = len .checked_mul(one_elem_size) .and_then(|x| usize::try_from(x).ok()) - .ok_or_else(|| Trap::MemoryOutOfBounds.into_anyhow())?; + .ok_or_else(|| Trap::MemoryOutOfBounds)?; // Get the data from the segment, checking bounds. - let src = usize::try_from(src).map_err(|_| Trap::MemoryOutOfBounds.into_anyhow())?; + let src = usize::try_from(src).map_err(|_| Trap::MemoryOutOfBounds)?; let data = instance .wasm_data(data_range) .get(src..) .and_then(|d| d.get(..byte_len)) - .ok_or_else(|| Trap::MemoryOutOfBounds.into_anyhow())?; + .ok_or_else(|| Trap::MemoryOutOfBounds)?; // Allocate the (uninitialized) array. let gc_layout = store @@ -739,7 +732,7 @@ unsafe fn array_new_data( .store_opaque_mut() .unwrap_gc_store_mut() .alloc_uninit_array(shared_ty, u32::try_from(byte_len).unwrap(), &array_layout)? - .ok_or_else(|| GcHeapOutOfMemory::new(()).into_anyhow())? + .ok_or_else(|| GcHeapOutOfMemory::new(()))? } }; @@ -782,24 +775,20 @@ unsafe fn array_init_data( ); // Null check the array. - let gc_ref = VMGcRef::from_raw_u32(array).ok_or_else(|| Trap::NullReference.into_anyhow())?; + let gc_ref = VMGcRef::from_raw_u32(array).ok_or_else(|| Trap::NullReference)?; let array = gc_ref .into_arrayref(&*store.unwrap_gc_store().gc_heap) .expect("gc ref should be an array"); - let dst = usize::try_from(dst).map_err(|_| Trap::MemoryOutOfBounds.into_anyhow())?; - let src = usize::try_from(src).map_err(|_| Trap::MemoryOutOfBounds.into_anyhow())?; - let len = usize::try_from(len).map_err(|_| Trap::MemoryOutOfBounds.into_anyhow())?; + let dst = usize::try_from(dst).map_err(|_| Trap::MemoryOutOfBounds)?; + let src = usize::try_from(src).map_err(|_| Trap::MemoryOutOfBounds)?; + let len = usize::try_from(len).map_err(|_| Trap::MemoryOutOfBounds)?; // Bounds check the array. let array_len = array.len(store.store_opaque()); - let array_len = usize::try_from(array_len).map_err(|_| Trap::ArrayOutOfBounds.into_anyhow())?; - if dst - .checked_add(len) - .ok_or_else(|| Trap::ArrayOutOfBounds.into_anyhow())? - > array_len - { - return Err(Trap::ArrayOutOfBounds.into_anyhow()); + let array_len = usize::try_from(array_len).map_err(|_| Trap::ArrayOutOfBounds)?; + if dst.checked_add(len).ok_or_else(|| Trap::ArrayOutOfBounds)? > array_len { + return Err(Trap::ArrayOutOfBounds.into()); } // Calculate the byte length from the array length. @@ -811,7 +800,7 @@ unsafe fn array_init_data( .expect("Wasm validation ensures that this type have a defined byte size"); let data_len = len .checked_mul(usize::try_from(one_elem_size).unwrap()) - .ok_or_else(|| Trap::MemoryOutOfBounds.into_anyhow())?; + .ok_or_else(|| Trap::MemoryOutOfBounds)?; // Get the data from the segment, checking its bounds. let data_range = instance.wasm_data_range(data_index); @@ -819,7 +808,7 @@ unsafe fn array_init_data( .wasm_data(data_range) .get(src..) .and_then(|d| d.get(..data_len)) - .ok_or_else(|| Trap::MemoryOutOfBounds.into_anyhow())?; + .ok_or_else(|| Trap::MemoryOutOfBounds)?; // Copy the data into the array. @@ -868,8 +857,8 @@ unsafe fn array_new_elem( let mut storage = None; let elements = instance.passive_element_segment(&mut storage, elem_index); - let src = usize::try_from(src).map_err(|_| Trap::TableOutOfBounds.into_anyhow())?; - let len = usize::try_from(len).map_err(|_| Trap::TableOutOfBounds.into_anyhow())?; + let src = usize::try_from(src).map_err(|_| Trap::TableOutOfBounds)?; + let len = usize::try_from(len).map_err(|_| Trap::TableOutOfBounds)?; let shared_ty = instance.engine_type_index(array_type_index); let array_ty = ArrayType::from_shared_type_index(store.engine(), shared_ty); @@ -884,7 +873,7 @@ unsafe fn array_new_elem( vals.extend( fs.get(src..) .and_then(|s| s.get(..len)) - .ok_or_else(|| Trap::TableOutOfBounds.into_anyhow())? + .ok_or_else(|| Trap::TableOutOfBounds)? .iter() .map(|f| { let raw_func_ref = instance.get_func_ref(*f); @@ -897,7 +886,7 @@ unsafe fn array_new_elem( let xs = xs .get(src..) .and_then(|s| s.get(..len)) - .ok_or_else(|| Trap::TableOutOfBounds.into_anyhow())?; + .ok_or_else(|| Trap::TableOutOfBounds)?; let mut const_context = ConstEvalContext::new(instance); let mut const_evaluator = ConstExprEvaluator::default(); @@ -960,7 +949,7 @@ unsafe fn array_init_elem( ); // Convert the raw GC ref into a `Rooted`. - let array = VMGcRef::from_raw_u32(array).ok_or_else(|| Trap::NullReference.into_anyhow())?; + let array = VMGcRef::from_raw_u32(array).ok_or_else(|| Trap::NullReference)?; let array = store.unwrap_gc_store_mut().clone_gc_ref(&array); let array = { let mut no_gc = AutoAssertNoGc::new(&mut store); @@ -970,12 +959,8 @@ unsafe fn array_init_elem( // Bounds check the destination within the array. let array_len = array._len(&store)?; log::trace!("array_len = {array_len}"); - if dst - .checked_add(len) - .ok_or_else(|| Trap::ArrayOutOfBounds.into_anyhow())? - > array_len - { - return Err(Trap::ArrayOutOfBounds.into_anyhow()); + if dst.checked_add(len).ok_or_else(|| Trap::ArrayOutOfBounds)? > array_len { + return Err(Trap::ArrayOutOfBounds.into()); } // Get the passive element segment. @@ -983,15 +968,15 @@ unsafe fn array_init_elem( let elements = instance.passive_element_segment(&mut storage, elem_index); // Convert array offsets into `usize`s. - let src = usize::try_from(src).map_err(|_| Trap::TableOutOfBounds.into_anyhow())?; - let len = usize::try_from(len).map_err(|_| Trap::TableOutOfBounds.into_anyhow())?; + let src = usize::try_from(src).map_err(|_| Trap::TableOutOfBounds)?; + let len = usize::try_from(len).map_err(|_| Trap::TableOutOfBounds)?; // Turn the elements into `Val`s. let vals = match elements { TableSegmentElements::Functions(fs) => fs .get(src..) .and_then(|s| s.get(..len)) - .ok_or_else(|| Trap::TableOutOfBounds.into_anyhow())? + .ok_or_else(|| Trap::TableOutOfBounds)? .iter() .map(|f| { let raw_func_ref = instance.get_func_ref(*f); @@ -1008,7 +993,7 @@ unsafe fn array_init_elem( xs.get(src..) .and_then(|s| s.get(..len)) - .ok_or_else(|| Trap::TableOutOfBounds.into_anyhow())? + .ok_or_else(|| Trap::TableOutOfBounds)? .iter() .map(|x| unsafe { let raw = const_evaluator @@ -1055,33 +1040,23 @@ unsafe fn array_copy( let mut store = AutoAssertNoGc::new(&mut store); // Convert the raw GC refs into `Rooted`s. - let dst_array = - VMGcRef::from_raw_u32(dst_array).ok_or_else(|| Trap::NullReference.into_anyhow())?; + let dst_array = VMGcRef::from_raw_u32(dst_array).ok_or_else(|| Trap::NullReference)?; let dst_array = store.unwrap_gc_store_mut().clone_gc_ref(&dst_array); let dst_array = ArrayRef::from_cloned_gc_ref(&mut store, dst_array); - let src_array = - VMGcRef::from_raw_u32(src_array).ok_or_else(|| Trap::NullReference.into_anyhow())?; + let src_array = VMGcRef::from_raw_u32(src_array).ok_or_else(|| Trap::NullReference)?; let src_array = store.unwrap_gc_store_mut().clone_gc_ref(&src_array); let src_array = ArrayRef::from_cloned_gc_ref(&mut store, src_array); // Bounds check the destination array's elements. let dst_array_len = dst_array._len(&store)?; - if dst - .checked_add(len) - .ok_or_else(|| Trap::ArrayOutOfBounds.into_anyhow())? - > dst_array_len - { - return Err(Trap::ArrayOutOfBounds.into_anyhow()); + if dst.checked_add(len).ok_or_else(|| Trap::ArrayOutOfBounds)? > dst_array_len { + return Err(Trap::ArrayOutOfBounds.into()); } // Bounds check the source array's elements. let src_array_len = src_array._len(&store)?; - if src - .checked_add(len) - .ok_or_else(|| Trap::ArrayOutOfBounds.into_anyhow())? - > src_array_len - { - return Err(Trap::ArrayOutOfBounds.into_anyhow()); + if src.checked_add(len).ok_or_else(|| Trap::ArrayOutOfBounds)? > src_array_len { + return Err(Trap::ArrayOutOfBounds.into()); } let mut store = AutoAssertNoGc::new(&mut store); diff --git a/crates/wasmtime/src/runtime/vm/memory/malloc.rs b/crates/wasmtime/src/runtime/vm/memory/malloc.rs index 95378ee3c604..b822a376acc3 100644 --- a/crates/wasmtime/src/runtime/vm/memory/malloc.rs +++ b/crates/wasmtime/src/runtime/vm/memory/malloc.rs @@ -39,17 +39,12 @@ impl MallocMemory { } let initial_allocation_byte_size = minimum - .checked_add( - tunables - .memory_reservation_for_growth - .try_into() - .err2anyhow()?, - ) + .checked_add(tunables.memory_reservation_for_growth.try_into()?) .context("memory allocation size too large")?; let initial_allocation_len = byte_size_to_element_len(initial_allocation_byte_size); let mut storage = Vec::new(); - storage.try_reserve(initial_allocation_len).err2anyhow()?; + storage.try_reserve(initial_allocation_len)?; let initial_len = byte_size_to_element_len(minimum); if initial_len > 0 { @@ -76,8 +71,7 @@ impl RuntimeLinearMemory for MallocMemory { let new_element_len = byte_size_to_element_len(new_size); if new_element_len > self.storage.len() { self.storage - .try_reserve(new_element_len - self.storage.len()) - .err2anyhow()?; + .try_reserve(new_element_len - self.storage.len())?; grow_storage_to(&mut self.storage, new_element_len); self.base_ptr = SendSyncPtr::new(NonNull::new(self.storage.as_mut_ptr()).unwrap()).cast(); diff --git a/crates/wasmtime/src/runtime/vm/memory/mmap.rs b/crates/wasmtime/src/runtime/vm/memory/mmap.rs index 66840f8dcf5c..0d536d1d2737 100644 --- a/crates/wasmtime/src/runtime/vm/memory/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/memory/mmap.rs @@ -4,13 +4,14 @@ use crate::prelude::*; use crate::runtime::vm::memory::RuntimeLinearMemory; use crate::runtime::vm::{mmap::AlignedLength, HostAlignedByteCount, Mmap}; +use alloc::sync::Arc; use wasmtime_environ::Tunables; /// A linear memory instance. #[derive(Debug)] pub struct MmapMemory { // The underlying allocation. - mmap: Mmap, + mmap: Arc>, // The current length of this Wasm memory, in bytes. // @@ -58,7 +59,6 @@ impl MmapMemory { // Also be sure to round up to the host page size for this value. let offset_guard_bytes = HostAlignedByteCount::new_rounded_up_u64(tunables.memory_guard_size) - .err2anyhow() .context("tunable.memory_guard_size overflows")?; let pre_guard_bytes = if tunables.guard_before_linear_memory { offset_guard_bytes @@ -92,28 +92,28 @@ impl MmapMemory { // Convert `alloc_bytes` and `extra_to_reserve_on_growth` to // page-aligned `usize` values. let alloc_bytes = HostAlignedByteCount::new_rounded_up_u64(alloc_bytes) - .err2anyhow() .context("tunables.memory_reservation overflows")?; let extra_to_reserve_on_growth = HostAlignedByteCount::new_rounded_up_u64(extra_to_reserve_on_growth) - .err2anyhow() .context("tunables.memory_reservation_for_growth overflows")?; let request_bytes = pre_guard_bytes .checked_add(alloc_bytes) .and_then(|i| i.checked_add(offset_guard_bytes)) - .err2anyhow() .with_context(|| format!("cannot allocate {minimum} with guard regions"))?; - let mut mmap = Mmap::accessible_reserved(HostAlignedByteCount::ZERO, request_bytes)?; + let mmap = Mmap::accessible_reserved(HostAlignedByteCount::ZERO, request_bytes)?; if minimum > 0 { - let accessible = HostAlignedByteCount::new_rounded_up(minimum).err2anyhow()?; - mmap.make_accessible(pre_guard_bytes, accessible)?; + let accessible = HostAlignedByteCount::new_rounded_up(minimum)?; + // SAFETY: mmap is not in use right now so it's safe to make it accessible. + unsafe { + mmap.make_accessible(pre_guard_bytes, accessible)?; + } } Ok(Self { - mmap, + mmap: Arc::new(mmap), len: minimum, maximum, pre_guard_size: pre_guard_bytes, @@ -152,7 +152,7 @@ impl RuntimeLinearMemory for MmapMemory { } fn grow_to(&mut self, new_size: usize) -> Result<()> { - let new_accessible = HostAlignedByteCount::new_rounded_up(new_size).err2anyhow()?; + let new_accessible = HostAlignedByteCount::new_rounded_up(new_size)?; let current_capacity = self.current_capacity(); if new_accessible > current_capacity { // If the new size of this heap exceeds the current size of the @@ -164,12 +164,15 @@ impl RuntimeLinearMemory for MmapMemory { .checked_add(new_accessible) .and_then(|s| s.checked_add(self.extra_to_reserve_on_growth)) .and_then(|s| s.checked_add(self.offset_guard_size)) - .err2anyhow() .context("overflow calculating size of memory allocation")?; let mut new_mmap = Mmap::accessible_reserved(HostAlignedByteCount::ZERO, request_bytes)?; - new_mmap.make_accessible(self.pre_guard_size, new_accessible)?; + // SAFETY: new_mmap is not in use right now so it's safe to make it + // accessible. + unsafe { + new_mmap.make_accessible(self.pre_guard_size, new_accessible)?; + } // This method has an exclusive reference to `self.mmap` and just // created `new_mmap` so it should be safe to acquire references @@ -182,7 +185,7 @@ impl RuntimeLinearMemory for MmapMemory { dst.copy_from_slice(src); } - self.mmap = new_mmap; + self.mmap = Arc::new(new_mmap); } else { // If the new size of this heap fits within the existing allocation // then all we need to do is to make the new pages accessible. This @@ -198,13 +201,16 @@ impl RuntimeLinearMemory for MmapMemory { // since we are forced to round our accessible range up to the // host's page size. if let Ok(difference) = new_accessible.checked_sub(self.accessible()) { - self.mmap.make_accessible( - self.pre_guard_size - .checked_add(self.accessible()) - .err2anyhow() - .context("overflow calculating new accessible region")?, - difference, - )?; + // SAFETY: the difference was previously inaccessible so we + // never handed out any references to within it. + unsafe { + self.mmap.make_accessible( + self.pre_guard_size + .checked_add(self.accessible()) + .context("overflow calculating new accessible region")?, + difference, + )?; + } } } diff --git a/crates/wasmtime/src/runtime/vm/mmap.rs b/crates/wasmtime/src/runtime/vm/mmap.rs index f9c0d692d43f..c16ec11e812f 100644 --- a/crates/wasmtime/src/runtime/vm/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/mmap.rs @@ -63,7 +63,7 @@ impl Mmap { /// Create a new `Mmap` pointing to at least `size` bytes of page-aligned /// accessible memory. pub fn with_at_least(size: usize) -> Result { - let rounded_size = HostAlignedByteCount::new_rounded_up(size).err2anyhow()?; + let rounded_size = HostAlignedByteCount::new_rounded_up(size)?; Self::accessible_reserved(rounded_size, rounded_size) } @@ -93,17 +93,20 @@ impl Mmap { data: AlignedLength {}, }) } else { - let mut result = Mmap { + let result = Mmap { sys: mmap::Mmap::reserve(mapping_size) .context(format!("mmap failed to reserve {mapping_size:#x} bytes"))?, data: AlignedLength {}, }; if !accessible_size.is_zero() { - result - .make_accessible(HostAlignedByteCount::ZERO, accessible_size) - .context(format!( - "mmap failed to allocate {accessible_size:#x} bytes" - ))?; + // SAFETY: result was just created and is not in use. + unsafe { + result + .make_accessible(HostAlignedByteCount::ZERO, accessible_size) + .context(format!( + "mmap failed to allocate {accessible_size:#x} bytes" + ))?; + } } Ok(result) } @@ -133,11 +136,16 @@ impl Mmap { /// accessible. `start` and `len` must be native page-size multiples and /// describe a range within `self`'s reserved memory. /// + /// # Safety + /// + /// There must not be any other references to the region of memory being + /// made accessible. + /// /// # Panics /// /// Panics if `start + len >= self.len()`. - pub fn make_accessible( - &mut self, + pub unsafe fn make_accessible( + &self, start: HostAlignedByteCount, len: HostAlignedByteCount, ) -> Result<()> { @@ -331,12 +339,12 @@ mod tests { let pagex3 = page_size.checked_mul(3).unwrap(); let pagex4 = page_size.checked_mul(4).unwrap(); - let mut mem = Mmap::accessible_reserved(pagex2, pagex4).expect("allocated memory"); - - mem.make_accessible(pagex3, HostAlignedByteCount::ZERO) - .expect("make_accessible succeeded"); + let mem = Mmap::accessible_reserved(pagex2, pagex4).expect("allocated memory"); unsafe { + mem.make_accessible(pagex3, HostAlignedByteCount::ZERO) + .expect("make_accessible succeeded"); + mem.make_executable(pagex3.byte_count()..pagex3.byte_count(), false) .expect("make_executable succeeded"); diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs index 1bcd9b2bfd0f..650bc070d444 100644 --- a/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs @@ -51,8 +51,8 @@ impl Mmap { anyhow::bail!("not supported on this platform"); } - pub fn make_accessible( - &mut self, + pub unsafe fn make_accessible( + &self, start: HostAlignedByteCount, len: HostAlignedByteCount, ) -> Result<()> { diff --git a/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs index 05bd596e9658..eae0ed29fc9f 100644 --- a/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs @@ -30,8 +30,11 @@ impl Mmap { } pub fn new(size: HostAlignedByteCount) -> Result { - let mut ret = Mmap::reserve(size)?; - ret.make_accessible(HostAlignedByteCount::ZERO, size)?; + let ret = Mmap::reserve(size)?; + // SAFETY: The memory was just created so no one else has access to it. + unsafe { + ret.make_accessible(HostAlignedByteCount::ZERO, size)?; + } Ok(ret) } @@ -54,8 +57,8 @@ impl Mmap { bail!("not supported on miri"); } - pub fn make_accessible( - &mut self, + pub unsafe fn make_accessible( + &self, start: HostAlignedByteCount, len: HostAlignedByteCount, ) -> Result<()> { diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs index c2a00e0f1abe..50512070d7b5 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs @@ -9,7 +9,7 @@ use std::{fs::File, path::Path}; /// Open a file so that it can be mmap'd for executing. #[cfg(feature = "std")] pub fn open_file_for_mmap(path: &Path) -> Result { - File::open(path).err2anyhow().context("failed to open file") + File::open(path).context("failed to open file") } #[derive(Debug)] @@ -48,8 +48,7 @@ impl Mmap { size.byte_count(), rustix::mm::ProtFlags::READ | rustix::mm::ProtFlags::WRITE, rustix::mm::MapFlags::PRIVATE | MMAP_NORESERVE_FLAG, - ) - .err2anyhow()? + )? }; let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), size.byte_count()); let memory = SendSyncPtr::new(NonNull::new(memory).unwrap()); @@ -74,8 +73,7 @@ impl Mmap { // Virtual memory that cannot be accessed should not have a backing store reserved // for it. Hence, passing in NORESERVE is correct here. rustix::mm::MapFlags::PRIVATE | MMAP_NORESERVE_FLAG, - ) - .err2anyhow()? + )? }; let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), size.byte_count()); @@ -87,7 +85,6 @@ impl Mmap { pub fn from_file(file: &File) -> Result { let len = file .metadata() - .err2anyhow() .context("failed to get file metadata")? .len(); let len = usize::try_from(len).map_err(|_| anyhow::anyhow!("file too large to map"))?; @@ -100,7 +97,6 @@ impl Mmap { &file, 0, ) - .err2anyhow() .context(format!("mmap failed to allocate {len:#x} bytes"))? }; let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), len); @@ -109,8 +105,8 @@ impl Mmap { Ok(Mmap { memory }) } - pub fn make_accessible( - &mut self, + pub unsafe fn make_accessible( + &self, start: HostAlignedByteCount, len: HostAlignedByteCount, ) -> Result<()> { @@ -120,8 +116,7 @@ impl Mmap { ptr.byte_add(start.byte_count()).cast(), len.byte_count(), MprotectFlags::READ | MprotectFlags::WRITE, - ) - .err2anyhow()?; + )?; } Ok(()) @@ -168,7 +163,7 @@ impl Mmap { flags }; - mprotect(base, len, flags).err2anyhow()?; + mprotect(base, len, flags)?; Ok(()) } @@ -177,7 +172,7 @@ impl Mmap { let base = self.memory.as_ptr().byte_add(range.start).cast(); let len = range.end - range.start; - mprotect(base, len, MprotectFlags::READ).err2anyhow()?; + mprotect(base, len, MprotectFlags::READ)?; Ok(()) } diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/vm.rs b/crates/wasmtime/src/runtime/vm/sys/unix/vm.rs index 0f3114bfdf78..6d457ba5f191 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/vm.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/vm.rs @@ -102,7 +102,6 @@ impl MemoryImageSource { // in-memory file to represent the heap image. This anonymous // file is then used as the basis for further mmaps. - use crate::prelude::*; use std::io::{ErrorKind, Write}; // Create the memfd. It needs a name, but the documentation for @@ -118,9 +117,9 @@ impl MemoryImageSource { Err(memfd::Error::Create(err)) if err.kind() == ErrorKind::Unsupported => { return Ok(None) } - Err(e) => return Err(e.into_anyhow()), + Err(e) => return Err(e.into()), }; - memfd.as_file().write_all(data).err2anyhow()?; + memfd.as_file().write_all(data)?; // Seal the memfd's data and length. // @@ -137,14 +136,12 @@ impl MemoryImageSource { // extra-super-sure that it never changes, and because // this costs very little, we use the kernel's "seal" API // to make the memfd image permanently read-only. - memfd - .add_seals(&[ - memfd::FileSeal::SealGrow, - memfd::FileSeal::SealShrink, - memfd::FileSeal::SealWrite, - memfd::FileSeal::SealSeal, - ]) - .err2anyhow()?; + memfd.add_seals(&[ + memfd::FileSeal::SealGrow, + memfd::FileSeal::SealShrink, + memfd::FileSeal::SealWrite, + memfd::FileSeal::SealSeal, + ])?; Ok(Some(MemoryImageSource::Memfd(memfd))) } diff --git a/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs index b45c3488c445..9f23e0f2066d 100644 --- a/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs @@ -22,7 +22,6 @@ pub fn open_file_for_mmap(path: &Path) -> Result { .access_mode(FILE_GENERIC_READ | FILE_GENERIC_EXECUTE) .share_mode(FILE_SHARE_READ) .open(path) - .err2anyhow() .context("failed to open file") } @@ -85,7 +84,6 @@ impl Mmap { unsafe { let len = file .metadata() - .err2anyhow() .context("failed to get file metadata")? .len(); let len = usize::try_from(len).map_err(|_| anyhow!("file too large to map"))?; @@ -105,8 +103,7 @@ impl Mmap { ptr::null(), ); if mapping == INVALID_HANDLE_VALUE { - return Err(io::Error::last_os_error().into_anyhow()) - .context("failed to create file mapping"); + return Err(io::Error::last_os_error()).context("failed to create file mapping"); } // Create a view for the entire file using all our requisite @@ -123,8 +120,7 @@ impl Mmap { let err = io::Error::last_os_error(); CloseHandle(mapping); if ptr.is_null() { - return Err(err.into_anyhow()) - .context(format!("failed to create map view of {:#x} bytes", len)); + return Err(err).context(format!("failed to create map view of {:#x} bytes", len)); } let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), len); @@ -138,7 +134,7 @@ impl Mmap { // remove the execute bit) let mut old = 0; if VirtualProtect(ret.as_mut_ptr().cast(), ret.len(), PAGE_WRITECOPY, &mut old) == 0 { - return Err(io::Error::last_os_error().into_anyhow()) + return Err(io::Error::last_os_error()) .context("failed change pages to `PAGE_READONLY`"); } @@ -146,8 +142,8 @@ impl Mmap { } } - pub fn make_accessible( - &mut self, + pub unsafe fn make_accessible( + &self, start: HostAlignedByteCount, len: HostAlignedByteCount, ) -> Result<()> { diff --git a/examples/mpk.rs b/examples/mpk.rs index 59edaaabf086..8b850d2edbdb 100644 --- a/examples/mpk.rs +++ b/examples/mpk.rs @@ -31,8 +31,6 @@ //! $ sysctl vm.max_map_count=$LARGER_LIMIT //! ``` -#![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] - use anyhow::anyhow; use bytesize::ByteSize; use clap::Parser; @@ -115,7 +113,6 @@ fn probe_engine_size(args: &Args, mpk: MpkEnabled) -> Result { } #[derive(Debug)] -#[allow(dead_code)] struct Pool { num_memories: u32, mapped_bytes: usize, diff --git a/pulley/fuzz/src/interp.rs b/pulley/fuzz/src/interp.rs index 826d0ad30f86..82f29ffe0c88 100644 --- a/pulley/fuzz/src/interp.rs +++ b/pulley/fuzz/src/interp.rs @@ -118,6 +118,8 @@ fn op_is_safe_for_fuzzing(op: &Op) -> bool { Op::XPush32Many(_) | Op::XPush64Many(_) => false, Op::XPop32Many(_) | Op::XPop64Many(_) => false, Op::BrTable32(_) => false, + Op::StackAlloc32(_) => false, + Op::StackFree32(_) => false, } } @@ -125,7 +127,6 @@ fn extended_op_is_safe_for_fuzzing(op: &ExtendedOp) -> bool { match op { ExtendedOp::Trap(_) => true, ExtendedOp::Nop(_) => true, - ExtendedOp::GetSp(GetSp { dst, .. }) => !dst.is_special(), ExtendedOp::CallIndirectHost(_) => false, } } diff --git a/pulley/src/disas.rs b/pulley/src/disas.rs index bdedf1164f59..301bf2c345d6 100644 --- a/pulley/src/disas.rs +++ b/pulley/src/disas.rs @@ -274,7 +274,7 @@ impl<'a> OpVisitor for Disassembler<'a> { write!(&mut self.disas, "{space}{byte:02x}").unwrap(); need_space = true; } - for _ in 0..11_usize.saturating_sub(size) { + for _ in 0..12_usize.saturating_sub(size) { write!(&mut self.disas, " ").unwrap(); } } diff --git a/pulley/src/interp.rs b/pulley/src/interp.rs index 1724f2a7d910..4e13d385ef24 100644 --- a/pulley/src/interp.rs +++ b/pulley/src/interp.rs @@ -1237,6 +1237,20 @@ impl OpVisitor for Interpreter<'_> { let rel = unwrap_uninhabited(PcRelOffset::decode(&mut self.pc)); self.pc_rel_jump(rel, 0) } + + fn stack_alloc32(&mut self, amt: u32) -> ControlFlow { + let amt = usize::try_from(amt).unwrap(); + let new_sp = self.state[XReg::sp].get_ptr::().wrapping_sub(amt); + self.set_sp(new_sp)?; + ControlFlow::Continue(()) + } + + fn stack_free32(&mut self, amt: u32) -> ControlFlow { + let amt = usize::try_from(amt).unwrap(); + let new_sp = self.state[XReg::sp].get_ptr::().wrapping_add(amt); + self.set_sp_unchecked(new_sp); + ControlFlow::Continue(()) + } } impl ExtendedOpVisitor for Interpreter<'_> { @@ -1248,12 +1262,6 @@ impl ExtendedOpVisitor for Interpreter<'_> { ControlFlow::Break(Done::Trap(self.pc.as_ptr())) } - fn get_sp(&mut self, dst: XReg) -> ControlFlow { - let sp = self.state[XReg::sp].get_u64(); - self.state[dst].set_u64(sp); - ControlFlow::Continue(()) - } - fn call_indirect_host(&mut self, sig: u8) -> ControlFlow { let _ = sig; // TODO: should stash this somewhere ControlFlow::Break(Done::ReturnToHost) diff --git a/pulley/src/lib.rs b/pulley/src/lib.rs index abb91df56b01..30a9da64c0e5 100644 --- a/pulley/src/lib.rs +++ b/pulley/src/lib.rs @@ -163,11 +163,11 @@ macro_rules! for_each_op { /// `sp = fp; pop fp; pop lr` pop_frame = PopFrame ; - /// `*sp = low32(src); sp += 4` + /// `*sp = low32(src); sp = sp.checked_add(4)` xpush32 = XPush32 { src: XReg }; /// `for src in srcs { xpush32 src }` xpush32_many = XPush32Many { srcs: RegSet }; - /// `*sp = src; sp += 8` + /// `*sp = src; sp = sp.checked_add(8)` xpush64 = XPush64 { src: XReg }; /// `for src in srcs { xpush64 src }` xpush64_many = XPush64Many { srcs: RegSet }; @@ -189,6 +189,12 @@ macro_rules! for_each_op { bitcast_float_from_int_32 = BitcastFloatFromInt32 { dst: FReg, src: XReg }; /// `dst = bitcast src as f64` bitcast_float_from_int_64 = BitcastFloatFromInt64 { dst: FReg, src: XReg }; + + /// `sp = sp.checked_sub(amt)` + stack_alloc32 = StackAlloc32 { amt: u32 }; + + /// `sp = sp + amt` + stack_free32 = StackFree32 { amt: u32 }; } }; } @@ -203,8 +209,6 @@ macro_rules! for_each_extended_op { /// Do nothing. nop = Nop; - /// Copy the special `sp` stack pointer register into an `x` register. - get_sp = GetSp { dst: XReg }; /// A special opcode to use an indirect function call to reenter the /// host from the interpreter. /// diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index b0c24e598424..0235a67f4f16 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -2354,6 +2354,12 @@ No `unsafe` code in this update. Lots of changes but all object-file-format-related, everything looks good. """ +[[audits.object]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.36.0 -> 0.36.5" +notes = "No new unsafe code, lots of new relocations/objects support, everything looks nominal" + [[audits.once_cell]] who = "Chris Fallin " criteria = "safe-to-deploy" @@ -3939,7 +3945,7 @@ end = "2025-09-20" criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-10-05" -end = "2024-09-01" +end = "2025-12-02" [[trusted.async-trait]] criteria = "safe-to-deploy" @@ -4281,13 +4287,13 @@ end = "2024-07-06" criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-03-01" -end = "2024-07-06" +end = "2025-12-02" [[trusted.serde_derive]] criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-03-01" -end = "2024-07-06" +end = "2025-12-02" [[trusted.serde_json]] criteria = "safe-to-deploy" @@ -4305,7 +4311,7 @@ end = "2025-02-12" criteria = "safe-to-deploy" user-id = 3618 # David Tolnay (dtolnay) start = "2019-03-01" -end = "2024-07-06" +end = "2025-12-02" [[trusted.system-interface]] criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index cb0cbaa3cd7a..d54501a21130 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -5,186 +5,370 @@ version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-bforest]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-bforest]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-bitset]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-bitset]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-codegen]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-codegen]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-codegen-meta]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-codegen-meta]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-codegen-shared]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-codegen-shared]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-control]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-control]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-entity]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-entity]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-frontend]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-frontend]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-interpreter]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-interpreter]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-isle]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-isle]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-jit]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-jit]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-module]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-module]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-native]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-native]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-object]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-object]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-reader]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-reader]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.cranelift-serde]] version = "0.115.0" audited_as = "0.113.1" +[[unpublished.cranelift-serde]] +version = "0.116.0" +audited_as = "0.114.0" + [[unpublished.pulley-interpreter]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.pulley-interpreter]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasi-common]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasi-common]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-asm-macros]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-asm-macros]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-cache]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-cache]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-cli]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-cli]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-cli-flags]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-cli-flags]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-component-macro]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-component-macro]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-component-util]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-component-util]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-cranelift]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-cranelift]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-environ]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-environ]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-explorer]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-explorer]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-fiber]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-fiber]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-jit-debug]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-jit-debug]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-jit-icache-coherence]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-jit-icache-coherence]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-slab]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-slab]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wasi]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-wasi]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wasi-config]] version = "28.0.0" audited_as = "27.0.0" +[[unpublished.wasmtime-wasi-config]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wasi-http]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-wasi-http]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wasi-keyvalue]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-wasi-keyvalue]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wasi-nn]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-wasi-nn]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wasi-threads]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-wasi-threads]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wast]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-wast]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-winch]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-winch]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wit-bindgen]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-wit-bindgen]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wasmtime-wmemcheck]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wasmtime-wmemcheck]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wiggle]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wiggle]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wiggle-generate]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wiggle-generate]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wiggle-macro]] version = "28.0.0" audited_as = "26.0.1" +[[unpublished.wiggle-macro]] +version = "29.0.0" +audited_as = "27.0.0" + [[unpublished.wiggle-test]] version = "0.0.0" audited_as = "0.1.0" @@ -193,6 +377,10 @@ audited_as = "0.1.0" version = "28.0.0" audited_as = "26.0.1" +[[unpublished.winch-codegen]] +version = "29.0.0" +audited_as = "27.0.0" + [[publisher.aho-corasick]] version = "1.0.2" when = "2023-06-04" @@ -236,8 +424,8 @@ user-login = "epage" user-name = "Ed Page" [[publisher.anyhow]] -version = "1.0.75" -when = "2023-08-17" +version = "1.0.93" +when = "2024-11-06" user-id = 3618 user-login = "dtolnay" user-name = "David Tolnay" @@ -376,104 +564,104 @@ user-login = "jrmuizel" user-name = "Jeff Muizelaar" [[publisher.cranelift]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-bforest]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-bitset]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-codegen]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-codegen-meta]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-codegen-shared]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-control]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-entity]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-frontend]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-interpreter]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-isle]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-jit]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-module]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-native]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-object]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-reader]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.cranelift-serde]] -version = "0.113.1" -when = "2024-11-05" +version = "0.114.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" @@ -660,15 +848,15 @@ user-login = "dtolnay" user-name = "David Tolnay" [[publisher.proc-macro2]] -version = "1.0.81" -when = "2024-04-17" +version = "1.0.92" +when = "2024-11-21" user-id = 3618 user-login = "dtolnay" user-name = "David Tolnay" [[publisher.pulley-interpreter]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" @@ -750,15 +938,15 @@ user-login = "BurntSushi" user-name = "Andrew Gallant" [[publisher.serde]] -version = "1.0.188" -when = "2023-08-26" +version = "1.0.215" +when = "2024-11-11" user-id = 3618 user-login = "dtolnay" user-name = "David Tolnay" [[publisher.serde_derive]] -version = "1.0.188" -when = "2023-08-26" +version = "1.0.215" +when = "2024-11-11" user-id = 3618 user-login = "dtolnay" user-name = "David Tolnay" @@ -791,8 +979,8 @@ user-login = "dtolnay" user-name = "David Tolnay" [[publisher.syn]] -version = "2.0.60" -when = "2024-04-17" +version = "2.0.90" +when = "2024-11-29" user-id = 3618 user-login = "dtolnay" user-name = "David Tolnay" @@ -896,8 +1084,8 @@ user-login = "BurntSushi" user-name = "Andrew Gallant" [[publisher.wasi-common]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" @@ -985,92 +1173,92 @@ user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-asm-macros]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-cache]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-cli]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-cli-flags]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-component-macro]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-component-util]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-cranelift]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-environ]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-explorer]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-fiber]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-jit-debug]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-jit-icache-coherence]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-slab]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-wasi]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" @@ -1081,50 +1269,50 @@ user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-wasi-http]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-wasi-keyvalue]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-wasi-nn]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-wasi-threads]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-wast]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-winch]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-wit-bindgen]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmtime-wmemcheck]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" @@ -1141,20 +1329,20 @@ user-id = 73222 user-login = "wasmtime-publish" [[publisher.wiggle]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wiggle-generate]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wiggle-macro]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" @@ -1173,8 +1361,8 @@ user-login = "BurntSushi" user-name = "Andrew Gallant" [[publisher.winch-codegen]] -version = "26.0.1" -when = "2024-11-05" +version = "27.0.0" +when = "2024-11-20" user-id = 73222 user-login = "wasmtime-publish" diff --git a/tests/all/types.rs b/tests/all/types.rs index 993a5354bc39..d3dc2c4a3626 100644 --- a/tests/all/types.rs +++ b/tests/all/types.rs @@ -7,6 +7,13 @@ fn field(heap_ty: HeapType) -> FieldType { ) } +fn imm_field(heap_ty: HeapType) -> FieldType { + FieldType::new( + Mutability::Const, + StorageType::ValType(RefType::new(true, heap_ty).into()), + ) +} + fn valty(heap_ty: HeapType) -> ValType { ValType::Ref(RefType::new(true, heap_ty)) } @@ -81,25 +88,57 @@ fn basic_struct_types() -> Result<()> { fn struct_type_matches() -> Result<()> { let engine = Engine::default(); - let super_ty = StructType::new(&engine, [field(HeapType::Func)])?; + let super_ty = StructType::with_finality_and_supertype( + &engine, + Finality::NonFinal, + None, + [imm_field(HeapType::Func)], + )?; // Depth. - let sub_ty = StructType::new(&engine, [field(HeapType::NoFunc)])?; + let sub_ty = StructType::with_finality_and_supertype( + &engine, + Finality::Final, + Some(&super_ty), + [imm_field(HeapType::NoFunc)], + )?; assert!(sub_ty.matches(&super_ty)); + let not_sub_ty = StructType::new(&engine, [imm_field(HeapType::NoFunc)])?; + assert!(!not_sub_ty.matches(&super_ty)); // Width. - let sub_ty = StructType::new(&engine, [field(HeapType::Func), field(HeapType::Extern)])?; + let sub_ty = StructType::with_finality_and_supertype( + &engine, + Finality::Final, + Some(&super_ty), + [imm_field(HeapType::Func), imm_field(HeapType::Extern)], + )?; assert!(sub_ty.matches(&super_ty)); + let not_sub_ty = StructType::new( + &engine, + [imm_field(HeapType::Func), imm_field(HeapType::Extern)], + )?; + assert!(!not_sub_ty.matches(&super_ty)); // Depth and width. - let sub_ty = StructType::new(&engine, [field(HeapType::NoFunc), field(HeapType::Extern)])?; + let sub_ty = StructType::with_finality_and_supertype( + &engine, + Finality::Final, + Some(&super_ty), + [imm_field(HeapType::NoFunc), imm_field(HeapType::Extern)], + )?; assert!(sub_ty.matches(&super_ty)); + let not_sub_ty = StructType::new( + &engine, + [imm_field(HeapType::NoFunc), imm_field(HeapType::Extern)], + )?; + assert!(!not_sub_ty.matches(&super_ty)); - // Not depth. + // Unrelated structs. + let not_sub_ty = StructType::new(&engine, [imm_field(HeapType::Extern)])?; + assert!(!not_sub_ty.matches(&super_ty)); let not_sub_ty = StructType::new(&engine, [field(HeapType::Extern)])?; assert!(!not_sub_ty.matches(&super_ty)); - - // Not width. let not_sub_ty = StructType::new(&engine, [])?; assert!(!not_sub_ty.matches(&super_ty)); @@ -109,29 +148,41 @@ fn struct_type_matches() -> Result<()> { #[test] fn struct_subtyping_fields_must_match() -> Result<()> { let engine = Engine::default(); + let a = StructType::with_finality_and_supertype( &engine, Finality::NonFinal, None, - [field(HeapType::Any)], + [imm_field(HeapType::Any)], )?; - for (expected, fields) in [ - // Missing field. - (false, vec![]), - // Non-matching field. - (false, vec![field(HeapType::Extern)]), - // Exact match is okay. - (true, vec![field(HeapType::Any)]), - // Subtype of the field is okay. - (true, vec![field(HeapType::Eq)]), - // Extra fields are okay. - (true, vec![field(HeapType::Any), field(HeapType::Extern)]), + for (msg, expected, fields) in [ + ("Missing field", false, vec![]), + ( + "Non-matching field", + false, + vec![imm_field(HeapType::Extern)], + ), + ("Wrong mutability field", false, vec![field(HeapType::Any)]), + ("Exact match is okay", true, vec![imm_field(HeapType::Any)]), + ( + "Subtype of the field is okay", + true, + vec![imm_field(HeapType::Eq)], + ), + ( + "Extra fields are okay", + true, + vec![imm_field(HeapType::Any), imm_field(HeapType::Extern)], + ), ] { let actual = StructType::with_finality_and_supertype(&engine, Finality::NonFinal, Some(&a), fields) .is_ok(); - assert_eq!(expected, actual); + assert_eq!( + expected, actual, + "expected valid? {expected}; actually valid? {actual}; {msg}" + ); } Ok(()) @@ -263,16 +314,18 @@ fn array_subtyping_field_must_match() -> Result<()> { &engine, Finality::NonFinal, None, - field(HeapType::Any), + imm_field(HeapType::Any), )?; for (expected, field) in [ // Non-matching field. - (false, field(HeapType::Extern)), + (false, imm_field(HeapType::Extern)), + // Wrong mutability field. + (false, field(HeapType::Any)), // Exact match is okay. - (true, field(HeapType::Any)), + (true, imm_field(HeapType::Any)), // Subtype of the field is okay. - (true, field(HeapType::Eq)), + (true, imm_field(HeapType::Eq)), ] { let actual = ArrayType::with_finality_and_supertype(&engine, Finality::NonFinal, Some(&a), field) @@ -322,61 +375,61 @@ fn array_subtyping() -> Result<()> { &engine, Finality::NonFinal, None, - field(HeapType::Any), + imm_field(HeapType::Any), )?; let a = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, Some(&base), - field(HeapType::Any), + imm_field(HeapType::Any), )?; let b = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, Some(&base), - field(HeapType::Eq), + imm_field(HeapType::Eq), )?; let c = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, Some(&a), - field(HeapType::Any), + imm_field(HeapType::Any), )?; let d = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, Some(&a), - field(HeapType::Eq), + imm_field(HeapType::Eq), )?; let e = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, Some(&c), - field(HeapType::Any), + imm_field(HeapType::Any), )?; let f = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, Some(&e), - field(HeapType::Any), + imm_field(HeapType::Any), )?; let g = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, None, - field(HeapType::Eq), + imm_field(HeapType::Eq), )?; let h = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, Some(&g), - field(HeapType::Eq), + imm_field(HeapType::Eq), )?; let i = ArrayType::with_finality_and_supertype( &engine, Finality::NonFinal, Some(&h), - field(HeapType::Eq), + imm_field(HeapType::Eq), )?; for (expected, sub_name, sub, sup_name, sup) in [ diff --git a/tests/disas/pulley/br_table.wat b/tests/disas/pulley/br_table.wat index 63ec9cefde36..ad6c1fc2f7b5 100644 --- a/tests/disas/pulley/br_table.wat +++ b/tests/disas/pulley/br_table.wat @@ -19,30 +19,17 @@ ) ) ;; wasm[0]::function[0]: -;; xconst8 spilltmp0, -16 -;; xadd32 sp, sp, spilltmp0 -;; store64_offset8 sp, 8, lr -;; store64 sp, fp -;; xmov fp, sp +;; push_frame ;; br_table32 x2, 3 -;; 0x1d // target = 0x33 -;; 0x8 // target = 0x22 -;; 0x26 // target = 0x44 -;; 22: xconst8 x0, 1 -;; load64_offset8 lr, sp, 8 -;; load64 fp, sp -;; xconst8 spilltmp0, 16 -;; xadd32 sp, sp, spilltmp0 +;; 0x11 // target = 0x18 +;; 0x8 // target = 0x13 +;; 0xe // target = 0x1d +;; 13: xconst8 x0, 1 +;; pop_frame ;; ret -;; 33: xconst8 x0, 2 -;; 36: load64_offset8 lr, sp, 8 -;; 3a: load64 fp, sp -;; 3d: xconst8 spilltmp0, 16 -;; 40: xadd32 sp, sp, spilltmp0 -;; 43: ret -;; 44: xconst8 x0, 0 -;; 47: load64_offset8 lr, sp, 8 -;; 4b: load64 fp, sp -;; 4e: xconst8 spilltmp0, 16 -;; 51: xadd32 sp, sp, spilltmp0 -;; 54: ret +;; 18: xconst8 x0, 2 +;; 1b: pop_frame +;; 1c: ret +;; 1d: xconst8 x0, 0 +;; 20: pop_frame +;; 21: ret diff --git a/tests/disas/pulley/call.wat b/tests/disas/pulley/call.wat new file mode 100644 index 000000000000..238e2b363d2a --- /dev/null +++ b/tests/disas/pulley/call.wat @@ -0,0 +1,16 @@ +;;! target = "pulley32" +;;! test = "compile" + +(module + (import "" "" (func $x)) + (func (export "") call $x) +) +;; wasm[0]::function[1]: +;; push_frame +;; load32_u_offset8 x3, x0, 44 +;; xmov x6, x0 +;; load32_u_offset8 x0, x6, 52 +;; xmov x1, x6 +;; call_indirect x3 +;; pop_frame +;; ret diff --git a/tests/disas/pulley/i32_add/const.wat b/tests/disas/pulley/i32_add/const.wat index f0e23cd22d0f..75629758d48c 100644 --- a/tests/disas/pulley/i32_add/const.wat +++ b/tests/disas/pulley/i32_add/const.wat @@ -10,14 +10,7 @@ ) ;; wasm[0]::function[0]: -;; xconst8 spilltmp0, -16 -;; xadd32 sp, sp, spilltmp0 -;; store64_offset8 sp, 8, lr -;; store64 sp, fp -;; xmov fp, sp +;; push_frame ;; xconst8 x0, 30 -;; load64_offset8 lr, sp, 8 -;; load64 fp, sp -;; xconst8 spilltmp0, 16 -;; xadd32 sp, sp, spilltmp0 +;; pop_frame ;; ret diff --git a/tests/disas/pulley/loads.wat b/tests/disas/pulley/loads.wat index 76e2063b268b..dbf9a380ab02 100644 --- a/tests/disas/pulley/loads.wat +++ b/tests/disas/pulley/loads.wat @@ -16,37 +16,23 @@ ) ;; wasm[0]::function[0]::i32: -;; xconst8 spilltmp0, -16 -;; xadd32 sp, sp, spilltmp0 -;; store64_offset8 sp, 8, lr -;; store64 sp, fp -;; xmov fp, sp +;; push_frame ;; load32_u_offset8 x6, x0, 52 -;; br_if_xult32 x6, x2, 0x1f // target = 0x33 -;; 1b: load32_u_offset8 x7, x0, 48 +;; br_if_xult32 x6, x2, 0x13 // target = 0x18 +;; c: load32_u_offset8 x7, x0, 48 ;; xadd32 x7, x7, x2 ;; load32_u x0, x7 -;; load64_offset8 lr, sp, 8 -;; load64 fp, sp -;; xconst8 spilltmp0, 16 -;; xadd32 sp, sp, spilltmp0 +;; pop_frame ;; ret -;; 33: trap +;; 18: trap ;; ;; wasm[0]::function[1]::i64: -;; xconst8 spilltmp0, -16 -;; xadd32 sp, sp, spilltmp0 -;; store64_offset8 sp, 8, lr -;; store64 sp, fp -;; xmov fp, sp +;; push_frame ;; load32_u_offset8 x6, x0, 52 -;; br_if_xult32 x6, x2, 0x1f // target = 0x33 -;; 1b: load32_u_offset8 x7, x0, 48 +;; br_if_xult32 x6, x2, 0x13 // target = 0x18 +;; c: load32_u_offset8 x7, x0, 48 ;; xadd32 x7, x7, x2 ;; load64 x0, x7 -;; load64_offset8 lr, sp, 8 -;; load64 fp, sp -;; xconst8 spilltmp0, 16 -;; xadd32 sp, sp, spilltmp0 +;; pop_frame ;; ret -;; 33: trap +;; 18: trap diff --git a/winch/codegen/src/abi/mod.rs b/winch/codegen/src/abi/mod.rs index c2fa325c1f50..c205f7ea54c4 100644 --- a/winch/codegen/src/abi/mod.rs +++ b/winch/codegen/src/abi/mod.rs @@ -212,21 +212,6 @@ impl ABIOperand { _ => unreachable!(), } } - - /// Get the register associated to this [`ABIOperand`]. - pub fn get_reg(&self) -> Option { - match *self { - ABIOperand::Reg { reg, .. } => Some(reg), - _ => None, - } - } - - /// Get the type associated to this [`ABIOperand`]. - pub fn ty(&self) -> WasmValType { - match *self { - ABIOperand::Reg { ty, .. } | ABIOperand::Stack { ty, .. } => ty, - } - } } /// Information about the [`ABIOperand`] information used in [`ABISig`]. diff --git a/winch/codegen/src/codegen/bounds.rs b/winch/codegen/src/codegen/bounds.rs index 1904c8b68128..37ebd1088327 100644 --- a/winch/codegen/src/codegen/bounds.rs +++ b/winch/codegen/src/codegen/bounds.rs @@ -4,7 +4,7 @@ use super::env::HeapData; use crate::{ abi::{scratch, vmctx}, - codegen::CodeGenContext, + codegen::{CodeGenContext, Emission}, isa::reg::{writable, Reg}, masm::{IntCmpKind, MacroAssembler, OperandSize, RegImm, TrapCode}, stack::TypedReg, @@ -82,7 +82,7 @@ impl Index { /// Loads the bounds of the dynamic heap. pub(crate) fn load_dynamic_heap_bounds( - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, heap: &HeapData, ptr_size: OperandSize, @@ -149,7 +149,7 @@ pub(crate) fn ensure_index_and_offset( /// criteria is in bounds. pub(crate) fn load_heap_addr_checked( masm: &mut M, - context: &mut CodeGenContext, + context: &mut CodeGenContext, ptr_size: OperandSize, heap: &HeapData, enable_spectre_mitigation: bool, diff --git a/winch/codegen/src/codegen/call.rs b/winch/codegen/src/codegen/call.rs index ee3b4415cd5c..2cbb06bf96b5 100644 --- a/winch/codegen/src/codegen/call.rs +++ b/winch/codegen/src/codegen/call.rs @@ -58,7 +58,7 @@ use crate::{ abi::{scratch, vmctx, ABIOperand, ABISig, RetArea}, - codegen::{BuiltinFunction, BuiltinType, Callee, CodeGenContext}, + codegen::{BuiltinFunction, BuiltinType, Callee, CodeGenContext, Emission}, masm::{ CalleeKind, ContextArgs, MacroAssembler, MemMoveDirection, OperandSize, SPOffset, VMContextLoc, @@ -85,7 +85,7 @@ impl FnCall { pub fn emit( env: &mut FuncEnv, masm: &mut M, - context: &mut CodeGenContext, + context: &mut CodeGenContext, callee: Callee, ) { let (kind, callee_context) = Self::lower(env, context.vmoffsets, &callee, context, masm); @@ -129,7 +129,7 @@ impl FnCall { env: &mut FuncEnv, vmoffsets: &VMOffsets, callee: &Callee, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, ) -> (CalleeKind, ContextArgs) { let ptr = vmoffsets.ptr.size(); @@ -177,7 +177,7 @@ impl FnCall { fn lower_import( index: FuncIndex, sig: &ABISig, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, vmoffsets: &VMOffsets

, ) -> (CalleeKind, ContextArgs) { @@ -204,7 +204,7 @@ impl FnCall { fn lower_funcref( sig: &ABISig, ptr: impl PtrSize, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, ) -> (CalleeKind, ContextArgs) { // Pop the funcref pointer to a register and allocate a register to hold the @@ -275,7 +275,7 @@ impl FnCall { sig: &ABISig, callee_context: &ContextArgs, ret_area: Option<&RetArea>, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, ) { let arg_count = sig.params.len_without_retptr(); @@ -337,7 +337,7 @@ impl FnCall { reserved_space: u32, ret_area: Option, masm: &mut M, - context: &mut CodeGenContext, + context: &mut CodeGenContext, ) { // Free any registers holding any function references. match callee_kind { diff --git a/winch/codegen/src/codegen/context.rs b/winch/codegen/src/codegen/context.rs index 8cb315e696a6..99b9dc765667 100644 --- a/winch/codegen/src/codegen/context.rs +++ b/winch/codegen/src/codegen/context.rs @@ -3,6 +3,7 @@ use wasmtime_environ::{VMOffsets, WasmHeapType, WasmValType}; use super::ControlStackFrame; use crate::{ abi::{scratch, vmctx, ABIOperand, ABIResults, RetArea}, + codegen::{CodeGenPhase, Emission, Prologue}, frame::Frame, isa::reg::RegClass, masm::{MacroAssembler, OperandSize, RegImm, SPOffset, ShiftKind, StackSlot}, @@ -26,25 +27,78 @@ use crate::{ /// generation process. The code generation context should /// be generally used as the single entry point to access /// the compound functionality provided by its elements. -pub(crate) struct CodeGenContext<'a> { +pub(crate) struct CodeGenContext<'a, P: CodeGenPhase> { /// The register allocator. pub regalloc: RegAlloc, /// The value stack. pub stack: Stack, /// The current function's frame. - pub frame: Frame, + pub frame: Frame

, /// Reachability state. pub reachable: bool, /// A reference to the VMOffsets. pub vmoffsets: &'a VMOffsets, } -impl<'a> CodeGenContext<'a> { +impl<'a> CodeGenContext<'a, Emission> { + /// Prepares arguments for emitting an i32 shift operation. + pub fn i32_shift(&mut self, masm: &mut M, kind: ShiftKind) + where + M: MacroAssembler, + { + let top = self.stack.peek().expect("value at stack top"); + + if top.is_i32_const() { + let val = self + .stack + .pop_i32_const() + .expect("i32 const value at stack top"); + let typed_reg = self.pop_to_reg(masm, None); + masm.shift_ir( + writable!(typed_reg.reg), + val as u64, + typed_reg.reg, + kind, + OperandSize::S32, + ); + self.stack.push(typed_reg.into()); + } else { + masm.shift(self, kind, OperandSize::S32); + } + } + + /// Prepares arguments for emitting an i64 binary operation. + pub fn i64_shift(&mut self, masm: &mut M, kind: ShiftKind) + where + M: MacroAssembler, + { + let top = self.stack.peek().expect("value at stack top"); + if top.is_i64_const() { + let val = self + .stack + .pop_i64_const() + .expect("i64 const value at stack top"); + let typed_reg = self.pop_to_reg(masm, None); + masm.shift_ir( + writable!(typed_reg.reg), + val as u64, + typed_reg.reg, + kind, + OperandSize::S64, + ); + self.stack.push(typed_reg.into()); + } else { + masm.shift(self, kind, OperandSize::S64); + }; + } +} + +impl<'a> CodeGenContext<'a, Prologue> { /// Create a new code generation context. pub fn new( regalloc: RegAlloc, stack: Stack, - frame: Frame, + frame: Frame, vmoffsets: &'a VMOffsets, ) -> Self { Self { @@ -56,6 +110,19 @@ impl<'a> CodeGenContext<'a> { } } + /// Prepares the frame for the [`Emission`] code generation phase. + pub fn for_emission(self) -> CodeGenContext<'a, Emission> { + CodeGenContext { + regalloc: self.regalloc, + stack: self.stack, + reachable: self.reachable, + vmoffsets: self.vmoffsets, + frame: self.frame.for_emission(), + } + } +} + +impl<'a> CodeGenContext<'a, Emission> { /// Request a specific register to the register allocator, /// spilling if not available. pub fn reg(&mut self, named: Reg, masm: &mut M) -> Reg { @@ -325,57 +392,6 @@ impl<'a> CodeGenContext<'a> { }; } - /// Prepares arguments for emitting an i32 shift operation. - pub fn i32_shift(&mut self, masm: &mut M, kind: ShiftKind) - where - M: MacroAssembler, - { - let top = self.stack.peek().expect("value at stack top"); - - if top.is_i32_const() { - let val = self - .stack - .pop_i32_const() - .expect("i32 const value at stack top"); - let typed_reg = self.pop_to_reg(masm, None); - masm.shift_ir( - writable!(typed_reg.reg), - val as u64, - typed_reg.reg, - kind, - OperandSize::S32, - ); - self.stack.push(typed_reg.into()); - } else { - masm.shift(self, kind, OperandSize::S32); - } - } - - /// Prepares arguments for emitting an i64 binary operation. - pub fn i64_shift(&mut self, masm: &mut M, kind: ShiftKind) - where - M: MacroAssembler, - { - let top = self.stack.peek().expect("value at stack top"); - if top.is_i64_const() { - let val = self - .stack - .pop_i64_const() - .expect("i64 const value at stack top"); - let typed_reg = self.pop_to_reg(masm, None); - masm.shift_ir( - writable!(typed_reg.reg), - val as u64, - typed_reg.reg, - kind, - OperandSize::S64, - ); - self.stack.push(typed_reg.into()); - } else { - masm.shift(self, kind, OperandSize::S64); - }; - } - /// Prepares arguments for emitting a convert operation. pub fn convert_op(&mut self, masm: &mut M, dst_ty: WasmValType, mut emit: F) where @@ -511,7 +527,7 @@ impl<'a> CodeGenContext<'a> { mut calculate_ret_area: F, ) where M: MacroAssembler, - F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, + F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, { let area = results .on_stack() @@ -558,7 +574,7 @@ impl<'a> CodeGenContext<'a> { where M: MacroAssembler, { - let addr = masm.local_address(&self.frame.vmctx_slot); + let addr = masm.local_address(&self.frame.vmctx_slot()); masm.load_ptr(addr, writable!(vmctx!(M))); } @@ -570,7 +586,7 @@ impl<'a> CodeGenContext<'a> { fn spill_impl( stack: &mut Stack, regalloc: &mut RegAlloc, - frame: &Frame, + frame: &Frame, masm: &mut M, ) { stack.inner_mut().iter_mut().for_each(|v| match v { diff --git a/winch/codegen/src/codegen/control.rs b/winch/codegen/src/codegen/control.rs index d9fc7fc7ee8e..d9bab98880bd 100644 --- a/winch/codegen/src/codegen/control.rs +++ b/winch/codegen/src/codegen/control.rs @@ -9,6 +9,7 @@ use super::{CodeGenContext, OperandSize, Reg, TypedReg}; use crate::{ abi::{ABIOperand, ABIResults, ABISig, RetArea, ABI}, + codegen::Emission, masm::{IntCmpKind, MacroAssembler, MemMoveDirection, RegImm, SPOffset}, reg::writable, stack::Val, @@ -248,7 +249,7 @@ impl ControlStackFrame { pub fn r#if( sig: BlockSig, masm: &mut M, - context: &mut CodeGenContext, + context: &mut CodeGenContext, ) -> Self { let mut control = Self::If { cont: masm.get_label(), @@ -266,7 +267,7 @@ impl ControlStackFrame { pub fn block( sig: BlockSig, masm: &mut M, - context: &mut CodeGenContext, + context: &mut CodeGenContext, ) -> Self { let mut control = Self::Block { sig, @@ -283,7 +284,7 @@ impl ControlStackFrame { pub fn r#loop( sig: BlockSig, masm: &mut M, - context: &mut CodeGenContext, + context: &mut CodeGenContext, ) -> Self { let mut control = Self::Loop { stack_state: Default::default(), @@ -295,7 +296,7 @@ impl ControlStackFrame { control } - fn init(&mut self, masm: &mut M, context: &mut CodeGenContext) { + fn init(&mut self, masm: &mut M, context: &mut CodeGenContext) { self.calculate_stack_state(context, masm); // If the block has stack results, immediately resolve the return area // base. @@ -336,7 +337,7 @@ impl ControlStackFrame { /// Calculates the [StackState] of the block. fn calculate_stack_state( &mut self, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, ) { use ControlStackFrame::*; @@ -388,7 +389,7 @@ impl ControlStackFrame { pub fn ensure_stack_state( &mut self, masm: &mut M, - context: &mut CodeGenContext, + context: &mut CodeGenContext, ) { let state = self.stack_state(); // This assumes that at jump sites, the machine stack pointer will be @@ -416,7 +417,7 @@ impl ControlStackFrame { } } - fn emit(&mut self, masm: &mut M, context: &mut CodeGenContext) { + fn emit(&mut self, masm: &mut M, context: &mut CodeGenContext) { use ControlStackFrame::*; // Do not perform any emissions if we are in an unreachable state. @@ -455,7 +456,11 @@ impl ControlStackFrame { /// Handles the else branch if the current control stack frame is /// [`ControlStackFrame::If`]. - pub fn emit_else(&mut self, masm: &mut M, context: &mut CodeGenContext) { + pub fn emit_else( + &mut self, + masm: &mut M, + context: &mut CodeGenContext, + ) { debug_assert!(self.is_if()); let state = self.stack_state(); @@ -467,7 +472,11 @@ impl ControlStackFrame { /// Binds the else branch label and converts `self` to /// [`ControlStackFrame::Else`]. - pub fn bind_else(&mut self, masm: &mut M, context: &mut CodeGenContext) { + pub fn bind_else( + &mut self, + masm: &mut M, + context: &mut CodeGenContext, + ) { use ControlStackFrame::*; match self { If { @@ -510,7 +519,11 @@ impl ControlStackFrame { } /// Handles the end of a control stack frame. - pub fn emit_end(&mut self, masm: &mut M, context: &mut CodeGenContext) { + pub fn emit_end( + &mut self, + masm: &mut M, + context: &mut CodeGenContext, + ) { use ControlStackFrame::*; match self { If { stack_state, .. } | Else { stack_state, .. } | Block { stack_state, .. } => { @@ -527,7 +540,11 @@ impl ControlStackFrame { /// Binds the exit label of the current control stack frame and pushes the /// ABI results to the value stack. - pub fn bind_end(&mut self, masm: &mut M, context: &mut CodeGenContext) { + pub fn bind_end( + &mut self, + masm: &mut M, + context: &mut CodeGenContext, + ) { self.push_abi_results(context, masm); self.bind_exit_label(masm); } @@ -627,12 +644,12 @@ impl ControlStackFrame { /// updated. pub fn pop_abi_results( &mut self, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, calculate_ret_area: F, ) where M: MacroAssembler, - F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, + F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, { Self::pop_abi_results_impl(self.results::(), context, masm, calculate_ret_area) } @@ -648,12 +665,12 @@ impl ControlStackFrame { /// results should be interpreted. pub fn pop_abi_results_impl( results: &mut ABIResults, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, mut calculate_ret_area: F, ) where M: MacroAssembler, - F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, + F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, { let mut iter = results.operands().iter().rev().peekable(); @@ -690,7 +707,7 @@ impl ControlStackFrame { /// Convenience wrapper around [CodeGenContext::push_abi_results] using the /// results of the current frame. - fn push_abi_results(&mut self, context: &mut CodeGenContext, masm: &mut M) + fn push_abi_results(&mut self, context: &mut CodeGenContext, masm: &mut M) where M: MacroAssembler, { @@ -705,12 +722,12 @@ impl ControlStackFrame { /// taken. pub fn top_abi_results( &mut self, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, calculate_ret_area: F, ) where M: MacroAssembler, - F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, + F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, { Self::top_abi_results_impl::(self.results::(), context, masm, calculate_ret_area) } @@ -720,12 +737,12 @@ impl ControlStackFrame { /// needed. fn top_abi_results_impl( results: &mut ABIResults, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, mut calculate_ret_area: F, ) where M: MacroAssembler, - F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, + F: FnMut(&ABIResults, &mut CodeGenContext, &mut M) -> Option, { let mut area = None; Self::pop_abi_results_impl::(results, context, masm, |r, context, masm| { @@ -764,7 +781,7 @@ impl ControlStackFrame { fn adjust_stack_results( ret_area: RetArea, results: &ABIResults, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, ) where M: MacroAssembler, @@ -889,7 +906,7 @@ impl ControlStackFrame { /// Ensures that there is enough space for return values on the stack. /// This function is called at the end of all blocks and when branching from /// within blocks. - fn ensure_ret_area(ret_area: &RetArea, context: &mut CodeGenContext, masm: &mut M) + fn ensure_ret_area(ret_area: &RetArea, context: &mut CodeGenContext, masm: &mut M) where M: MacroAssembler, { @@ -907,7 +924,7 @@ impl ControlStackFrame { fn maybe_load_retptr( ret_area: Option<&RetArea>, results: &ABIResults, - context: &mut CodeGenContext, + context: &mut CodeGenContext, masm: &mut M, ) -> Option where diff --git a/winch/codegen/src/codegen/mod.rs b/winch/codegen/src/codegen/mod.rs index 08a306def6c6..63f442c23444 100644 --- a/winch/codegen/src/codegen/mod.rs +++ b/winch/codegen/src/codegen/mod.rs @@ -13,6 +13,7 @@ use cranelift_codegen::{ ir::{RelSourceLoc, SourceLoc}, }; use smallvec::SmallVec; +use std::marker::PhantomData; use wasmparser::{ BinaryReader, FuncValidator, MemArg, Operator, ValidatorResources, VisitOperator, VisitSimdOperator, @@ -37,6 +38,9 @@ pub(crate) mod bounds; use bounds::{Bounds, ImmOffset, Index}; +mod phase; +pub(crate) use phase::*; + /// Holds metadata about the source code location and the machine code emission. /// The fields of this struct are opaque and are not interpreted in any way. /// They serve as a mapping between source code and machine code. @@ -50,15 +54,16 @@ pub(crate) struct SourceLocation { } /// The code generation abstraction. -pub(crate) struct CodeGen<'a, 'translation: 'a, 'data: 'translation, M> +pub(crate) struct CodeGen<'a, 'translation: 'a, 'data: 'translation, M, P> where M: MacroAssembler, + P: CodeGenPhase, { /// The ABI-specific representation of the function signature, excluding results. pub sig: ABISig, /// The code generation context. - pub context: CodeGenContext<'a>, + pub context: CodeGenContext<'a, P>, /// A reference to the function compilation environment. pub env: FuncEnv<'a, 'translation, 'data, M::Ptr>, @@ -83,19 +88,20 @@ where /// Local counter to track fuel consumption. pub fuel_consumed: i64, + phase: PhantomData

, } -impl<'a, 'translation, 'data, M> CodeGen<'a, 'translation, 'data, M> +impl<'a, 'translation, 'data, M> CodeGen<'a, 'translation, 'data, M, Prologue> where M: MacroAssembler, { pub fn new( tunables: &'a Tunables, masm: &'a mut M, - context: CodeGenContext<'a>, + context: CodeGenContext<'a, Prologue>, env: FuncEnv<'a, 'translation, 'data, M::Ptr>, sig: ABISig, - ) -> Self { + ) -> CodeGen<'a, 'translation, 'data, M, Prologue> { Self { sig, context, @@ -107,32 +113,11 @@ where found_unsupported_instruction: None, // Empty functions should consume at least 1 fuel unit. fuel_consumed: 1, + phase: PhantomData, } } - /// Emit the function body to machine code. - pub fn emit( - &mut self, - body: &mut BinaryReader<'a>, - validator: &mut FuncValidator, - ) -> Result<()> { - self.emit_start() - .and_then(|_| self.emit_body(body, validator)) - .and_then(|_| self.emit_end())?; - - Ok(()) - } - - /// Derives a [RelSourceLoc] from a [SourceLoc]. - pub fn source_loc_from(&mut self, loc: SourceLoc) -> RelSourceLoc { - if self.source_location.base.is_none() && !loc.is_default() { - self.source_location.base = Some(loc); - } - - RelSourceLoc::from_base_offset(self.source_location.base.unwrap_or_default(), loc) - } - - fn emit_start(&mut self) -> Result<()> { + pub fn emit_prologue(mut self) -> Result> { let vmctx = self .sig .params() @@ -153,32 +138,95 @@ where ); self.masm.reserve_stack(self.context.frame.locals_size); + self.spill_register_arguments(); + + let defined_locals_range = &self.context.frame.defined_locals_range; + self.masm.zero_mem_range(defined_locals_range.as_range()); + + // Save the results base parameter register into its slot. + self.sig.params.has_retptr().then(|| { + match self.sig.params.unwrap_results_area_operand() { + ABIOperand::Reg { ty, reg, .. } => { + let results_base_slot = self.context.frame.results_base_slot.as_ref().unwrap(); + debug_assert!(results_base_slot.addressed_from_sp()); + let addr = self.masm.local_address(results_base_slot); + self.masm.store((*reg).into(), addr, (*ty).into()); + } + // The result base parameter is a stack parameter, addressed + // from FP. + _ => {} + } + }); self.masm.end_source_loc(); - if self.tunables.consume_fuel { - self.emit_fuel_check(); + Ok(CodeGen { + sig: self.sig, + context: self.context.for_emission(), + masm: self.masm, + env: self.env, + tunables: self.tunables, + source_location: self.source_location, + control_frames: self.control_frames, + found_unsupported_instruction: self.found_unsupported_instruction, + fuel_consumed: self.fuel_consumed, + phase: PhantomData, + }) + } + + fn spill_register_arguments(&mut self) { + use WasmValType::*; + for (operand, slot) in self + .sig + .params_without_retptr() + .iter() + .zip(self.context.frame.locals()) + { + match (operand, slot) { + (ABIOperand::Reg { ty, reg, .. }, slot) => { + let addr = self.masm.local_address(slot); + match &ty { + I32 | I64 | F32 | F64 | V128 => { + self.masm.store((*reg).into(), addr, (*ty).into()) + } + Ref(rt) => match rt.heap_type { + WasmHeapType::Func | WasmHeapType::Extern => { + self.masm.store_ptr((*reg).into(), addr) + } + ht => unimplemented!("Support for WasmHeapType: {ht}"), + }, + } + } + // Skip non-register arguments + _ => {} + } } + } +} - // Once we have emitted the epilogue and reserved stack space for the locals, we push the - // base control flow block. - self.control_frames.push(ControlStackFrame::block( - BlockSig::from_sig(self.sig.clone()), - self.masm, - &mut self.context, - )); +impl<'a, 'translation, 'data, M> CodeGen<'a, 'translation, 'data, M, Emission> +where + M: MacroAssembler, +{ + /// Emit the function body to machine code. + pub fn emit( + &mut self, + body: &mut BinaryReader<'a>, + validator: &mut FuncValidator, + ) -> Result<()> { + self.emit_body(body, validator) + .and_then(|_| self.emit_end())?; - // Set the return area of the results *after* initializing the block. In - // the function body block case, we'll treat the results as any other - // case, addressed from the stack pointer, and when ending the function - // the return area will be set to the return pointer. - if self.sig.params.has_retptr() { - self.sig - .results - .set_ret_area(RetArea::slot(self.context.frame.results_base_slot.unwrap())); + Ok(()) + } + + /// Derives a [RelSourceLoc] from a [SourceLoc]. + pub fn source_loc_from(&mut self, loc: SourceLoc) -> RelSourceLoc { + if self.source_location.base.is_none() && !loc.is_default() { + self.source_location.base = Some(loc); } - Ok(()) + RelSourceLoc::from_base_offset(self.source_location.base.unwrap_or_default(), loc) } /// The following two helpers, handle else or end instructions when the @@ -224,24 +272,27 @@ where body: &mut BinaryReader<'a>, validator: &mut FuncValidator, ) -> Result<()> { - self.spill_register_arguments(); - let defined_locals_range = &self.context.frame.defined_locals_range; - self.masm.zero_mem_range(defined_locals_range.as_range()); + if self.tunables.consume_fuel { + self.emit_fuel_check(); + } - // Save the results base parameter register into its slot. - self.sig.params.has_retptr().then(|| { - match self.sig.params.unwrap_results_area_operand() { - ABIOperand::Reg { ty, reg, .. } => { - let results_base_slot = self.context.frame.results_base_slot.as_ref().unwrap(); - debug_assert!(results_base_slot.addressed_from_sp()); - let addr = self.masm.local_address(results_base_slot); - self.masm.store((*reg).into(), addr, (*ty).into()); - } - // The result base parameter is a stack parameter, addressed - // from FP. - _ => {} - } - }); + // Once we have emitted the epilogue and reserved stack space for the locals, we push the + // base control flow block. + self.control_frames.push(ControlStackFrame::block( + BlockSig::from_sig(self.sig.clone()), + self.masm, + &mut self.context, + )); + + // Set the return area of the results *after* initializing the block. In + // the function body block case, we'll treat the results as any other + // case, addressed from the stack pointer, and when ending the function + // the return area will be set to the return pointer. + if self.sig.params.has_retptr() { + self.sig + .results + .set_ret_area(RetArea::slot(self.context.frame.results_base_slot.unwrap())); + } while !body.eof() { let offset = body.original_position(); @@ -307,7 +358,7 @@ where } impl<'a, 'translation, 'data, M: MacroAssembler> VisitorHooks - for CodeGen<'a, 'translation, 'data, M> + for CodeGen<'a, 'translation, 'data, M, Emission> { fn visit(&self, op: &Operator) -> bool { self.context.reachable || visit_op_when_unreachable(op) @@ -431,35 +482,6 @@ where Ok(()) } - fn spill_register_arguments(&mut self) { - use WasmValType::*; - self.sig - // Skip the results base param if any; [Self::emit_body], - // will handle spilling the results base param if it's in a register. - .params_without_retptr() - .iter() - .enumerate() - .filter(|(_, a)| a.is_reg()) - .for_each(|(index, arg)| { - let ty = arg.ty(); - let local = self.context.frame.get_frame_local(index); - let addr = self.masm.local_address(local); - let src = arg - .get_reg() - .expect("arg should be associated to a register"); - - match &ty { - I32 | I64 | F32 | F64 | V128 => self.masm.store(src.into(), addr, ty.into()), - Ref(rt) => match rt.heap_type { - WasmHeapType::Func | WasmHeapType::Extern => { - self.masm.store_ptr(src.into(), addr) - } - ht => unimplemented!("Support for WasmHeapType: {ht}"), - }, - } - }); - } - /// Pops the value at the stack top and assigns it to the local at /// the given index, returning the typed register holding the /// source value. @@ -633,8 +655,12 @@ where // * index + offset + access_size overflows // OR // * index + offset + access_size > bound - let bounds = - bounds::load_dynamic_heap_bounds(&mut self.context, self.masm, &heap, ptr_size); + let bounds = bounds::load_dynamic_heap_bounds::<_>( + &mut self.context, + self.masm, + &heap, + ptr_size, + ); let index_reg = index.as_typed_reg().reg; // Allocate a temporary register to hold @@ -944,7 +970,14 @@ where /// performing a zero-comparison with the number of units stored in /// `VMRuntimeLimits`. pub fn emit_fuel_check(&mut self) { - let fuel_var = self.emit_load_fuel_consumed(); + let out_of_fuel = self.env.builtins.out_of_gas::(); + let fuel_var = + self.context + .without::(&out_of_fuel.sig().regs, self.masm, |cx, masm| { + cx.any_gpr(masm) + }); + + self.emit_load_fuel_consumed(fuel_var); let continuation = self.masm.get_label(); // Spill locals and registers to avoid conflicts at the out-of-fuel @@ -960,7 +993,6 @@ where OperandSize::S64, ); // Out-of-fuel branch. - let out_of_fuel = self.env.builtins.out_of_gas::(); FnCall::emit::( &mut self.env, self.masm, @@ -972,6 +1004,24 @@ where self.context.free_reg(fuel_var); } + /// Emits a series of instructions that load the `fuel_consumed` field from + /// `VMRuntimeLimits`. + fn emit_load_fuel_consumed(&mut self, fuel_var: Reg) { + let limits_offset = self.env.vmoffsets.ptr.vmctx_runtime_limits(); + let fuel_offset = self.env.vmoffsets.ptr.vmruntime_limits_fuel_consumed(); + self.masm.load_ptr( + self.masm.address_at_vmctx(u32::from(limits_offset)), + writable!(fuel_var), + ); + + self.masm.load( + self.masm.address_at_reg(fuel_var, u32::from(fuel_offset)), + writable!(fuel_var), + // Fuel is an i64. + OperandSize::S64, + ); + } + /// Increments the fuel consumed in `VMRuntimeLimits` by flushing /// `self.fuel_consumed` to memory. fn emit_fuel_increment(&mut self) { @@ -1016,27 +1066,6 @@ where self.context.free_reg(limits_var); } - /// Emits a series of instructions that load the `fuel_consumed` field from - /// `VMRuntimeLimits`. - fn emit_load_fuel_consumed(&mut self) -> Reg { - let limits_offset = self.env.vmoffsets.ptr.vmctx_runtime_limits(); - let fuel_offset = self.env.vmoffsets.ptr.vmruntime_limits_fuel_consumed(); - let fuel_var = self.context.any_gpr(self.masm); - self.masm.load_ptr( - self.masm.address_at_vmctx(u32::from(limits_offset)), - writable!(fuel_var), - ); - - self.masm.load( - self.masm.address_at_reg(fuel_var, u32::from(fuel_offset)), - writable!(fuel_var), - // Fuel is an i64. - OperandSize::S64, - ); - - fuel_var - } - /// Hook to handle fuel before visiting an operator. fn fuel_before_visit_op(&mut self, op: &Operator) { if !self.context.reachable { diff --git a/winch/codegen/src/codegen/phase.rs b/winch/codegen/src/codegen/phase.rs new file mode 100644 index 000000000000..de2d2e0206fa --- /dev/null +++ b/winch/codegen/src/codegen/phase.rs @@ -0,0 +1,24 @@ +//! Type-based states to represent code generation phases. +//! These states help enforce code generation invariants at compile time. +//! +//! Currently two phases are defined for code generation: +//! +//! * Prologue: responsible of setting up the function's frame. +//! * Emission: emission of Wasm code to machine code. + +/// A code generation phase. +pub trait CodeGenPhase {} + +/// The prologue phase. +/// +/// Its main responsibility is to setup the function's frame, by creating the +/// well known local slots. In this phase, writes to such slots is allowed. +/// After this phase, the frame is considered immutable. +pub struct Prologue; +/// The code emission phase. +/// +/// Its main responsibility is to emit Wasm code to machine code. +pub struct Emission; + +impl CodeGenPhase for Prologue {} +impl CodeGenPhase for Emission {} diff --git a/winch/codegen/src/frame/mod.rs b/winch/codegen/src/frame/mod.rs index 1ebdace8daf3..c813141d7184 100644 --- a/winch/codegen/src/frame/mod.rs +++ b/winch/codegen/src/frame/mod.rs @@ -1,18 +1,27 @@ use crate::{ abi::{align_to, ABIOperand, ABISig, LocalSlot, ABI}, + codegen::{CodeGenPhase, Emission, Prologue}, masm::MacroAssembler, }; use anyhow::Result; use smallvec::SmallVec; +use std::marker::PhantomData; use std::ops::Range; use wasmparser::{BinaryReader, FuncValidator, ValidatorResources}; use wasmtime_environ::{TypeConvert, WasmValType}; +/// WebAssembly locals. // TODO: // SpiderMonkey's implementation uses 16; // (ref: https://searchfox.org/mozilla-central/source/js/src/wasm/WasmBCFrame.h#585) // during instrumentation we should measure to verify if this is a good default. -pub(crate) type Locals = SmallVec<[LocalSlot; 16]>; +pub(crate) type WasmLocals = SmallVec<[LocalSlot; 16]>; +/// Special local slots used by the compiler. +// Winch's ABI uses two extra parameters to store the callee and caller +// VMContext pointers. +// These arguments are spilled and treated as frame locals, but not +// WebAssembly locals. +pub(crate) type SpecialLocals = [LocalSlot; 2]; /// Function defined locals start and end in the frame. pub(crate) struct DefinedLocalsRange(Range); @@ -28,7 +37,7 @@ impl DefinedLocalsRange { #[derive(Default)] pub(crate) struct DefinedLocals { /// The defined locals for a function. - pub defined_locals: Locals, + pub defined_locals: WasmLocals, /// The size of the defined locals. pub stack_size: u32, } @@ -43,7 +52,7 @@ impl DefinedLocals { let mut next_stack: u32 = 0; // The first 32 bits of a Wasm binary function describe the number of locals. let local_count = reader.read_var_u32()?; - let mut slots: Locals = Default::default(); + let mut slots: WasmLocals = Default::default(); for _ in 0..local_count { let position = reader.original_position(); @@ -67,7 +76,7 @@ impl DefinedLocals { } /// Frame handler abstraction. -pub(crate) struct Frame { +pub(crate) struct Frame { /// The size of the entire local area; the arguments plus the function defined locals. pub locals_size: u32, @@ -78,23 +87,24 @@ pub(crate) struct Frame { /// /// Locals get calculated when allocating a frame and are readonly /// through the function compilation lifetime. - locals: Locals, - - /// The offset to the slot containing the `VMContext`. - pub vmctx_slot: LocalSlot, + wasm_locals: WasmLocals, + /// Special locals used by the internal ABI. See [`SpecialLocals`]. + special_locals: SpecialLocals, /// The slot holding the address of the results area. pub results_base_slot: Option, + marker: PhantomData

, } -impl Frame { +impl Frame { /// Allocate a new [`Frame`]. - pub fn new(sig: &ABISig, defined_locals: &DefinedLocals) -> Result { - let (mut locals, defined_locals_start) = Self::compute_arg_slots::(sig)?; + pub fn new(sig: &ABISig, defined_locals: &DefinedLocals) -> Result> { + let (special_locals, mut wasm_locals, defined_locals_start) = + Self::compute_arg_slots::(sig)?; // The defined locals have a zero-based offset by default // so we need to add the defined locals start to the offset. - locals.extend( + wasm_locals.extend( defined_locals .defined_locals .iter() @@ -138,66 +148,37 @@ impl Frame { (None, defined_locals_end) }; - let vmctx_slot = *locals.get(0).expect("LocalSlot for VMContext"); Ok(Self { - locals, + wasm_locals, + special_locals, locals_size, - vmctx_slot, defined_locals_range: DefinedLocalsRange( defined_locals_start..(defined_locals_start + defined_locals.stack_size), ), results_base_slot, + marker: PhantomData, }) } - // Winch's ABI uses two extra parameters to store the callee and caller - // VMContext pointers. - // These arguments are spilled and treated as frame locals, but not - // WebAssembly locals. - const WASM_LOCALS_OFFSET: usize = 2; - - /// Get the [LocalSlot] for a WebAssembly local. - /// This method assumes that the index is bound to u32::MAX, representing - /// the index space for WebAssembly locals. - /// - /// # Panics - /// This method panics if the index is not associated to a valid WebAssembly - /// local. - pub fn get_wasm_local(&self, index: u32) -> &LocalSlot { - let local_index = Self::WASM_LOCALS_OFFSET + index as usize; - self.locals - .get(local_index) - .unwrap_or_else(|| panic!(" Expected WebAssembly local at slot: {index}")) - } - - /// Get the [LocalSlot] for a frame local. - /// This method doesn't make any asumptions about the local index passed in, - /// and simply delegates the [LocalSlot] retrieval to the underlying locals - /// vector. - /// - /// # Panics - /// This method panics if the index is not associated to a valid WebAssembly - /// local. - pub fn get_frame_local(&self, index: usize) -> &LocalSlot { - self.locals - .get(index) - .unwrap_or_else(|| panic!(" Expected Frame local at slot: {index}")) + /// Returns an iterator over all the [`LocalSlot`]s in the frame, including + /// the [`SpecialLocals`]. + pub fn locals(&self) -> impl Iterator { + self.special_locals.iter().chain(self.wasm_locals.iter()) } - /// Returns the address of the local at the given index. - /// - /// # Panics - /// This function panics if the index is not associated to a local. - pub fn get_local_address( - &self, - index: u32, - masm: &mut M, - ) -> (WasmValType, M::Address) { - let slot = self.get_wasm_local(index); - (slot.ty, masm.local_address(&slot)) + /// Prepares the frame for the [`Emission`] code generation phase. + pub fn for_emission(self) -> Frame { + Frame { + wasm_locals: self.wasm_locals, + special_locals: self.special_locals, + locals_size: self.locals_size, + defined_locals_range: self.defined_locals_range, + results_base_slot: self.results_base_slot, + marker: PhantomData, + } } - fn compute_arg_slots(sig: &ABISig) -> Result<(Locals, u32)> { + fn compute_arg_slots(sig: &ABISig) -> Result<(SpecialLocals, WasmLocals, u32)> { // Go over the function ABI-signature and // calculate the stack slots. // @@ -231,13 +212,24 @@ impl Frame { // Skip the results base param; if present, the [Frame] will create // a dedicated slot for it. - let slots: Locals = sig - .params_without_retptr() - .into_iter() + let mut params_iter = sig.params_without_retptr().into_iter(); + + // Handle special local slots. + let callee_vmctx = params_iter + .next() + .map(|arg| Self::abi_arg_slot(&arg, &mut next_stack, arg_base_offset)) + .expect("Slot for VMContext"); + + let caller_vmctx = params_iter + .next() + .map(|arg| Self::abi_arg_slot(&arg, &mut next_stack, arg_base_offset)) + .expect("Slot for VMContext"); + + let slots: WasmLocals = params_iter .map(|arg| Self::abi_arg_slot(&arg, &mut next_stack, arg_base_offset)) .collect(); - Ok((slots, next_stack)) + Ok(([callee_vmctx, caller_vmctx], slots, next_stack)) } fn abi_arg_slot(arg: &ABIOperand, next_stack: &mut u32, arg_base_offset: u32) -> LocalSlot { @@ -256,3 +248,47 @@ impl Frame { } } } + +impl Frame { + /// Get the [`LocalSlot`] for a WebAssembly local. + /// This method assumes that the index is bound to u32::MAX, representing + /// the index space for WebAssembly locals. + /// + /// # Panics + /// This method panics if the index is not associated to a valid WebAssembly + /// local. + pub fn get_wasm_local(&self, index: u32) -> &LocalSlot { + self.wasm_locals + .get(index as usize) + .unwrap_or_else(|| panic!(" Expected WebAssembly local at slot: {index}")) + } + + /// Get the [`LocalSlot`] for a special local. + /// + /// # Panics + /// This method panics if the index is not associated to a valid special + /// local. + pub fn get_special_local(&self, index: usize) -> &LocalSlot { + self.special_locals + .get(index) + .unwrap_or_else(|| panic!(" Expected special local at slot: {index}")) + } + + /// Get the special [`LocalSlot`] for the `VMContext`. + pub fn vmctx_slot(&self) -> &LocalSlot { + self.get_special_local(0) + } + + /// Returns the address of the local at the given index. + /// + /// # Panics + /// This function panics if the index is not associated to a local. + pub fn get_local_address( + &self, + index: u32, + masm: &mut M, + ) -> (WasmValType, M::Address) { + let slot = self.get_wasm_local(index); + (slot.ty, masm.local_address(&slot)) + } +} diff --git a/winch/codegen/src/isa/aarch64/masm.rs b/winch/codegen/src/isa/aarch64/masm.rs index 02226387baa3..9be8a60f772a 100644 --- a/winch/codegen/src/isa/aarch64/masm.rs +++ b/winch/codegen/src/isa/aarch64/masm.rs @@ -1,7 +1,7 @@ use super::{abi::Aarch64ABI, address::Address, asm::Assembler, regs}; use crate::{ abi::local::LocalSlot, - codegen::{ptr_type_from_ptr_size, CodeGenContext, FuncEnv}, + codegen::{ptr_type_from_ptr_size, CodeGenContext, Emission, FuncEnv}, isa::reg::{writable, Reg, WritableReg}, masm::{ CalleeKind, DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind, @@ -350,11 +350,11 @@ impl Masm for MacroAssembler { self.asm.fabs_rr(dst.to_reg(), dst, size); } - fn float_round, &mut CodeGenContext, &mut Self)>( + fn float_round, &mut CodeGenContext, &mut Self)>( &mut self, mode: RoundingMode, _env: &mut FuncEnv, - context: &mut CodeGenContext, + context: &mut CodeGenContext, size: OperandSize, _fallback: F, ) { @@ -433,7 +433,12 @@ impl Masm for MacroAssembler { self.asm.shift_ir(imm, lhs, dst, kind, size) } - fn shift(&mut self, context: &mut CodeGenContext, kind: ShiftKind, size: OperandSize) { + fn shift( + &mut self, + context: &mut CodeGenContext, + kind: ShiftKind, + size: OperandSize, + ) { let src = context.pop_to_reg(self, None); let dst = context.pop_to_reg(self, None); @@ -444,11 +449,11 @@ impl Masm for MacroAssembler { context.stack.push(dst.into()); } - fn div(&mut self, _context: &mut CodeGenContext, _kind: DivKind, _size: OperandSize) { + fn div(&mut self, _context: &mut CodeGenContext, _kind: DivKind, _size: OperandSize) { todo!() } - fn rem(&mut self, _context: &mut CodeGenContext, _kind: RemKind, _size: OperandSize) { + fn rem(&mut self, _context: &mut CodeGenContext, _kind: RemKind, _size: OperandSize) { todo!() } @@ -456,7 +461,7 @@ impl Masm for MacroAssembler { self.asm.load_constant(0, reg); } - fn popcnt(&mut self, context: &mut CodeGenContext, size: OperandSize) { + fn popcnt(&mut self, context: &mut CodeGenContext, size: OperandSize) { let src = context.pop_to_reg(self, None); let tmp = regs::float_scratch(); self.asm.mov_to_fpu(src.into(), writable!(tmp), size); @@ -700,7 +705,7 @@ impl Masm for MacroAssembler { todo!() } - fn mul_wide(&mut self, context: &mut CodeGenContext, kind: MulWideKind) { + fn mul_wide(&mut self, context: &mut CodeGenContext, kind: MulWideKind) { let _ = (context, kind); todo!() } diff --git a/winch/codegen/src/isa/aarch64/mod.rs b/winch/codegen/src/isa/aarch64/mod.rs index 17c49577a6fb..e54ffa0c9d4e 100644 --- a/winch/codegen/src/isa/aarch64/mod.rs +++ b/winch/codegen/src/isa/aarch64/mod.rs @@ -123,11 +123,12 @@ impl TargetIsa for Aarch64 { ); let regalloc = RegAlloc::from(gpr, fpr); let codegen_context = CodeGenContext::new(regalloc, stack, frame, &vmoffsets); - let mut codegen = CodeGen::new(tunables, &mut masm, codegen_context, env, abi_sig); + let codegen = CodeGen::new(tunables, &mut masm, codegen_context, env, abi_sig); - codegen.emit(&mut body, validator)?; - let names = codegen.env.take_name_map(); - let base = codegen.source_location.base; + let mut body_codegen = codegen.emit_prologue()?; + body_codegen.emit(&mut body, validator)?; + let names = body_codegen.env.take_name_map(); + let base = body_codegen.source_location.base; Ok(CompiledFunction::new( masm.finalize(base), names, diff --git a/winch/codegen/src/isa/x64/masm.rs b/winch/codegen/src/isa/x64/masm.rs index 4d72b79e6965..9937d165e9b9 100644 --- a/winch/codegen/src/isa/x64/masm.rs +++ b/winch/codegen/src/isa/x64/masm.rs @@ -12,7 +12,7 @@ use crate::masm::{ }; use crate::{ abi::{self, align_to, calculate_frame_adjustment, LocalSlot}, - codegen::{ptr_type_from_ptr_size, CodeGenContext, FuncEnv}, + codegen::{ptr_type_from_ptr_size, CodeGenContext, Emission, FuncEnv}, stack::{TypedReg, Val}, }; use crate::{ @@ -474,11 +474,11 @@ impl Masm for MacroAssembler { self.asm.xmm_and_rr(scratch_xmm, dst, size); } - fn float_round, &mut CodeGenContext, &mut Self)>( + fn float_round, &mut CodeGenContext, &mut Self)>( &mut self, mode: RoundingMode, env: &mut FuncEnv, - context: &mut CodeGenContext, + context: &mut CodeGenContext, size: OperandSize, mut fallback: F, ) { @@ -565,7 +565,12 @@ impl Masm for MacroAssembler { self.asm.shift_ir(imm as u8, dst, kind, size) } - fn shift(&mut self, context: &mut CodeGenContext, kind: ShiftKind, size: OperandSize) { + fn shift( + &mut self, + context: &mut CodeGenContext, + kind: ShiftKind, + size: OperandSize, + ) { // Number of bits to shift must be in the CL register. let src = context.pop_to_reg(self, Some(regs::rcx())); let dst = context.pop_to_reg(self, None); @@ -577,7 +582,7 @@ impl Masm for MacroAssembler { context.stack.push(dst.into()); } - fn div(&mut self, context: &mut CodeGenContext, kind: DivKind, size: OperandSize) { + fn div(&mut self, context: &mut CodeGenContext, kind: DivKind, size: OperandSize) { // Allocate rdx:rax. let rdx = context.reg(regs::rdx(), self); let rax = context.reg(regs::rax(), self); @@ -599,7 +604,7 @@ impl Masm for MacroAssembler { context.stack.push(rax.into()); } - fn rem(&mut self, context: &mut CodeGenContext, kind: RemKind, size: OperandSize) { + fn rem(&mut self, context: &mut CodeGenContext, kind: RemKind, size: OperandSize) { // Allocate rdx:rax. let rdx = context.reg(regs::rdx(), self); let rax = context.reg(regs::rax(), self); @@ -787,7 +792,7 @@ impl Masm for MacroAssembler { self.asm.jmp(target); } - fn popcnt(&mut self, context: &mut CodeGenContext, size: OperandSize) { + fn popcnt(&mut self, context: &mut CodeGenContext, size: OperandSize) { let src = context.pop_to_reg(self, None); if self.flags.has_popcnt() && self.flags.has_sse42() { self.asm.popcnt(src.into(), size); @@ -1028,7 +1033,7 @@ impl Masm for MacroAssembler { self.asm.sbb_rr(rhs_hi, dst_hi, OperandSize::S64); } - fn mul_wide(&mut self, context: &mut CodeGenContext, kind: MulWideKind) { + fn mul_wide(&mut self, context: &mut CodeGenContext, kind: MulWideKind) { // Reserve rax/rdx since they're required by the `mul_wide` instruction // being used here. let rax = context.reg(regs::rax(), self); diff --git a/winch/codegen/src/isa/x64/mod.rs b/winch/codegen/src/isa/x64/mod.rs index ae038f6d7776..de0029d08d00 100644 --- a/winch/codegen/src/isa/x64/mod.rs +++ b/winch/codegen/src/isa/x64/mod.rs @@ -134,12 +134,14 @@ impl TargetIsa for X64 { let regalloc = RegAlloc::from(gpr, fpr); let codegen_context = CodeGenContext::new(regalloc, stack, frame, &vmoffsets); - let mut codegen = CodeGen::new(tunables, &mut masm, codegen_context, env, abi_sig); + let codegen = CodeGen::new(tunables, &mut masm, codegen_context, env, abi_sig); - codegen.emit(&mut body, validator)?; - let base = codegen.source_location.base; + let mut body_codegen = codegen.emit_prologue()?; - let names = codegen.env.take_name_map(); + body_codegen.emit(&mut body, validator)?; + let base = body_codegen.source_location.base; + + let names = body_codegen.env.take_name_map(); Ok(CompiledFunction::new( masm.finalize(base), names, diff --git a/winch/codegen/src/masm.rs b/winch/codegen/src/masm.rs index 95de6e789225..1bd5a7a59b4e 100644 --- a/winch/codegen/src/masm.rs +++ b/winch/codegen/src/masm.rs @@ -1,5 +1,5 @@ use crate::abi::{self, align_to, scratch, LocalSlot}; -use crate::codegen::{CodeGenContext, FuncEnv}; +use crate::codegen::{CodeGenContext, Emission, FuncEnv}; use crate::isa::reg::{writable, Reg, WritableReg}; use cranelift_codegen::{ binemit::CodeOffset, @@ -744,11 +744,11 @@ pub(crate) trait MacroAssembler { fn float_neg(&mut self, dst: WritableReg, size: OperandSize); /// Perform a floating point floor operation. - fn float_round, &mut CodeGenContext, &mut Self)>( + fn float_round, &mut CodeGenContext, &mut Self)>( &mut self, mode: RoundingMode, env: &mut FuncEnv, - context: &mut CodeGenContext, + context: &mut CodeGenContext, size: OperandSize, fallback: F, ); @@ -781,7 +781,7 @@ pub(crate) trait MacroAssembler { /// caller from having to deal with the architecture specific constraints /// we give this function access to the code generation context, allowing /// each implementation to decide the lowering path. - fn shift(&mut self, context: &mut CodeGenContext, kind: ShiftKind, size: OperandSize); + fn shift(&mut self, context: &mut CodeGenContext, kind: ShiftKind, size: OperandSize); /// Perform division operation. /// Division is special in that some architectures have specific @@ -794,10 +794,10 @@ pub(crate) trait MacroAssembler { /// unconstrained binary operation, the caller can decide to use /// the `CodeGenContext::i32_binop` or `CodeGenContext::i64_binop` /// functions. - fn div(&mut self, context: &mut CodeGenContext, kind: DivKind, size: OperandSize); + fn div(&mut self, context: &mut CodeGenContext, kind: DivKind, size: OperandSize); /// Calculate remainder. - fn rem(&mut self, context: &mut CodeGenContext, kind: RemKind, size: OperandSize); + fn rem(&mut self, context: &mut CodeGenContext, kind: RemKind, size: OperandSize); /// Compares `src1` against `src2` for the side effect of setting processor /// flags. @@ -852,7 +852,7 @@ pub(crate) trait MacroAssembler { /// Count the number of 1 bits in src and put the result in dst. In x64, /// this will emit multiple instructions if the `has_popcnt` flag is false. - fn popcnt(&mut self, context: &mut CodeGenContext, size: OperandSize); + fn popcnt(&mut self, context: &mut CodeGenContext, size: OperandSize); /// Converts an i64 to an i32 by discarding the high 32 bits. fn wrap(&mut self, dst: WritableReg, src: Reg); @@ -1053,5 +1053,5 @@ pub(crate) trait MacroAssembler { /// /// Note that some platforms require special handling of registers in this /// instruction (e.g. x64) so full access to `CodeGenContext` is provided. - fn mul_wide(&mut self, context: &mut CodeGenContext, kind: MulWideKind); + fn mul_wide(&mut self, context: &mut CodeGenContext, kind: MulWideKind); } diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs index c38cd41ac1ed..1fae5644330e 100644 --- a/winch/codegen/src/visitor.rs +++ b/winch/codegen/src/visitor.rs @@ -5,7 +5,7 @@ //! machine code emitter. use crate::abi::RetArea; -use crate::codegen::{control_index, Callee, CodeGen, ControlStackFrame, FnCall}; +use crate::codegen::{control_index, Callee, CodeGen, ControlStackFrame, Emission, FnCall}; use crate::masm::{ DivKind, ExtendKind, FloatCmpKind, IntCmpKind, MacroAssembler, MemMoveDirection, MulWideKind, OperandSize, RegImm, RemKind, RoundingMode, SPOffset, ShiftKind, TruncKind, @@ -253,7 +253,7 @@ macro_rules! def_unsupported { (emit $unsupported:tt $($rest:tt)*) => {$($rest)*}; } -impl<'a, 'translation, 'data, M> VisitOperator<'a> for CodeGen<'a, 'translation, 'data, M> +impl<'a, 'translation, 'data, M> VisitOperator<'a> for CodeGen<'a, 'translation, 'data, M, Emission> where M: MacroAssembler, { @@ -2212,7 +2212,8 @@ where wasmparser::for_each_visit_operator!(def_unsupported); } -impl<'a, 'translation, 'data, M> VisitSimdOperator<'a> for CodeGen<'a, 'translation, 'data, M> +impl<'a, 'translation, 'data, M> VisitSimdOperator<'a> + for CodeGen<'a, 'translation, 'data, M, Emission> where M: MacroAssembler, { @@ -2231,7 +2232,7 @@ where wasmparser::for_each_visit_simd_operator!(def_unsupported); } -impl<'a, 'translation, 'data, M> CodeGen<'a, 'translation, 'data, M> +impl<'a, 'translation, 'data, M> CodeGen<'a, 'translation, 'data, M, Emission> where M: MacroAssembler, {